diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/CommonItemReaderTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/CommonItemReaderTests.java
new file mode 100644
index 000000000..a8fd20c1e
--- /dev/null
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/CommonItemReaderTests.java
@@ -0,0 +1,67 @@
+package org.springframework.batch.item;
+
+import org.springframework.batch.item.sample.Foo;
+import org.springframework.util.Assert;
+
+import junit.framework.TestCase;
+
+/**
+ * Common tests for {@link ItemReader} implementations. Expected input is five
+ * {@link Foo} objects with values 1 to 5.
+ */
+public abstract class CommonItemReaderTests extends TestCase {
+
+ protected ItemReader tested;
+
+ /**
+ * @return configured ItemReader ready for use.
+ */
+ protected abstract ItemReader getItemReader() throws Exception;
+
+ protected void setUp() throws Exception {
+ tested = getItemReader();
+ }
+
+ /**
+ * Regular scenario - read the input and eventually return null.
+ */
+ public void testRead() throws Exception {
+
+ Foo foo1 = (Foo) tested.read();
+ assertEquals(1, foo1.getValue());
+
+ Foo foo2 = (Foo) tested.read();
+ assertEquals(2, foo2.getValue());
+
+ Foo foo3 = (Foo) tested.read();
+ assertEquals(3, foo3.getValue());
+
+ Foo foo4 = (Foo) tested.read();
+ assertEquals(4, foo4.getValue());
+
+ Foo foo5 = (Foo) tested.read();
+ assertEquals(5, foo5.getValue());
+
+ assertNull(tested.read());
+ }
+
+ /**
+ * Rollback scenario - reader resets to last marked point.
+ */
+ public void testReset() throws Exception {
+ Foo foo1 = (Foo) tested.read();
+
+ tested.mark();
+
+ Foo foo2 = (Foo) tested.read();
+ Assert.state(!foo2.equals(foo1));
+
+ Foo foo3 = (Foo) tested.read();
+ Assert.state(!foo2.equals(foo3));
+
+ tested.reset();
+
+ assertEquals(foo2, tested.read());
+ }
+
+}
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/CommonItemStreamItemReaderTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/CommonItemStreamItemReaderTests.java
new file mode 100644
index 000000000..7d018fbe8
--- /dev/null
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/CommonItemStreamItemReaderTests.java
@@ -0,0 +1,57 @@
+package org.springframework.batch.item;
+
+import org.springframework.batch.item.sample.Foo;
+
+/**
+ * Common tests for readers implementing both {@link ItemReader} and
+ * {@link ItemStream}. Expected input is five {@link Foo} objects with values 1
+ * to 5.
+ */
+public abstract class CommonItemStreamItemReaderTests extends CommonItemReaderTests {
+
+ protected ExecutionContext executionContext = new ExecutionContext();
+
+ /**
+ * Cast the reader to ItemStream.
+ */
+ protected ItemStream testedAsStream() {
+ return (ItemStream) tested;
+ }
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ testedAsStream().open(executionContext);
+ }
+
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ testedAsStream().close(executionContext);
+ }
+
+
+
+ /**
+ * Restart scenario - read items, update execution context, create new
+ * reader and restore from restart data - the new input source should
+ * continue where the old one finished.
+ */
+ public void testRestart() throws Exception {
+
+ Foo foo1 = (Foo) tested.read();
+ assertEquals(1, foo1.getValue());
+
+ Foo foo2 = (Foo) tested.read();
+ assertEquals(2, foo2.getValue());
+
+ testedAsStream().update(executionContext);
+
+ // create new input source
+ tested = getItemReader();
+
+ testedAsStream().open(executionContext);
+
+ Foo fooAfterRestart = (Foo) tested.read();
+ assertEquals(3, fooAfterRestart.getValue());
+ }
+
+}
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/BatchSqlUpdateItemWriterTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/BatchSqlUpdateItemWriterTests.java
index d28666bee..7e2943c75 100644
--- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/BatchSqlUpdateItemWriterTests.java
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/BatchSqlUpdateItemWriterTests.java
@@ -20,9 +20,7 @@ import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.List;
-import java.util.Map;
import junit.framework.TestCase;
@@ -88,10 +86,8 @@ public class BatchSqlUpdateItemWriterTests extends TestCase {
* @see junit.framework.TestCase#tearDown()
*/
protected void tearDown() throws Exception {
- Map map = TransactionSynchronizationManager.getResourceMap();
- for (Iterator iterator = map.keySet().iterator(); iterator.hasNext();) {
- String key = (String) iterator.next();
- TransactionSynchronizationManager.unbindResource(key);
+ if (TransactionSynchronizationManager.hasResource(BatchSqlUpdateItemWriter.ITEMS_PROCESSED)) {
+ TransactionSynchronizationManager.unbindResource(BatchSqlUpdateItemWriter.ITEMS_PROCESSED);
}
RepeatSynchronizationManager.clear();
}
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/CommonDatabaseItemStreamItemReaderTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/CommonDatabaseItemStreamItemReaderTests.java
new file mode 100644
index 000000000..ae5380e2b
--- /dev/null
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/CommonDatabaseItemStreamItemReaderTests.java
@@ -0,0 +1,26 @@
+package org.springframework.batch.item.database;
+
+import javax.sql.DataSource;
+
+import org.springframework.batch.item.CommonItemStreamItemReaderTests;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+public abstract class CommonDatabaseItemStreamItemReaderTests extends CommonItemStreamItemReaderTests {
+
+ private ClassPathXmlApplicationContext ctx;
+
+ protected void setUp() throws Exception {
+ ctx = new ClassPathXmlApplicationContext("foo-data-source-context.xml", JdbcCursorItemReaderCommonTests.class);
+ super.setUp();
+ }
+
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ ctx.close();
+ }
+
+ protected DataSource getDataSource() {
+ return (DataSource) ctx.getBean("dataSource");
+ }
+
+}
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/HibernateCursorItemReaderCommonTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/HibernateCursorItemReaderCommonTests.java
new file mode 100644
index 000000000..601e36ab0
--- /dev/null
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/HibernateCursorItemReaderCommonTests.java
@@ -0,0 +1,31 @@
+package org.springframework.batch.item.database;
+
+import org.hibernate.SessionFactory;
+import org.springframework.batch.item.ItemReader;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.Resource;
+import org.springframework.orm.hibernate3.LocalSessionFactoryBean;
+
+public class HibernateCursorItemReaderCommonTests extends CommonDatabaseItemStreamItemReaderTests {
+
+ protected ItemReader getItemReader() throws Exception {
+ LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean();
+ factoryBean.setDataSource(getDataSource());
+ factoryBean.setMappingLocations(new Resource[] { new ClassPathResource("Foo.hbm.xml", getClass()) });
+ factoryBean.afterPropertiesSet();
+
+ SessionFactory sessionFactory = (SessionFactory) factoryBean.getObject();
+
+ String hsqlQuery = "from Foo";
+
+ HibernateCursorItemReader reader = new HibernateCursorItemReader();
+ reader.setQueryString(hsqlQuery);
+ reader.setSessionFactory(sessionFactory);
+ reader.setUseStatelessSession(true);
+ reader.afterPropertiesSet();
+ reader.setSaveState(true);
+
+ return reader;
+ }
+
+}
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/IbatisItemReaderCommonTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/IbatisItemReaderCommonTests.java
new file mode 100644
index 000000000..cef6f6f29
--- /dev/null
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/IbatisItemReaderCommonTests.java
@@ -0,0 +1,32 @@
+package org.springframework.batch.item.database;
+
+import org.springframework.batch.item.ItemReader;
+import org.springframework.batch.item.database.support.IbatisKeyCollector;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.orm.ibatis.SqlMapClientFactoryBean;
+
+import com.ibatis.sqlmap.client.SqlMapClient;
+
+public class IbatisItemReaderCommonTests extends CommonDatabaseItemStreamItemReaderTests {
+
+ protected ItemReader getItemReader() throws Exception {
+ SqlMapClientFactoryBean factory = new SqlMapClientFactoryBean();
+ factory.setConfigLocation(new ClassPathResource("ibatis-config.xml", getClass()));
+ factory.setDataSource(getDataSource());
+ factory.afterPropertiesSet();
+ SqlMapClient sqlMapClient = (SqlMapClient) factory.getObject();
+
+ IbatisDrivingQueryItemReader reader = new IbatisDrivingQueryItemReader();
+ IbatisKeyCollector keyGenerator = new IbatisKeyCollector();
+ keyGenerator.setDrivingQueryId("getAllFooIds");
+ reader.setDetailsQueryId("getFooById");
+ keyGenerator.setRestartQueryId("getAllFooIdsRestart");
+ keyGenerator.setSqlMapClient(sqlMapClient);
+ reader.setSqlMapClient(sqlMapClient);
+ reader.setKeyCollector(keyGenerator);
+ reader.setSaveState(true);
+
+ return reader;
+ }
+
+}
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/JdbcCursorItemReaderCommonTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/JdbcCursorItemReaderCommonTests.java
new file mode 100644
index 000000000..acd9ce86d
--- /dev/null
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/JdbcCursorItemReaderCommonTests.java
@@ -0,0 +1,24 @@
+package org.springframework.batch.item.database;
+
+import org.springframework.batch.item.ItemReader;
+
+public class JdbcCursorItemReaderCommonTests extends CommonDatabaseItemStreamItemReaderTests {
+
+ protected ItemReader getItemReader() throws Exception {
+
+ JdbcCursorItemReader result = new JdbcCursorItemReader();
+ result.setDataSource(getDataSource());
+ result.setSql("select ID, NAME, VALUE from T_FOOS");
+ result.setIgnoreWarnings(true);
+ result.setVerifyCursorPosition(true);
+
+ result.setMapper(new FooRowMapper());
+ result.setFetchSize(10);
+ result.setMaxRows(100);
+ result.setQueryTimeout(1000);
+ result.setSaveState(true);
+
+ return result;
+ }
+
+}
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/SingleColumnJdbcDrivingQueryItemReaderCommonTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/SingleColumnJdbcDrivingQueryItemReaderCommonTests.java
new file mode 100644
index 000000000..82315efb3
--- /dev/null
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/SingleColumnJdbcDrivingQueryItemReaderCommonTests.java
@@ -0,0 +1,20 @@
+package org.springframework.batch.item.database;
+
+import org.springframework.batch.item.ItemReader;
+import org.springframework.batch.item.database.support.SingleColumnJdbcKeyCollector;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+public class SingleColumnJdbcDrivingQueryItemReaderCommonTests extends CommonDatabaseItemStreamItemReaderTests {
+
+ protected ItemReader getItemReader() throws Exception {
+ JdbcTemplate jdbcTemplate = new JdbcTemplate(getDataSource());
+ SingleColumnJdbcKeyCollector keyStrategy = new SingleColumnJdbcKeyCollector(jdbcTemplate,
+ "SELECT ID from T_FOOS order by ID");
+ keyStrategy.setRestartSql("SELECT ID from T_FOOS where ID > ? order by ID");
+ DrivingQueryItemReader reader = new DrivingQueryItemReader();
+ reader.setKeyCollector(keyStrategy);
+ reader.setSaveState(true);
+ return new FooItemReader(reader, jdbcTemplate);
+ }
+
+}
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/FlatFileItemReaderCommonTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/FlatFileItemReaderCommonTests.java
new file mode 100644
index 000000000..4f2426b49
--- /dev/null
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/FlatFileItemReaderCommonTests.java
@@ -0,0 +1,32 @@
+package org.springframework.batch.item.file;
+
+import org.springframework.batch.item.CommonItemStreamItemReaderTests;
+import org.springframework.batch.item.ItemReader;
+import org.springframework.batch.item.file.mapping.FieldSet;
+import org.springframework.batch.item.file.mapping.FieldSetMapper;
+import org.springframework.batch.item.sample.Foo;
+import org.springframework.core.io.ByteArrayResource;
+import org.springframework.core.io.Resource;
+
+public class FlatFileItemReaderCommonTests extends CommonItemStreamItemReaderTests {
+
+ private final String FOOS = "1 \n 2 \n 3 \n 4 \n 5 \n";
+
+ protected ItemReader getItemReader() throws Exception {
+ FlatFileItemReader tested = new FlatFileItemReader();
+ Resource resource = new ByteArrayResource(FOOS.getBytes());
+ tested.setResource(resource);
+ tested.setFieldSetMapper(new FieldSetMapper() {
+ public Object mapLine(FieldSet fs) {
+ Foo foo = new Foo();
+ foo.setValue(fs.readInt(0));
+ return foo;
+ }
+ });
+
+ tested.setSaveState(true);
+ tested.afterPropertiesSet();
+ return tested;
+ }
+
+}
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/xml/StaxEventItemReaderCommonTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/xml/StaxEventItemReaderCommonTests.java
new file mode 100644
index 000000000..6b8e70b77
--- /dev/null
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/xml/StaxEventItemReaderCommonTests.java
@@ -0,0 +1,43 @@
+package org.springframework.batch.item.xml;
+
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.Attribute;
+import javax.xml.stream.events.StartElement;
+
+import org.springframework.batch.item.CommonItemStreamItemReaderTests;
+import org.springframework.batch.item.ItemReader;
+import org.springframework.batch.item.sample.Foo;
+import org.springframework.core.io.ByteArrayResource;
+
+public class StaxEventItemReaderCommonTests extends CommonItemStreamItemReaderTests {
+
+ private final String FOOS = " ";
+
+ protected ItemReader getItemReader() throws Exception {
+ StaxEventItemReader reader = new StaxEventItemReader();
+ reader.setResource(new ByteArrayResource(FOOS.getBytes()));
+ reader.setFragmentRootElementName("foo");
+ reader.setFragmentDeserializer(new EventReaderDeserializer() {
+ public Object deserializeFragment(XMLEventReader eventReader) {
+ Attribute attr;
+ try {
+ assertTrue(eventReader.nextEvent().isStartDocument());
+ StartElement event = eventReader.nextEvent().asStartElement();
+ attr = (Attribute) event.getAttributes().next();
+ }
+ catch (XMLStreamException e) {
+ throw new RuntimeException(e);
+ }
+ Foo foo = new Foo();
+ foo.setValue(Integer.parseInt(attr.getValue()));
+ return foo;
+ }
+ });
+
+ reader.setSaveState(true);
+ reader.afterPropertiesSet();
+ return reader;
+ }
+
+}
diff --git a/spring-batch-infrastructure/src/test/resources/org/springframework/batch/item/database/foo-data-source-context.xml b/spring-batch-infrastructure/src/test/resources/org/springframework/batch/item/database/foo-data-source-context.xml
new file mode 100644
index 000000000..0cb93caa3
--- /dev/null
+++ b/spring-batch-infrastructure/src/test/resources/org/springframework/batch/item/database/foo-data-source-context.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file