diff --git a/pom.xml b/pom.xml
index 1613c9093..0b20365fc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -101,6 +101,11 @@
6.2.5
1.9.6
8.0.23
+ 42.2.22
+ 11.5.6.0
+ 21.1.0.0
+ 9.2.1.jre8
+ 1.3.1
1.15.3
1.0
1
diff --git a/spring-batch-core/pom.xml b/spring-batch-core/pom.xml
index 9301c44fe..8c93fc5c4 100644
--- a/spring-batch-core/pom.xml
+++ b/spring-batch-core/pom.xml
@@ -112,6 +112,66 @@
${testcontainers.version}
test
+
+ org.postgresql
+ postgresql
+ ${postgresql.version}
+ test
+
+
+ org.testcontainers
+ postgresql
+ ${testcontainers.version}
+ test
+
+
+ com.ibm.db2
+ jcc
+ ${db2.version}
+ test
+
+
+ org.testcontainers
+ db2
+ ${testcontainers.version}
+ test
+
+
+ org.testcontainers
+ oracle-xe
+ ${testcontainers.version}
+ test
+
+
+ com.oracle.database.jdbc
+ ojdbc8
+ ${oracle.version}
+ test
+
+
+ org.testcontainers
+ mssqlserver
+ ${testcontainers.version}
+ test
+
+
+ com.microsoft.sqlserver
+ mssql-jdbc
+ ${sqlserver.version}
+ test
+
+
+ net.sourceforge.jtds
+ jtds
+ ${jtds.version}
+ test
+
+
+ org.xerial
+ sqlite-jdbc
+ ${sqlite.version}
+ test
+
com.h2database
h2
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/test/repository/Db2JobRepositoryIntegrationTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/test/repository/Db2JobRepositoryIntegrationTests.java
new file mode 100644
index 000000000..9a1fd5f72
--- /dev/null
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/test/repository/Db2JobRepositoryIntegrationTests.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2020-2021 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
+ *
+ * https://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.test.repository;
+
+import javax.sql.DataSource;
+
+import com.ibm.db2.jcc.DB2SimpleDataSource;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.testcontainers.containers.Db2Container;
+import org.testcontainers.utility.DockerImageName;
+
+import org.springframework.batch.core.ExitStatus;
+import org.springframework.batch.core.Job;
+import org.springframework.batch.core.JobExecution;
+import org.springframework.batch.core.JobParameters;
+import org.springframework.batch.core.JobParametersBuilder;
+import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
+import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
+import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
+import org.springframework.batch.core.launch.JobLauncher;
+import org.springframework.batch.repeat.RepeatStatus;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringRunner;
+
+/**
+ * @author Mahmoud Ben Hassine
+ */
+@RunWith(SpringRunner.class)
+@ContextConfiguration
+public class Db2JobRepositoryIntegrationTests {
+
+ // TODO find the best way to externalize and manage image versions
+ private static final DockerImageName DB2_IMAGE = DockerImageName.parse("ibmcom/db2:11.5.5.1");
+
+ @ClassRule
+ public static Db2Container db2 = new Db2Container(DB2_IMAGE).acceptLicense();
+
+ @Autowired
+ private DataSource dataSource;
+ @Autowired
+ private JobLauncher jobLauncher;
+ @Autowired
+ private Job job;
+
+ @Before
+ public void setUp() {
+ ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator();
+ databasePopulator.addScript(new ClassPathResource("/org/springframework/batch/core/schema-db2.sql"));
+ databasePopulator.execute(this.dataSource);
+ }
+
+ @Test
+ public void testJobExecution() throws Exception {
+ // given
+ JobParameters jobParameters = new JobParametersBuilder().toJobParameters();
+
+ // when
+ JobExecution jobExecution = this.jobLauncher.run(this.job, jobParameters);
+
+ // then
+ Assert.assertNotNull(jobExecution);
+ Assert.assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
+ }
+
+ @Configuration
+ @EnableBatchProcessing
+ static class TestConfiguration {
+
+ @Bean
+ public DataSource dataSource() throws Exception {
+ DB2SimpleDataSource dataSource =new DB2SimpleDataSource();
+ dataSource.setDatabaseName(db2.getDatabaseName());
+ dataSource.setUser(db2.getUsername());
+ dataSource.setPassword(db2.getPassword());
+ dataSource.setDriverType(4);
+ dataSource.setServerName(db2.getContainerIpAddress());
+ dataSource.setPortNumber(db2.getMappedPort(Db2Container.DB2_PORT));
+ dataSource.setSslConnection(false);
+ return dataSource;
+ }
+
+ @Bean
+ public Job job(JobBuilderFactory jobs, StepBuilderFactory steps) {
+ return jobs.get("job")
+ .start(steps.get("step")
+ .tasklet((contribution, chunkContext) -> RepeatStatus.FINISHED)
+ .build())
+ .build();
+ }
+
+ }
+}
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/test/repository/DerbyJobRepositoryIntegrationTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/test/repository/DerbyJobRepositoryIntegrationTests.java
new file mode 100644
index 000000000..feede6f27
--- /dev/null
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/test/repository/DerbyJobRepositoryIntegrationTests.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2020-2021 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
+ *
+ * https://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.test.repository;
+
+import javax.sql.DataSource;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.springframework.batch.core.ExitStatus;
+import org.springframework.batch.core.Job;
+import org.springframework.batch.core.JobExecution;
+import org.springframework.batch.core.JobParameters;
+import org.springframework.batch.core.JobParametersBuilder;
+import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
+import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
+import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
+import org.springframework.batch.core.launch.JobLauncher;
+import org.springframework.batch.repeat.RepeatStatus;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
+import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringRunner;
+
+/**
+ * @author Mahmoud Ben Hassine
+ */
+@RunWith(SpringRunner.class)
+@ContextConfiguration
+public class DerbyJobRepositoryIntegrationTests {
+
+ @Autowired
+ private JobLauncher jobLauncher;
+ @Autowired
+ private Job job;
+
+ @Test
+ public void testJobExecution() throws Exception {
+ // given
+ JobParameters jobParameters = new JobParametersBuilder().toJobParameters();
+
+ // when
+ JobExecution jobExecution = this.jobLauncher.run(this.job, jobParameters);
+
+ // then
+ Assert.assertNotNull(jobExecution);
+ Assert.assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
+ }
+
+ @Configuration
+ @EnableBatchProcessing
+ static class TestConfiguration {
+
+ @Bean
+ public DataSource dataSource() {
+ return new EmbeddedDatabaseBuilder()
+ .setType(EmbeddedDatabaseType.DERBY)
+ .addScript("/org/springframework/batch/core/schema-derby.sql")
+ .generateUniqueName(true)
+ .build();
+ }
+
+ @Bean
+ public Job job(JobBuilderFactory jobs, StepBuilderFactory steps) {
+ return jobs.get("job")
+ .start(steps.get("step")
+ .tasklet((contribution, chunkContext) -> RepeatStatus.FINISHED)
+ .build())
+ .build();
+ }
+
+ }
+}
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/test/repository/H2JobRepositoryIntegrationTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/test/repository/H2JobRepositoryIntegrationTests.java
new file mode 100644
index 000000000..cfac294fb
--- /dev/null
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/test/repository/H2JobRepositoryIntegrationTests.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2020-2021 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
+ *
+ * https://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.test.repository;
+
+import javax.sql.DataSource;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.springframework.batch.core.ExitStatus;
+import org.springframework.batch.core.Job;
+import org.springframework.batch.core.JobExecution;
+import org.springframework.batch.core.JobParameters;
+import org.springframework.batch.core.JobParametersBuilder;
+import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
+import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
+import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
+import org.springframework.batch.core.launch.JobLauncher;
+import org.springframework.batch.repeat.RepeatStatus;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
+import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringRunner;
+
+/**
+ * @author Mahmoud Ben Hassine
+ */
+@RunWith(SpringRunner.class)
+@ContextConfiguration
+public class H2JobRepositoryIntegrationTests {
+
+ @Autowired
+ private JobLauncher jobLauncher;
+ @Autowired
+ private Job job;
+
+ @Test
+ public void testJobExecution() throws Exception {
+ // given
+ JobParameters jobParameters = new JobParametersBuilder().toJobParameters();
+
+ // when
+ JobExecution jobExecution = this.jobLauncher.run(this.job, jobParameters);
+
+ // then
+ Assert.assertNotNull(jobExecution);
+ Assert.assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
+ }
+
+ @Configuration
+ @EnableBatchProcessing
+ static class TestConfiguration {
+
+ @Bean
+ public DataSource dataSource() {
+ return new EmbeddedDatabaseBuilder()
+ .setType(EmbeddedDatabaseType.H2)
+ .addScript("/org/springframework/batch/core/schema-h2.sql")
+ .generateUniqueName(true)
+ .build();
+ }
+
+ @Bean
+ public Job job(JobBuilderFactory jobs, StepBuilderFactory steps) {
+ return jobs.get("job")
+ .start(steps.get("step")
+ .tasklet((contribution, chunkContext) -> RepeatStatus.FINISHED)
+ .build())
+ .build();
+ }
+
+ }
+}
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/test/repository/HSQLDBJobRepositoryIntegrationTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/test/repository/HSQLDBJobRepositoryIntegrationTests.java
new file mode 100644
index 000000000..2c3e376b0
--- /dev/null
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/test/repository/HSQLDBJobRepositoryIntegrationTests.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2020-2021 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
+ *
+ * https://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.test.repository;
+
+import javax.sql.DataSource;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.springframework.batch.core.ExitStatus;
+import org.springframework.batch.core.Job;
+import org.springframework.batch.core.JobExecution;
+import org.springframework.batch.core.JobParameters;
+import org.springframework.batch.core.JobParametersBuilder;
+import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
+import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
+import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
+import org.springframework.batch.core.launch.JobLauncher;
+import org.springframework.batch.repeat.RepeatStatus;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
+import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringRunner;
+
+/**
+ * @author Mahmoud Ben Hassine
+ */
+@RunWith(SpringRunner.class)
+@ContextConfiguration
+public class HSQLDBJobRepositoryIntegrationTests {
+
+ @Autowired
+ private JobLauncher jobLauncher;
+ @Autowired
+ private Job job;
+
+ @Test
+ public void testJobExecution() throws Exception {
+ // given
+ JobParameters jobParameters = new JobParametersBuilder().toJobParameters();
+
+ // when
+ JobExecution jobExecution = this.jobLauncher.run(this.job, jobParameters);
+
+ // then
+ Assert.assertNotNull(jobExecution);
+ Assert.assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
+ }
+
+ @Configuration
+ @EnableBatchProcessing
+ static class TestConfiguration {
+
+ @Bean
+ public DataSource dataSource() {
+ return new EmbeddedDatabaseBuilder()
+ .setType(EmbeddedDatabaseType.HSQL)
+ .addScript("/org/springframework/batch/core/schema-hsqldb.sql")
+ .generateUniqueName(true)
+ .build();
+ }
+
+ @Bean
+ public Job job(JobBuilderFactory jobs, StepBuilderFactory steps) {
+ return jobs.get("job")
+ .start(steps.get("step")
+ .tasklet((contribution, chunkContext) -> RepeatStatus.FINISHED)
+ .build())
+ .build();
+ }
+
+ }
+}
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/test/repository/MySQLJobRepositoryIntegrationTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/test/repository/MySQLJobRepositoryIntegrationTests.java
new file mode 100644
index 000000000..c1b687b43
--- /dev/null
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/test/repository/MySQLJobRepositoryIntegrationTests.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2020-2021 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
+ *
+ * https://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.test.repository;
+
+import javax.sql.DataSource;
+
+import com.mysql.cj.jdbc.MysqlDataSource;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.testcontainers.containers.MySQLContainer;
+import org.testcontainers.utility.DockerImageName;
+
+import org.springframework.batch.core.ExitStatus;
+import org.springframework.batch.core.Job;
+import org.springframework.batch.core.JobExecution;
+import org.springframework.batch.core.JobParameters;
+import org.springframework.batch.core.JobParametersBuilder;
+import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
+import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
+import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
+import org.springframework.batch.core.launch.JobLauncher;
+import org.springframework.batch.repeat.RepeatStatus;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringRunner;
+
+/**
+ * @author Mahmoud Ben Hassine
+ */
+@RunWith(SpringRunner.class)
+@ContextConfiguration
+public class MySQLJobRepositoryIntegrationTests {
+
+ // TODO find the best way to externalize and manage image versions
+ private static final DockerImageName MYSQL_IMAGE = DockerImageName.parse("mysql:8.0.25");
+
+ @ClassRule
+ public static MySQLContainer> mysql = new MySQLContainer<>(MYSQL_IMAGE);
+
+ @Autowired
+ private DataSource dataSource;
+ @Autowired
+ private JobLauncher jobLauncher;
+ @Autowired
+ private Job job;
+
+ @Before
+ public void setUp() {
+ ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator();
+ databasePopulator.addScript(new ClassPathResource("/org/springframework/batch/core/schema-mysql.sql"));
+ databasePopulator.execute(this.dataSource);
+ }
+
+ @Test
+ public void testJobExecution() throws Exception {
+ // given
+ JobParameters jobParameters = new JobParametersBuilder().toJobParameters();
+
+ // when
+ JobExecution jobExecution = this.jobLauncher.run(this.job, jobParameters);
+
+ // then
+ Assert.assertNotNull(jobExecution);
+ Assert.assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
+ }
+
+ @Configuration
+ @EnableBatchProcessing
+ static class TestConfiguration {
+
+ @Bean
+ public DataSource dataSource() throws Exception {
+ MysqlDataSource datasource = new MysqlDataSource();
+ datasource.setURL(mysql.getJdbcUrl());
+ datasource.setUser(mysql.getUsername());
+ datasource.setPassword(mysql.getPassword());
+ datasource.setUseSSL(false);
+ return datasource;
+ }
+
+ @Bean
+ public Job job(JobBuilderFactory jobs, StepBuilderFactory steps) {
+ return jobs.get("job")
+ .start(steps.get("step")
+ .tasklet((contribution, chunkContext) -> RepeatStatus.FINISHED)
+ .build())
+ .build();
+ }
+
+ }
+}
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/test/repository/OracleJobRepositoryIntegrationTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/test/repository/OracleJobRepositoryIntegrationTests.java
new file mode 100644
index 000000000..09e3cfc94
--- /dev/null
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/test/repository/OracleJobRepositoryIntegrationTests.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2020-2021 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
+ *
+ * https://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.test.repository;
+
+import javax.sql.DataSource;
+
+import oracle.jdbc.pool.OracleDataSource;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.testcontainers.containers.OracleContainer;
+import org.testcontainers.utility.DockerImageName;
+
+import org.springframework.batch.core.ExitStatus;
+import org.springframework.batch.core.Job;
+import org.springframework.batch.core.JobExecution;
+import org.springframework.batch.core.JobParameters;
+import org.springframework.batch.core.JobParametersBuilder;
+import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
+import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
+import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
+import org.springframework.batch.core.launch.JobLauncher;
+import org.springframework.batch.repeat.RepeatStatus;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringRunner;
+
+/**
+ * Official Docker images for Oracle are not publicly available. Oracle support is tested semi-manually for the moment:
+ * 1. Build a docker image for oracle/database:11.2.0.2-xe: https://github.com/oracle/docker-images/tree/main/OracleDatabase/SingleInstance#running-oracle-database-11gr2-express-edition-in-a-container
+ * 2. Run the test `testJobExecution`
+ *
+ * @author Mahmoud Ben Hassine
+ */
+@RunWith(SpringRunner.class)
+@ContextConfiguration
+@Ignore("Official Docker images for Oracle are not publicly available")
+public class OracleJobRepositoryIntegrationTests {
+
+ // TODO find the best way to externalize and manage image versions
+ private static final DockerImageName ORACLE_IMAGE = DockerImageName.parse("oracle/database:11.2.0.2-xe");
+
+ @ClassRule
+ public static OracleContainer oracle = new OracleContainer(ORACLE_IMAGE);
+
+ @Autowired
+ private DataSource dataSource;
+ @Autowired
+ private JobLauncher jobLauncher;
+ @Autowired
+ private Job job;
+
+ @Before
+ public void setUp() {
+ ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator();
+ databasePopulator.addScript(new ClassPathResource("/org/springframework/batch/core/schema-oracle10g.sql"));
+ databasePopulator.execute(this.dataSource);
+ }
+
+ @Test
+ public void testJobExecution() throws Exception {
+ // given
+ JobParameters jobParameters = new JobParametersBuilder().toJobParameters();
+
+ // when
+ JobExecution jobExecution = this.jobLauncher.run(this.job, jobParameters);
+
+ // then
+ Assert.assertNotNull(jobExecution);
+ Assert.assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
+ }
+
+ @Configuration
+ @EnableBatchProcessing
+ static class TestConfiguration {
+
+ @Bean
+ public DataSource dataSource() throws Exception {
+ OracleDataSource oracleDataSource = new OracleDataSource();
+ oracleDataSource.setUser(oracle.getUsername());
+ oracleDataSource.setPassword(oracle.getPassword());
+ oracleDataSource.setDatabaseName(oracle.getDatabaseName());
+ oracleDataSource.setServerName(oracle.getContainerIpAddress());
+ oracleDataSource.setPortNumber(oracle.getOraclePort());
+ return oracleDataSource;
+ }
+
+ @Bean
+ public Job job(JobBuilderFactory jobs, StepBuilderFactory steps) {
+ return jobs.get("job")
+ .start(steps.get("step")
+ .tasklet((contribution, chunkContext) -> RepeatStatus.FINISHED)
+ .build())
+ .build();
+ }
+
+ }
+}
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/test/repository/PostgreSQLJobRepositoryIntegrationTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/test/repository/PostgreSQLJobRepositoryIntegrationTests.java
new file mode 100644
index 000000000..e2c5f0ff8
--- /dev/null
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/test/repository/PostgreSQLJobRepositoryIntegrationTests.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2020-2021 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
+ *
+ * https://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.test.repository;
+
+import javax.sql.DataSource;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.postgresql.ds.PGSimpleDataSource;
+import org.testcontainers.containers.PostgreSQLContainer;
+import org.testcontainers.utility.DockerImageName;
+
+import org.springframework.batch.core.ExitStatus;
+import org.springframework.batch.core.Job;
+import org.springframework.batch.core.JobExecution;
+import org.springframework.batch.core.JobParameters;
+import org.springframework.batch.core.JobParametersBuilder;
+import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
+import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
+import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
+import org.springframework.batch.core.launch.JobLauncher;
+import org.springframework.batch.repeat.RepeatStatus;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringRunner;
+
+/**
+ * @author Mahmoud Ben Hassine
+ */
+@RunWith(SpringRunner.class)
+@ContextConfiguration
+public class PostgreSQLJobRepositoryIntegrationTests {
+
+ // TODO find the best way to externalize and manage image versions
+ private static final DockerImageName POSTGRESQL_IMAGE = DockerImageName.parse("postgres:13.3");
+
+ @ClassRule
+ public static PostgreSQLContainer> postgres = new PostgreSQLContainer<>(POSTGRESQL_IMAGE);
+
+ @Autowired
+ private DataSource dataSource;
+ @Autowired
+ private JobLauncher jobLauncher;
+ @Autowired
+ private Job job;
+
+ @Before
+ public void setUp() {
+ ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator();
+ databasePopulator.addScript(new ClassPathResource("/org/springframework/batch/core/schema-postgresql.sql"));
+ databasePopulator.execute(this.dataSource);
+ }
+
+ @Test
+ public void testJobExecution() throws Exception {
+ // given
+ JobParameters jobParameters = new JobParametersBuilder().toJobParameters();
+
+ // when
+ JobExecution jobExecution = this.jobLauncher.run(this.job, jobParameters);
+
+ // then
+ Assert.assertNotNull(jobExecution);
+ Assert.assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
+ }
+
+ @Configuration
+ @EnableBatchProcessing
+ static class TestConfiguration {
+
+ @Bean
+ public DataSource dataSource() throws Exception {
+ PGSimpleDataSource datasource = new PGSimpleDataSource();
+ datasource.setURL(postgres.getJdbcUrl());
+ datasource.setUser(postgres.getUsername());
+ datasource.setPassword(postgres.getPassword());
+ return datasource;
+ }
+
+ @Bean
+ public Job job(JobBuilderFactory jobs, StepBuilderFactory steps) {
+ return jobs.get("job")
+ .start(steps.get("step")
+ .tasklet((contribution, chunkContext) -> RepeatStatus.FINISHED)
+ .build())
+ .build();
+ }
+
+ }
+}
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/test/repository/SQLServerJobRepositoryIntegrationTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/test/repository/SQLServerJobRepositoryIntegrationTests.java
new file mode 100644
index 000000000..37800699d
--- /dev/null
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/test/repository/SQLServerJobRepositoryIntegrationTests.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2020-2021 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
+ *
+ * https://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.test.repository;
+
+import javax.sql.DataSource;
+
+import com.microsoft.sqlserver.jdbc.SQLServerDataSource;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.testcontainers.containers.MSSQLServerContainer;
+import org.testcontainers.utility.DockerImageName;
+
+import org.springframework.batch.core.ExitStatus;
+import org.springframework.batch.core.Job;
+import org.springframework.batch.core.JobExecution;
+import org.springframework.batch.core.JobParameters;
+import org.springframework.batch.core.JobParametersBuilder;
+import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
+import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
+import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
+import org.springframework.batch.core.launch.JobLauncher;
+import org.springframework.batch.repeat.RepeatStatus;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringRunner;
+
+/**
+ * @author Mahmoud Ben Hassine
+ */
+@RunWith(SpringRunner.class)
+@ContextConfiguration
+public class SQLServerJobRepositoryIntegrationTests {
+
+ // TODO find the best way to externalize and manage image versions
+ private static final DockerImageName SQLSERVER_IMAGE = DockerImageName.parse("mcr.microsoft.com/mssql/server:2019-CU11-ubuntu-20.04");
+
+ @ClassRule
+ public static MSSQLServerContainer> sqlserver = new MSSQLServerContainer<>(SQLSERVER_IMAGE).acceptLicense();
+
+ @Autowired
+ private DataSource dataSource;
+ @Autowired
+ private JobLauncher jobLauncher;
+ @Autowired
+ private Job job;
+
+ @Before
+ public void setUp() {
+ ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator();
+ databasePopulator.addScript(new ClassPathResource("/org/springframework/batch/core/schema-sqlserver.sql"));
+ databasePopulator.execute(this.dataSource);
+ }
+
+ @Test
+ public void testJobExecution() throws Exception {
+ // given
+ JobParameters jobParameters = new JobParametersBuilder().toJobParameters();
+
+ // when
+ JobExecution jobExecution = this.jobLauncher.run(this.job, jobParameters);
+
+ // then
+ Assert.assertNotNull(jobExecution);
+ Assert.assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
+ }
+
+ @Configuration
+ @EnableBatchProcessing
+ static class TestConfiguration {
+
+ @Bean
+ public DataSource dataSource() throws Exception {
+ SQLServerDataSource dataSource = new SQLServerDataSource();
+ dataSource.setUser(sqlserver.getUsername());
+ dataSource.setPassword(sqlserver.getPassword());
+ dataSource.setURL(sqlserver.getJdbcUrl());
+ return dataSource;
+ }
+
+ @Bean
+ public Job job(JobBuilderFactory jobs, StepBuilderFactory steps) {
+ return jobs.get("job")
+ .start(steps.get("step")
+ .tasklet((contribution, chunkContext) -> RepeatStatus.FINISHED)
+ .build())
+ .build();
+ }
+
+ }
+}
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/test/repository/SQLiteJobRepositoryIntegrationTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/test/repository/SQLiteJobRepositoryIntegrationTests.java
new file mode 100644
index 000000000..775f53461
--- /dev/null
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/test/repository/SQLiteJobRepositoryIntegrationTests.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2020-2021 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
+ *
+ * https://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.test.repository;
+
+import javax.sql.DataSource;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.sqlite.SQLiteDataSource;
+
+import org.springframework.batch.core.ExitStatus;
+import org.springframework.batch.core.Job;
+import org.springframework.batch.core.JobExecution;
+import org.springframework.batch.core.JobParameters;
+import org.springframework.batch.core.JobParametersBuilder;
+import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
+import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
+import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
+import org.springframework.batch.core.launch.JobLauncher;
+import org.springframework.batch.repeat.RepeatStatus;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringRunner;
+
+/**
+ * @author Mahmoud Ben Hassine
+ */
+@RunWith(SpringRunner.class)
+@ContextConfiguration
+public class SQLiteJobRepositoryIntegrationTests {
+
+ @Autowired
+ private JobLauncher jobLauncher;
+ @Autowired
+ private Job job;
+
+ @Test
+ public void testJobExecution() throws Exception {
+ // given
+ JobParameters jobParameters = new JobParametersBuilder().toJobParameters();
+
+ // when
+ JobExecution jobExecution = this.jobLauncher.run(this.job, jobParameters);
+
+ // then
+ Assert.assertNotNull(jobExecution);
+ Assert.assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
+ }
+
+ @Configuration
+ @EnableBatchProcessing
+ static class TestConfiguration {
+
+ @Bean
+ public DataSource dataSource() {
+ SQLiteDataSource dataSource = new SQLiteDataSource();
+ dataSource.setUrl("jdbc:sqlite:target/spring-batch.sqlite");
+ ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator();
+ databasePopulator.addScript(new ClassPathResource("/org/springframework/batch/core/schema-sqlite.sql"));
+ databasePopulator.execute(dataSource);
+ return dataSource;
+ }
+
+ @Bean
+ public Job job(JobBuilderFactory jobs, StepBuilderFactory steps) {
+ return jobs.get("job")
+ .start(steps.get("step")
+ .tasklet((contribution, chunkContext) -> RepeatStatus.FINISHED)
+ .build())
+ .build();
+ }
+
+ }
+}
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/test/repository/SybaseJobRepositoryIntegrationTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/test/repository/SybaseJobRepositoryIntegrationTests.java
new file mode 100644
index 000000000..1839e6bfc
--- /dev/null
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/test/repository/SybaseJobRepositoryIntegrationTests.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2020-2021 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
+ *
+ * https://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.test.repository;
+
+import javax.sql.DataSource;
+
+import net.sourceforge.jtds.jdbcx.JtdsDataSource;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.springframework.batch.core.ExitStatus;
+import org.springframework.batch.core.Job;
+import org.springframework.batch.core.JobExecution;
+import org.springframework.batch.core.JobParameters;
+import org.springframework.batch.core.JobParametersBuilder;
+import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
+import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
+import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
+import org.springframework.batch.core.launch.JobLauncher;
+import org.springframework.batch.repeat.RepeatStatus;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringRunner;
+
+/**
+ * The Sybase official jdbc driver is not freely available. This test uses the non-official jTDS driver.
+ * There is no official public Docker image for Sybase neither. This test uses the non-official Docker image by Jetbrains.
+ * Sybase in not supported in testcontainers. Sysbase support is tested manually for the moment:
+ * 1. Run `docker run -d -t -p 5000:5000 -eSYBASE_USER=sa -eSYBASE_PASSWORD=sa -eSYBASE_DB=test datagrip/sybase:16.0`
+ * 2. Update the datasource configuration with the IP of the container
+ * 3. Run the test `testJobExecution`
+ *
+ * @author Mahmoud Ben Hassine
+ */
+@RunWith(SpringRunner.class)
+@ContextConfiguration
+@Ignore("No support for Sybase in testcontainers")
+public class SybaseJobRepositoryIntegrationTests {
+
+ @Autowired
+ private DataSource dataSource;
+ @Autowired
+ private JobLauncher jobLauncher;
+ @Autowired
+ private Job job;
+
+ @Before
+ public void setUp() {
+ ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator();
+ databasePopulator.addScript(new ClassPathResource("/org/springframework/batch/core/schema-sybase.sql"));
+ databasePopulator.execute(this.dataSource);
+ }
+
+ @Test
+ public void testJobExecution() throws Exception {
+ // given
+ JobParameters jobParameters = new JobParametersBuilder().toJobParameters();
+
+ // when
+ JobExecution jobExecution = this.jobLauncher.run(this.job, jobParameters);
+
+ // then
+ Assert.assertNotNull(jobExecution);
+ Assert.assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
+ }
+
+ @Configuration
+ @EnableBatchProcessing
+ static class TestConfiguration {
+
+ // FIXME Configuration parameters are hard-coded for the moment, to update once testcontainers support is available
+ @Bean
+ public DataSource dataSource() throws Exception {
+ JtdsDataSource dataSource = new JtdsDataSource();
+ dataSource.setUser("sa");
+ dataSource.setPassword("sa");
+ dataSource.setServerName("172.17.0.2");
+ dataSource.setPortNumber(5000);
+ dataSource.setDatabaseName("test");
+ return dataSource;
+ }
+
+ @Bean
+ public Job job(JobBuilderFactory jobs, StepBuilderFactory steps) {
+ return jobs.get("job")
+ .start(steps.get("step")
+ .tasklet((contribution, chunkContext) -> RepeatStatus.FINISHED)
+ .build())
+ .build();
+ }
+
+ }
+}