@Test
 public void testFilterCountOnSkip() throws Exception {
   processor.setProcessSkipPolicy(new AlwaysSkipItemSkipPolicy());
   processor.setItemProcessor(
       new ItemProcessor<String, String>() {
         public String process(String item) throws Exception {
           if (item.equals("1")) {
             throw new RuntimeException("Skippable");
           }
           if (item.equals("3")) {
             return null;
           }
           return item;
         }
       });
   Chunk<String> inputs = new Chunk<String>(Arrays.asList("3", "1", "2"));
   try {
     processor.process(contribution, inputs);
     fail("Expected Exception");
   } catch (Exception e) {
     assertEquals("Skippable", e.getMessage());
   }
   processor.process(contribution, inputs);
   assertEquals(1, list.size());
   assertEquals(1, contribution.getSkipCount());
   assertEquals(1, contribution.getFilterCount());
 }
  @Test
  public void testOnErrorInWriteAllItemsFail() throws Exception {
    Chunk<String> chunk = new Chunk<String>(Arrays.asList("foo", "bar"));
    processor =
        new FaultTolerantChunkProcessor<String, String>(
            new PassThroughItemProcessor<String>(),
            new ItemWriter<String>() {
              public void write(List<? extends String> items) throws Exception {
                // Always fail in writer
                throw new RuntimeException("Planned failure!");
              }
            },
            batchRetryTemplate);
    processor.setListeners(
        Arrays.asList(
            new ItemListenerSupport<String, String>() {
              @Override
              public void onWriteError(Exception e, List<? extends String> item) {
                writeError.addAll(item);
              }
            }));
    processor.setWriteSkipPolicy(new AlwaysSkipItemSkipPolicy());

    processAndExpectPlannedRuntimeException(chunk); // Process foo, bar
    processAndExpectPlannedRuntimeException(chunk); // Process foo
    processAndExpectPlannedRuntimeException(chunk); // Process bar

    assertEquals("[foo, bar, foo, bar]", writeError.toString());
  }
  @Test
  public void testAfterWriteAllPassedInRecovery() throws Exception {
    Chunk<String> chunk = new Chunk<String>(Arrays.asList("foo", "bar"));
    processor =
        new FaultTolerantChunkProcessor<String, String>(
            new PassThroughItemProcessor<String>(),
            new ItemWriter<String>() {
              public void write(List<? extends String> items) throws Exception {
                // Fail if there is more than one item
                if (items.size() > 1) {
                  throw new RuntimeException("Planned failure!");
                }
                list.addAll(items);
              }
            },
            batchRetryTemplate);
    processor.setListeners(
        Arrays.asList(
            new ItemListenerSupport<String, String>() {
              @Override
              public void afterWrite(List<? extends String> item) {
                after.addAll(item);
              }
            }));
    processor.setWriteSkipPolicy(new AlwaysSkipItemSkipPolicy());

    processAndExpectPlannedRuntimeException(chunk);
    processor.process(contribution, chunk);
    processor.process(contribution, chunk);

    assertEquals("[foo, bar]", list.toString());
    assertEquals("[foo, bar]", after.toString());
  }
 @Test
 public void testAfterWrite() throws Exception {
   Chunk<String> chunk = new Chunk<String>(Arrays.asList("foo", "fail", "bar"));
   processor.setListeners(
       Arrays.asList(
           new ItemListenerSupport<String, String>() {
             @Override
             public void afterWrite(List<? extends String> item) {
               after.addAll(item);
             }
           }));
   processor.setWriteSkipPolicy(new AlwaysSkipItemSkipPolicy());
   processAndExpectPlannedRuntimeException(chunk);
   processor.process(contribution, chunk);
   assertEquals(2, chunk.getItems().size());
   processAndExpectPlannedRuntimeException(chunk);
   assertEquals(1, chunk.getItems().size());
   processor.process(contribution, chunk);
   assertEquals(0, chunk.getItems().size());
   // foo is written once because it the failure is detected before it is
   // committed the first time
   assertEquals("[foo, bar]", list.toString());
   // the after listener is called once per successful item, which is
   // important
   assertEquals("[foo, bar]", after.toString());
 }
 @Test
 public void testWriteSkipOnExceptionWithTrivialChunk() throws Exception {
   processor.setWriteSkipPolicy(new AlwaysSkipItemSkipPolicy());
   processor.setItemWriter(
       new ItemWriter<String>() {
         public void write(List<? extends String> items) throws Exception {
           if (items.contains("fail")) {
             throw new RuntimeException("Expected Exception!");
           }
         }
       });
   Chunk<String> inputs = new Chunk<String>(Arrays.asList("fail"));
   try {
     processor.process(contribution, inputs);
     fail("Expected RuntimeException");
   } catch (RuntimeException e) {
     assertEquals("Expected Exception!", e.getMessage());
   }
   // BATCH-1518: ideally we would not want this to be necessary, but it
   // still is...
   try {
     processor.process(contribution, inputs);
     fail("Expected RuntimeException");
   } catch (RuntimeException e) {
     assertEquals("Expected Exception!", e.getMessage());
   }
   processor.process(contribution, inputs);
   assertEquals(1, contribution.getSkipCount());
   assertEquals(0, contribution.getWriteCount());
   assertEquals(0, contribution.getFilterCount());
 }
 @Test
 public void testWriteSkipOnException() throws Exception {
   processor.setWriteSkipPolicy(new AlwaysSkipItemSkipPolicy());
   processor.setItemWriter(
       new ItemWriter<String>() {
         public void write(List<? extends String> items) throws Exception {
           if (items.contains("fail")) {
             throw new RuntimeException("Expected Exception!");
           }
         }
       });
   Chunk<String> inputs = new Chunk<String>(Arrays.asList("3", "fail", "2"));
   try {
     processor.process(contribution, inputs);
     fail("Expected RuntimeException");
   } catch (RuntimeException e) {
     assertEquals("Expected Exception!", e.getMessage());
   }
   processor.process(contribution, inputs);
   try {
     processor.process(contribution, inputs);
     fail("Expected RuntimeException");
   } catch (RuntimeException e) {
     assertEquals("Expected Exception!", e.getMessage());
   }
   assertEquals(1, contribution.getSkipCount());
   assertEquals(1, contribution.getWriteCount());
   assertEquals(0, contribution.getFilterCount());
 }
 @Test
 public void testTransform() throws Exception {
   processor.setItemProcessor(
       new ItemProcessor<String, String>() {
         public String process(String item) throws Exception {
           return item.equals("1") ? null : item;
         }
       });
   Chunk<String> inputs = new Chunk<String>(Arrays.asList("1", "2"));
   processor.process(contribution, inputs);
   assertEquals(1, list.size());
   assertEquals(1, contribution.getFilterCount());
 }
 protected void processAndExpectPlannedRuntimeException(Chunk<String> chunk) throws Exception {
   try {
     processor.process(contribution, chunk);
     fail();
   } catch (RuntimeException e) {
     assertEquals("Planned failure!", e.getMessage());
   }
 }
 @Test
 // BATCH-1804
 public void testWriteRetryOnNonSkippableException() throws Exception {
   SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
   retryPolicy.setMaxAttempts(2);
   batchRetryTemplate.setRetryPolicy(retryPolicy);
   processor.setWriteSkipPolicy(
       new LimitCheckingItemSkipPolicy(
           1,
           Collections.<Class<? extends Throwable>, Boolean>singletonMap(
               IllegalArgumentException.class, true)));
   processor.setItemWriter(
       new ItemWriter<String>() {
         public void write(List<? extends String> items) throws Exception {
           if (items.contains("fail")) {
             throw new IllegalArgumentException("Expected Exception!");
           }
           if (items.contains("2")) {
             throw new RuntimeException("Expected Non-Skippable Exception!");
           }
         }
       });
   Chunk<String> inputs = new Chunk<String>(Arrays.asList("3", "fail", "2"));
   try {
     processor.process(contribution, inputs);
     fail("Expected IllegalArgumentException");
   } catch (IllegalArgumentException e) {
     assertEquals("Expected Exception!", e.getMessage());
   }
   try {
     // first retry
     processor.process(contribution, inputs);
     fail("Expected IllegalArgumentException");
   } catch (IllegalArgumentException e) {
     assertEquals("Expected Exception!", e.getMessage());
   }
   // retry exhausted, now scanning
   processor.process(contribution, inputs);
   try {
     // skip on this attempt
     processor.process(contribution, inputs);
     fail("Expected IllegalArgumentException");
   } catch (IllegalArgumentException e) {
     assertEquals("Expected Exception!", e.getMessage());
   }
   try {
     // should retry
     processor.process(contribution, inputs);
     fail("Expected RuntimeException");
   } catch (RetryException e) {
     throw e;
   } catch (RuntimeException e) {
     assertEquals("Expected Non-Skippable Exception!", e.getMessage());
   }
   assertEquals(1, contribution.getSkipCount());
   assertEquals(1, contribution.getWriteCount());
   assertEquals(0, contribution.getFilterCount());
 }
 @Test
 public void testTransformWithExceptionAndNoRollback() throws Exception {
   processor.setItemProcessor(
       new ItemProcessor<String, String>() {
         public String process(String item) throws Exception {
           if (item.equals("1")) throw new DataIntegrityViolationException("Planned");
           return item;
         }
       });
   processor.setProcessSkipPolicy(new AlwaysSkipItemSkipPolicy());
   processor.setRollbackClassifier(
       new BinaryExceptionClassifier(
           Collections.<Class<? extends Throwable>>singleton(
               DataIntegrityViolationException.class),
           false));
   Chunk<String> inputs = new Chunk<String>(Arrays.asList("1", "2"));
   processor.process(contribution, inputs);
   assertEquals(1, list.size());
 }
  @Test
  public void testOnErrorInWrite() throws Exception {
    Chunk<String> chunk = new Chunk<String>(Arrays.asList("foo", "fail"));
    processor.setListeners(
        Arrays.asList(
            new ItemListenerSupport<String, String>() {
              @Override
              public void onWriteError(Exception e, List<? extends String> item) {
                writeError.addAll(item);
              }
            }));
    processor.setWriteSkipPolicy(new AlwaysSkipItemSkipPolicy());

    processAndExpectPlannedRuntimeException(chunk); // Process foo, fail
    processor.process(contribution, chunk);
    ; // Process foo
    processAndExpectPlannedRuntimeException(chunk); // Process fail

    assertEquals("[foo, fail, fail]", writeError.toString());
  }
 /**
  * An Error can be retried or skipped but by default it is just propagated
  *
  * @throws Exception
  */
 @Test
 public void testWriteSkipOnError() throws Exception {
   processor.setWriteSkipPolicy(new AlwaysSkipItemSkipPolicy());
   processor.setItemWriter(
       new ItemWriter<String>() {
         public void write(List<? extends String> items) throws Exception {
           if (items.contains("fail")) {
             assertFalse("Expected Error!", true);
           }
         }
       });
   Chunk<String> inputs = new Chunk<String>(Arrays.asList("3", "fail", "2"));
   try {
     processor.process(contribution, inputs);
     fail("Expected Error");
   } catch (Error e) {
     assertEquals("Expected Error!", e.getMessage());
   }
   processor.process(contribution, inputs);
 }
 @Test
 public void testWriteRetryOnTwoExceptions() throws Exception {
   SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
   retryPolicy.setMaxAttempts(2);
   batchRetryTemplate.setRetryPolicy(retryPolicy);
   processor.setWriteSkipPolicy(new AlwaysSkipItemSkipPolicy());
   processor.setItemWriter(
       new ItemWriter<String>() {
         public void write(List<? extends String> items) throws Exception {
           if (items.contains("fail")) {
             throw new IllegalArgumentException("Expected Exception!");
           }
         }
       });
   Chunk<String> inputs = new Chunk<String>(Arrays.asList("3", "fail", "fail", "4"));
   try {
     processor.process(contribution, inputs);
     fail("Expected RuntimeException");
   } catch (RuntimeException e) {
     assertEquals("Expected Exception!", e.getMessage());
   }
   try {
     // first retry
     processor.process(contribution, inputs);
     fail("Expected RuntimeException");
   } catch (RuntimeException e) {
     assertEquals("Expected Exception!", e.getMessage());
   }
   // retry exhausted, now scanning
   processor.process(contribution, inputs);
   try {
     // skip on this attempt
     processor.process(contribution, inputs);
     fail("Expected RuntimeException");
   } catch (RuntimeException e) {
     assertEquals("Expected Exception!", e.getMessage());
   }
   try {
     // 2nd exception detected
     processor.process(contribution, inputs);
     fail("Expected RuntimeException");
   } catch (RuntimeException e) {
     assertEquals("Expected Exception!", e.getMessage());
   }
   // still scanning
   processor.process(contribution, inputs);
   assertEquals(2, contribution.getSkipCount());
   assertEquals(2, contribution.getWriteCount());
   assertEquals(0, contribution.getFilterCount());
 }
 @Test
 public void testWrite() throws Exception {
   Chunk<String> inputs = new Chunk<String>(Arrays.asList("1", "2"));
   processor.process(contribution, inputs);
   assertEquals(2, list.size());
 }