From 7a513d4749a6a274b68f15868e9c2959d893e836 Mon Sep 17 00:00:00 2001 From: dsyer Date: Tue, 25 Mar 2008 17:10:26 +0000 Subject: [PATCH] OPEN - issue BATCH-498: Skip method should get ExecutionContext as an argument Handle skip internally in ItemHandler. --- .../item/ItemSkipPolicyItemHandlerTests.java | 189 ++++++++++++++++++ .../item/SkipLimitStepFactoryBeanTests.java | 30 +-- 2 files changed, 195 insertions(+), 24 deletions(-) create mode 100644 spring-batch-core/src/test/java/org/springframework/batch/core/step/item/ItemSkipPolicyItemHandlerTests.java diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/ItemSkipPolicyItemHandlerTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/ItemSkipPolicyItemHandlerTests.java new file mode 100644 index 000000000..500b4d953 --- /dev/null +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/ItemSkipPolicyItemHandlerTests.java @@ -0,0 +1,189 @@ +/* + * 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 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.StepContribution; +import org.springframework.batch.core.job.JobSupport; +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.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; + +/** + * @author Dave Syer + * + */ +public class ItemSkipPolicyItemHandlerTests extends TestCase { + + private ItemSkipPolicyItemHandler handler = new ItemSkipPolicyItemHandler(new SkipReaderStub(), + new SkipWriterStub()); + + private StepContribution contribution = new StepContribution(new JobExecution(new JobInstance(new Long(11), + new JobParameters(), new JobSupport())).createStepExecution(new StepSupport("foo"))); + + 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.getContributionSkipCount()); + 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)); + assertEquals(1, contribution.getContributionSkipCount()); + 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.getContributionSkipCount()); + } + + public void testWriteWithSkip() throws Exception { + handler.setItemSkipPolicy(new AlwaysSkipItemSkipPolicy()); + handler.write(new Holder("3"), contribution); + try { + handler.write(new Holder("4"), contribution); + fail("Expected SkippableException"); + } + catch (SkippableException e) { + // expected + } + assertEquals(1, contribution.getContributionSkipCount()); + } + + // TODO: test the item key generator, especially with a mutable item that changes on write + + /** + * Simple item reader that supports skip functionality. + */ + private static class SkipReaderStub implements ItemReader { + + final Holder[] items = { new Holder("1"), new Holder("2"), new Holder("3"), new Holder("4"), new Holder("5"), + null }; + + Collection processed = new ArrayList(); + + int counter = -1; + + int marked = 0; + + public Object read() throws Exception, UnexpectedInputException, NoWorkFoundException, ParseException { + counter++; + if (counter == 1) { + throw new SkippableException("exception in reader"); + } + processed.add(items[counter]); + return items[counter]; + } + + 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 { + + List written = new ArrayList(); + + 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(Object item) throws Exception { + written.add(item); + if (((Holder) item).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 + "]"; + } + } + +} diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/SkipLimitStepFactoryBeanTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/SkipLimitStepFactoryBeanTests.java index 102fbc804..386af4ae9 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/SkipLimitStepFactoryBeanTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/SkipLimitStepFactoryBeanTests.java @@ -20,7 +20,6 @@ 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.Skippable; import org.springframework.batch.item.UnexpectedInputException; import org.springframework.batch.support.transaction.ResourcelessTransactionManager; @@ -67,10 +66,9 @@ public class SkipLimitStepFactoryBeanTests extends TestCase { assertEquals(2, stepExecution.getSkipCount()); - assertTrue(reader.skipped.contains("2")); - assertTrue(reader.skipped.contains("4")); // writer did not skip "2" as it never made it to writer, only "4" did - assertTrue(writer.skipped.contains("4")); + assertTrue(reader.processed.contains("4")); + assertFalse(writer.written.contains("4")); String[] expectedOutput = { "1", "3", "5" }; @@ -109,11 +107,11 @@ public class SkipLimitStepFactoryBeanTests extends TestCase { /** * Simple item reader that supports skip functionality. */ - private static class SkipReaderStub implements ItemReader, Skippable { + private static class SkipReaderStub implements ItemReader { final String[] items = { "1", "2", "3", "4", "5", null }; - Collection skipped = new ArrayList(); + Collection processed = new ArrayList(); int counter = -1; @@ -121,12 +119,10 @@ public class SkipLimitStepFactoryBeanTests extends TestCase { public Object read() throws Exception, UnexpectedInputException, NoWorkFoundException, ParseException { counter++; - while (skipped.contains(items[counter])) { - counter++; - } if ("2".equals(items[counter])) { throw new SkippableException("exception in reader"); } + processed.add(items[counter]); return items[counter]; } @@ -138,21 +134,15 @@ public class SkipLimitStepFactoryBeanTests extends TestCase { counter = marked; } - public void skip() { - skipped.add(items[counter]); - } - } /** * Simple item writer that supports skip functionality. */ - private static class SkipWriterStub implements ItemWriter, Skippable { + private static class SkipWriterStub implements ItemWriter { List written = new ArrayList(); - Collection skipped = new ArrayList(); - int flushIndex = -1; public void clear() throws ClearFailedException { @@ -166,20 +156,12 @@ public class SkipLimitStepFactoryBeanTests extends TestCase { } public void write(Object item) throws Exception { - if (skipped.contains(item)) { - return; - } written.add(item); if (item.equals("4")) { throw new SkippableRuntimeException("exception in writer"); } } - public void skip() { - int lastIndex = written.size() - 1; - skipped.add(written.get(lastIndex)); - } - } private static class SkippableException extends Exception {