Package org.springframework.batch.core.step.item

Source Code of org.springframework.batch.core.step.item.FaultTolerantStepFactoryBeanRetryTests

/*
* Copyright 2006-2013 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 static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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.BatchStatus;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
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.repository.dao.MapExecutionContextDao;
import org.springframework.batch.core.repository.dao.MapJobExecutionDao;
import org.springframework.batch.core.repository.dao.MapJobInstanceDao;
import org.springframework.batch.core.repository.dao.MapStepExecutionDao;
import org.springframework.batch.core.repository.support.SimpleJobRepository;
import org.springframework.batch.core.step.AbstractStep;
import org.springframework.batch.core.step.factory.FaultTolerantStepFactoryBean;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemStream;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader;
import org.springframework.batch.item.support.ListItemReader;
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
import org.springframework.batch.support.transaction.TransactionAwareProxyFactory;
import org.springframework.retry.policy.MapRetryContextCache;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.StringUtils;

/**
* @author Dave Syer
*
*/
public class FaultTolerantStepFactoryBeanRetryTests {

  protected final Log logger = LogFactory.getLog(getClass());

  private FaultTolerantStepFactoryBean<String, String> factory;

  private List<Object> recovered = new ArrayList<Object>();

  private List<Object> processed = new ArrayList<Object>();

  private List<Object> provided = new ArrayList<Object>();

  private List<Object> written = TransactionAwareProxyFactory
      .createTransactionalList();

  int count = 0;

  boolean fail = false;

  private SimpleJobRepository repository = new SimpleJobRepository(
      new MapJobInstanceDao(), new MapJobExecutionDao(),
      new MapStepExecutionDao(), new MapExecutionContextDao());

  JobExecution jobExecution;

  private ItemWriter<String> writer = new ItemWriter<String>() {
    @Override
    public void write(List<? extends String> data) throws Exception {
      processed.addAll(data);
    }
  };

  @SuppressWarnings("unchecked")
  @Before
  public void setUp() throws Exception {

    factory = new FaultTolerantStepFactoryBean<String, String>();
    factory.setBeanName("step");

    factory.setItemReader(new ListItemReader<String>(
        new ArrayList<String>()));
    factory.setItemWriter(writer);
    factory.setJobRepository(repository);
    factory.setTransactionManager(new ResourcelessTransactionManager());
    factory.setRetryableExceptionClasses(getExceptionMap(Exception.class));
    factory.setCommitInterval(1); // trivial by default

    factory.setSkippableExceptionClasses(getExceptionMap(Exception.class));

    JobParameters jobParameters = new JobParametersBuilder().addString(
        "statefulTest", "make_this_unique").toJobParameters();
    jobExecution = repository.createJobExecution("job", jobParameters);
    jobExecution.setEndTime(new Date());

  }

  @Test
  public void testType() throws Exception {
    assertTrue(Step.class.isAssignableFrom(factory.getObjectType()));
  }

  @SuppressWarnings("cast")
  @Test
  public void testDefaultValue() throws Exception {
    assertTrue(factory.getObject() instanceof Step);
  }

  @Test
  public void testProcessAllItemsWhenErrorInWriterTransformationWhenReaderTransactional()
      throws Exception {
    final int RETRY_LIMIT = 3;
    final List<String> ITEM_LIST =  TransactionAwareProxyFactory.createTransactionalList(Arrays.asList("1", "2", "3"));
    FaultTolerantStepFactoryBean<String, Integer> factory = new FaultTolerantStepFactoryBean<String, Integer>();
    factory.setBeanName("step");

    factory.setJobRepository(repository);
    factory.setTransactionManager(new ResourcelessTransactionManager());
    ItemWriter<Integer> failingWriter = new ItemWriter<Integer>() {
      @Override
      public void write(List<? extends Integer> data) throws Exception {
        int count = 0;
        for (Integer item : data) {
          if (count++ == 2) {
            throw new Exception("Planned failure in writer");
          }
          written.add(item);
        }
      }
    };

    ItemProcessor<String, Integer> processor = new ItemProcessor<String, Integer>() {
      @Override
      public Integer process(String item) throws Exception {
        processed.add(item);
        return Integer.parseInt(item);
      }
    };
    ItemReader<String> reader = new ListItemReader<String>(TransactionAwareProxyFactory.createTransactionalList(ITEM_LIST));
    factory.setCommitInterval(3);
    factory.setRetryLimit(RETRY_LIMIT);
    factory.setSkipLimit(1);
    factory.setIsReaderTransactionalQueue(true);
    @SuppressWarnings("unchecked")
    Map<Class<? extends Throwable>, Boolean> exceptionMap = getExceptionMap(Exception.class);
    factory.setSkippableExceptionClasses(exceptionMap);
    factory.setRetryableExceptionClasses(exceptionMap);
    factory.setItemReader(reader);
    factory.setItemProcessor(processor);
    factory.setItemWriter(failingWriter);
    Step step = factory.getObject();

    StepExecution stepExecution = new StepExecution(step.getName(),
        jobExecution);
    repository.add(stepExecution);
    step.execute(stepExecution);
    /*
     * Each chunk tried up to RETRY_LIMIT, then the scan processes each item
     * once, identifying the skip as it goes
     */
    assertEquals((RETRY_LIMIT +1) * ITEM_LIST.size(), processed.size());
  }

  @Test
  public void testProcessAllItemsWhenErrorInWriter() throws Exception {
    final int RETRY_LIMIT = 3;
    final List<String> ITEM_LIST = Arrays.asList("a", "b", "c");
    ItemWriter<String> failingWriter = new ItemWriter<String>() {
      @Override
      public void write(List<? extends String> data) throws Exception {
        int count = 0;
        for (String item : data) {
          if (count++ == 2) {
            throw new Exception("Planned failure in writer");
          }
          written.add(item);
        }
      }
    };

    ItemProcessor<String, String> processor = new ItemProcessor<String, String>() {
      @Override
      public String process(String item) throws Exception {
        processed.add(item);
        return item;
      }
    };
    ItemReader<String> reader = new ListItemReader<String>(ITEM_LIST);
    factory.setCommitInterval(3);
    factory.setRetryLimit(RETRY_LIMIT);
    factory.setSkipLimit(1);
    @SuppressWarnings("unchecked")
    Map<Class<? extends Throwable>, Boolean> exceptionMap = getExceptionMap(Exception.class);
    factory.setSkippableExceptionClasses(exceptionMap);
    factory.setItemReader(reader);
    factory.setItemProcessor(processor);
    factory.setItemWriter(failingWriter);
    Step step = factory.getObject();

    StepExecution stepExecution = new StepExecution(step.getName(),
        jobExecution);
    repository.add(stepExecution);
    step.execute(stepExecution);
    assertEquals(ExitStatus.COMPLETED.getExitCode(), stepExecution
        .getExitStatus().getExitCode());
    /*
     * Each chunk tried up to RETRY_LIMIT, then the scan processes each item
     * once, identifying the skip as it goes
     */
    assertEquals((RETRY_LIMIT +1) * ITEM_LIST.size(), processed.size());
  }

  @Test
  public void testNoItemsReprocessedWhenErrorInWriterAndProcessorNotTransactional()
      throws Exception {
    ItemWriter<String> failingWriter = new ItemWriter<String>() {
      @Override
      public void write(List<? extends String> data) throws Exception {
        int count = 0;
        for (String item : data) {
          if (count++ == 2) {
            throw new Exception("Planned failure in writer");
          }
          written.add(item);
        }
      }
    };

    ItemProcessor<String, String> processor = new ItemProcessor<String, String>() {
      @Override
      public String process(String item) throws Exception {
        processed.add(item);
        return item;
      }
    };
    ItemReader<String> reader = new ListItemReader<String>(Arrays.asList(
        "a", "b", "c"));
    factory.setProcessorTransactional(false);
    factory.setCommitInterval(3);
    factory.setRetryLimit(3);
    factory.setSkippableExceptionClasses(new HashMap<Class<? extends Throwable>, Boolean>());
    factory.setItemReader(reader);
    factory.setItemProcessor(processor);
    factory.setItemWriter(failingWriter);
    Step step = factory.getObject();

    StepExecution stepExecution = new StepExecution(step.getName(),
        jobExecution);
    repository.add(stepExecution);
    step.execute(stepExecution);
    assertEquals(3, processed.size()); // Initial try only, then cached
  }

  /**
   * N.B. this doesn't really test retry, since the retry is only on write
   * failures, but it does test that read errors are re-presented for another
   * try when the retryLimit is high enough (it is used to build an exception
   * handler).
   *
   * @throws Exception
   */
  @SuppressWarnings("unchecked")
  @Test
  public void testSuccessfulRetryWithReadFailure() throws Exception {
    ItemReader<String> provider = new ListItemReader<String>(Arrays.asList(
        "a", "b", "c")) {
      @Override
      public String read() {
        String item = super.read();
        provided.add(item);
        count++;
        if (count == 2) {
          throw new RuntimeException(
              "Temporary error - retry for success.");
        }
        return item;
      }
    };
    factory.setItemReader(provider);
    factory.setRetryLimit(10);
    factory.setSkippableExceptionClasses(getExceptionMap());
    Step step = factory.getObject();

    StepExecution stepExecution = new StepExecution(step.getName(),
        jobExecution);
    repository.add(stepExecution);
    step.execute(stepExecution);

    assertEquals(0, stepExecution.getSkipCount());

    // [a, b with error]
    assertEquals(2, provided.size());
    // [a]
    assertEquals(1, processed.size());
    // []
    assertEquals(0, recovered.size());
    assertEquals(1, stepExecution.getReadCount());
    assertEquals(0, stepExecution.getReadSkipCount());
  }

  @Test
  public void testRestartAfterFailedWrite() throws Exception {

    factory.setSkipLimit(0);
    factory.setCommitInterval(3);
    AbstractItemCountingItemStreamItemReader<String> reader = new AbstractItemCountingItemStreamItemReader<String>() {

      private ItemReader<String> reader;

      @Override
      protected void doClose() throws Exception {
        reader = null;
      }

      @Override
      protected void doOpen() throws Exception {
        reader = new ListItemReader<String>(Arrays.asList("a", "b",
            "c", "d", "e", "f"));
      }

      @Override
      protected String doRead() throws Exception {
        return reader.read();
      }

    };
    // Need to set name or else reader will fail to open
    reader.setName("foo");
    factory.setItemReader(reader);
    factory.setStreams(new ItemStream[] { reader });
    factory.setItemWriter(new ItemWriter<String>() {
      @Override
      public void write(List<? extends String> items) throws Exception {
        if (fail && items.contains("e")) {
          throw new RuntimeException("Planned failure");
        }
        processed.addAll(items);
      }
    });
    factory.setRetryLimit(0);
    Step step = factory.getObject();

    fail = true;
    StepExecution stepExecution = new StepExecution(step.getName(),
        jobExecution);
    repository.add(stepExecution);
    step.execute(stepExecution);

    assertEquals(BatchStatus.FAILED, stepExecution.getStatus());
    assertEquals(4, stepExecution.getWriteCount());
    assertEquals(6, stepExecution.getReadCount());

    fail = false;
    ExecutionContext executionContext = stepExecution.getExecutionContext();
    stepExecution = new StepExecution(step.getName(), jobExecution);
    stepExecution.setExecutionContext(executionContext);
    repository.add(stepExecution);
    step.execute(stepExecution);

    assertEquals(BatchStatus.COMPLETED, stepExecution.getStatus());
    assertEquals(2, stepExecution.getWriteCount());
    assertEquals(2, stepExecution.getReadCount());
  }

  @Test
  public void testSkipAndRetry() throws Exception {

    factory.setSkipLimit(2);
    ItemReader<String> provider = new ListItemReader<String>(Arrays.asList(
        "a", "b", "c", "d", "e", "f")) {
      @Override
      public String read() {
        String item = super.read();
        count++;
        if ("b".equals(item) || "d".equals(item)) {
          throw new RuntimeException(
              "Read error - planned but skippable.");
        }
        return item;
      }
    };
    factory.setItemReader(provider);
    factory.setRetryLimit(10);
    Step step = factory.getObject();

    StepExecution stepExecution = new StepExecution(step.getName(),
        jobExecution);
    repository.add(stepExecution);
    step.execute(stepExecution);

    assertEquals(2, stepExecution.getSkipCount());
    // b is processed once and skipped, plus 1, plus c, plus the null at end
    assertEquals(7, count);
    assertEquals(4, stepExecution.getReadCount());
  }

  @SuppressWarnings("unchecked")
  @Test
  public void testSkipAndRetryWithWriteFailure() throws Exception {

    factory.setListeners(new StepListener[] { new SkipListenerSupport<String, String>() {
      @Override
      public void onSkipInWrite(String item, Throwable t) {
        recovered.add(item);
        assertTrue(TransactionSynchronizationManager
            .isActualTransactionActive());
      }
    } });
    factory.setSkipLimit(2);
    ItemReader<String> provider = new ListItemReader<String>(Arrays.asList(
        "a", "b", "c", "d", "e", "f")) {
      @Override
      public String read() {
        String item = super.read();
        logger.debug("Read Called! Item: [" + item + "]");
        provided.add(item);
        count++;
        return item;
      }
    };

    ItemWriter<String> itemWriter = new ItemWriter<String>() {
      @Override
      public void write(List<? extends String> item) throws Exception {
        logger.debug("Write Called! Item: [" + item + "]");
        processed.addAll(item);
        written.addAll(item);
        if (item.contains("b") || item.contains("d")) {
          throw new RuntimeException(
              "Write error - planned but recoverable.");
        }
      }
    };
    factory.setItemReader(provider);
    factory.setItemWriter(itemWriter);
    factory.setRetryLimit(5);
    factory.setRetryableExceptionClasses(getExceptionMap(RuntimeException.class));
    AbstractStep step = (AbstractStep) factory.getObject();
    step.setName("mytest");
    StepExecution stepExecution = new StepExecution(step.getName(),
        jobExecution);
    repository.add(stepExecution);
    step.execute(stepExecution);

    assertEquals(2, recovered.size());
    assertEquals(2, stepExecution.getSkipCount());
    assertEquals(2, stepExecution.getWriteSkipCount());

    List<String> expectedOutput = Arrays.asList(StringUtils
        .commaDelimitedListToStringArray("a,c,e,f"));
    assertEquals(expectedOutput, written);

    assertEquals("[a, b, c, d, e, f, null]", provided.toString());
    assertEquals("[a, b, b, b, b, b, b, c, d, d, d, d, d, d, e, f]",
        processed.toString());
    assertEquals("[b, d]", recovered.toString());
  }

  @SuppressWarnings("unchecked")
  @Test
  public void testSkipAndRetryWithWriteFailureAndNonTrivialCommitInterval()
      throws Exception {

    factory.setCommitInterval(3);
    factory.setListeners(new StepListener[] { new SkipListenerSupport<String, String>() {
      @Override
      public void onSkipInWrite(String item, Throwable t) {
        recovered.add(item);
        assertTrue(TransactionSynchronizationManager
            .isActualTransactionActive());
      }
    } });
    factory.setSkipLimit(2);
    ItemReader<String> provider = new ListItemReader<String>(Arrays.asList(
        "a", "b", "c", "d", "e", "f")) {
      @Override
      public String read() {
        String item = super.read();
        logger.debug("Read Called! Item: [" + item + "]");
        provided.add(item);
        count++;
        return item;
      }
    };

    ItemWriter<String> itemWriter = new ItemWriter<String>() {
      @Override
      public void write(List<? extends String> item) throws Exception {
        logger.debug("Write Called! Item: [" + item + "]");
        processed.addAll(item);
        written.addAll(item);
        if (item.contains("b") || item.contains("d")) {
          throw new RuntimeException(
              "Write error - planned but recoverable.");
        }
      }
    };
    factory.setItemReader(provider);
    factory.setItemWriter(itemWriter);
    factory.setRetryLimit(5);
    factory.setRetryableExceptionClasses(getExceptionMap(RuntimeException.class));
    AbstractStep step = (AbstractStep) factory.getObject();
    step.setName("mytest");
    StepExecution stepExecution = new StepExecution(step.getName(),
        jobExecution);
    repository.add(stepExecution);
    step.execute(stepExecution);

    assertEquals(2, recovered.size());
    assertEquals(2, stepExecution.getSkipCount());
    assertEquals(2, stepExecution.getWriteSkipCount());

    List<String> expectedOutput = Arrays.asList(StringUtils
        .commaDelimitedListToStringArray("a,c,e,f"));
    assertEquals(expectedOutput, written);

    // [a, b, c, d, e, f, null]
    assertEquals(7, provided.size());
    // [a, b, c, a, b, c, a, b, c, a, b, c, a, b, c, a, b, c, d, e, f, d,
    // e, f, d, e, f, d, e, f, d, e, f, d, e, f]
    // System.err.println(processed);
    assertEquals(36, processed.size());
    // [b, d]
    assertEquals(2, recovered.size());
  }

  @Test
  public void testRetryWithNoSkip() throws Exception {

    factory.setRetryLimit(4);
    factory.setSkipLimit(0);
    ItemReader<String> provider = new ListItemReader<String>(
        Arrays.asList("b")) {
      @Override
      public String read() {
        String item = super.read();
        provided.add(item);
        count++;
        return item;
      }
    };
    ItemWriter<String> itemWriter = new ItemWriter<String>() {
      @Override
      public void write(List<? extends String> item) throws Exception {
        processed.addAll(item);
        written.addAll(item);
        logger.debug("Write Called! Item: [" + item + "]");
        throw new RuntimeException(
            "Write error - planned but retryable.");
      }
    };
    factory.setItemReader(provider);
    factory.setItemWriter(itemWriter);
    Step step = factory.getObject();

    StepExecution stepExecution = new StepExecution(step.getName(),
        jobExecution);
    repository.add(stepExecution);
    step.execute(stepExecution);
    assertEquals(BatchStatus.FAILED, stepExecution.getStatus());

    List<String> expectedOutput = Arrays.asList(StringUtils
        .commaDelimitedListToStringArray(""));
    assertEquals(expectedOutput, written);

    assertEquals(0, stepExecution.getSkipCount());
    // [b]
    assertEquals(1, provided.size());
    // the failed items are tried up to the limit (but only precisely so if
    // the commit interval is 1)
    assertEquals("[b, b, b, b, b]", processed.toString());
    // []
    assertEquals(0, recovered.size());
    assertEquals(1, stepExecution.getReadCount());
  }

  @SuppressWarnings("unchecked")
  @Test
  public void testNonSkippableException() throws Exception {

    // Very specific skippable exception
    factory.setSkippableExceptionClasses(getExceptionMap(UnsupportedOperationException.class));
    // ...which is not retryable...
    factory.setRetryableExceptionClasses(getExceptionMap());

    factory.setSkipLimit(1);
    ItemReader<String> provider = new ListItemReader<String>(
        Arrays.asList("b")) {
      @Override
      public String read() {
        String item = super.read();
        provided.add(item);
        count++;
        return item;
      }
    };
    ItemWriter<String> itemWriter = new ItemWriter<String>() {
      @Override
      public void write(List<? extends String> item) throws Exception {
        processed.addAll(item);
        written.addAll(item);
        logger.debug("Write Called! Item: [" + item + "]");
        throw new RuntimeException(
            "Write error - planned but not skippable.");
      }
    };
    factory.setItemReader(provider);
    factory.setItemWriter(itemWriter);
    Step step = factory.getObject();

    StepExecution stepExecution = new StepExecution(step.getName(),
        jobExecution);
    repository.add(stepExecution);
    step.execute(stepExecution);
    String message = stepExecution.getFailureExceptions().get(0)
        .getMessage();
    assertTrue("Wrong message: " + message,
        message.contains("Write error - planned but not skippable."));

    List<String> expectedOutput = Arrays.asList(StringUtils
        .commaDelimitedListToStringArray(""));
    assertEquals(expectedOutput, written);

    assertEquals(0, stepExecution.getSkipCount());
    // [b]
    assertEquals("[b]", provided.toString());
    // [b]
    assertEquals("[b]", processed.toString());
    // []
    assertEquals(0, recovered.size());
    assertEquals(1, stepExecution.getReadCount());
  }

  @Test
  public void testRetryPolicy() throws Exception {
    factory.setRetryPolicy(new SimpleRetryPolicy(4, Collections
        .<Class<? extends Throwable>, Boolean> singletonMap(
            Exception.class, true)));
    factory.setSkipLimit(0);
    ItemReader<String> provider = new ListItemReader<String>(
        Arrays.asList("b")) {
      @Override
      public String read() {
        String item = super.read();
        provided.add(item);
        count++;
        return item;
      }
    };
    ItemWriter<String> itemWriter = new ItemWriter<String>() {
      @Override
      public void write(List<? extends String> item) throws Exception {
        processed.addAll(item);
        written.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();

    StepExecution stepExecution = new StepExecution(step.getName(),
        jobExecution);
    repository.add(stepExecution);
    step.execute(stepExecution);
    assertEquals(BatchStatus.FAILED, stepExecution.getStatus());

    List<String> expectedOutput = Arrays.asList(StringUtils
        .commaDelimitedListToStringArray(""));
    assertEquals(expectedOutput, written);

    assertEquals(0, stepExecution.getSkipCount());
    // [b]
    assertEquals(1, provided.size());
    assertEquals("[b, b, b, b, b]", processed.toString());
    // []
    assertEquals(0, recovered.size());
    assertEquals(1, stepExecution.getReadCount());
  }

  @Test
  public void testCacheLimitWithRetry() throws Exception {
    factory.setRetryLimit(2);
    factory.setCommitInterval(3);
    // sufficiently high so we never hit it
    factory.setSkipLimit(10);
    // set the cache limit stupidly low
    factory.setRetryContextCache(new MapRetryContextCache(0));
    ItemReader<String> provider = new ItemReader<String>() {
      @Override
      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<String> itemWriter = new ItemWriter<String>() {
      @Override
      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();

    StepExecution stepExecution = new StepExecution(step.getName(),
        jobExecution);
    repository.add(stepExecution);
    step.execute(stepExecution);
    assertEquals(BatchStatus.FAILED, stepExecution.getStatus());

    // We added a bogus cache so no items are actually skipped
    // because they aren't recognised as eligible
    assertEquals(0, stepExecution.getSkipCount());
    // [0, 1, 2]
    assertEquals(3, provided.size());
    // [0, 1, 2]
    assertEquals(3, processed.size());
    // []
    assertEquals(0, recovered.size());
  }

  private Map<Class<? extends Throwable>, Boolean> getExceptionMap(
      Class<? extends Throwable>... args) {
    Map<Class<? extends Throwable>, Boolean> map = new HashMap<Class<? extends Throwable>, Boolean>();
    for (Class<? extends Throwable> arg : args) {
      map.put(arg, true);
    }
    return map;
  }
}
TOP

Related Classes of org.springframework.batch.core.step.item.FaultTolerantStepFactoryBeanRetryTests

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.