Remove datasource dependency in JobRepositoryTestUtils

Before this commit, the `JobRepositoryTestUtils` was
tied to the JDBC implementation of the `JobRepository`
as it was requiring a datasource. This makes it unusable
with implementations that do not rely on a datasource
to store batch meta-data (A MongoDB job repository for
instance where no datasource is used).

This commit decouples the `JobRepositoryTestUtils` from
the implementation details of the `JobRepository` by making
it working against the `JobRepository` interface.

This commit also introduces the necessary methods in the
`JobRepository` interface as well as various DAOs to
implement the utilities without having to deal with the
details of the underlying repository implementation.

Resolves #4070
This commit is contained in:
Mahmoud Ben Hassine
2022-08-23 21:16:50 +02:00
parent f104baa417
commit c425137eec
19 changed files with 354 additions and 96 deletions

View File

@@ -68,10 +68,6 @@ public class JobRepositoryTestUtils {
};
private JdbcOperations jdbcTemplate;
private String tablePrefix = AbstractJdbcBatchMetadataDao.DEFAULT_TABLE_PREFIX;
/**
* Default constructor.
*/
@@ -80,16 +76,10 @@ public class JobRepositoryTestUtils {
/**
* Create a {@link JobRepositoryTestUtils} with all its mandatory properties.
* @param jobRepository a {@link JobRepository} backed by a database
* @param dataSource a {@link DataSource}
* @param jobRepository a {@link JobRepository}.
*/
public JobRepositoryTestUtils(JobRepository jobRepository, DataSource dataSource) {
public JobRepositoryTestUtils(JobRepository jobRepository) {
this.jobRepository = jobRepository;
setDataSource(dataSource);
}
public final void setDataSource(DataSource dataSource) {
jdbcTemplate = new JdbcTemplate(dataSource);
}
/**
@@ -99,15 +89,6 @@ public class JobRepositoryTestUtils {
this.jobParametersIncrementer = jobParametersIncrementer;
}
/**
* Set the prefix of batch tables.
* @param tablePrefix of batch tables
* @since 5.0
*/
public void setTablePrefix(String tablePrefix) {
this.tablePrefix = tablePrefix;
}
/**
* @param jobRepository the jobRepository to set
*/
@@ -160,58 +141,53 @@ public class JobRepositoryTestUtils {
/**
* Remove the {@link JobExecution} instances, and all associated {@link JobInstance}
* and {@link StepExecution} instances from the standard RDBMS locations used by
* Spring Batch.
* @param list a list of {@link JobExecution}
* @throws DataAccessException if there is a problem
* and {@link StepExecution} instances from the standard locations used by Spring
* Batch.
* @param jobExecutions a collection of {@link JobExecution}
*/
public void removeJobExecutions(Collection<JobExecution> list) throws DataAccessException {
for (JobExecution jobExecution : list) {
List<Long> stepExecutionIds = jdbcTemplate.query(
getQuery("select STEP_EXECUTION_ID from %PREFIX%STEP_EXECUTION where JOB_EXECUTION_ID=?"),
new RowMapper<Long>() {
@Override
public Long mapRow(ResultSet rs, int rowNum) throws SQLException {
return rs.getLong(1);
}
}, jobExecution.getId());
for (Long stepExecutionId : stepExecutionIds) {
jdbcTemplate.update(getQuery("delete from %PREFIX%STEP_EXECUTION_CONTEXT where STEP_EXECUTION_ID=?"),
stepExecutionId);
jdbcTemplate.update(getQuery("delete from %PREFIX%STEP_EXECUTION where STEP_EXECUTION_ID=?"),
stepExecutionId);
}
jdbcTemplate.update(getQuery("delete from %PREFIX%JOB_EXECUTION_CONTEXT where JOB_EXECUTION_ID=?"),
jobExecution.getId());
jdbcTemplate.update(getQuery("delete from %PREFIX%JOB_EXECUTION_PARAMS where JOB_EXECUTION_ID=?"),
jobExecution.getId());
jdbcTemplate.update(getQuery("delete from %PREFIX%JOB_EXECUTION where JOB_EXECUTION_ID=?"),
jobExecution.getId());
public void removeJobExecutions(Collection<JobExecution> jobExecutions) {
for (JobExecution jobExecution : jobExecutions) {
removeJobExecution(jobExecution);
}
for (JobExecution jobExecution : list) {
jdbcTemplate.update(getQuery("delete from %PREFIX%JOB_INSTANCE where JOB_INSTANCE_ID=?"),
jobExecution.getJobId());
for (JobExecution jobExecution : jobExecutions) {
this.jobRepository.deleteJobInstance(jobExecution.getJobInstance());
}
}
/**
* Remove all the {@link JobExecution} instances, and all associated
* {@link JobInstance} and {@link StepExecution} instances from the standard RDBMS
* locations used by Spring Batch.
* @throws DataAccessException if there is a problem
* Remove the {@link JobExecution} and its associated {@link StepExecution} instances
* Ôfrom the standard locations used by Spring Batch.
* @param jobExecution the {@link JobExecution} to delete
*/
public void removeJobExecutions() throws DataAccessException {
jdbcTemplate.update(getQuery("delete from %PREFIX%STEP_EXECUTION_CONTEXT"));
jdbcTemplate.update(getQuery("delete from %PREFIX%STEP_EXECUTION"));
jdbcTemplate.update(getQuery("delete from %PREFIX%JOB_EXECUTION_CONTEXT"));
jdbcTemplate.update(getQuery("delete from %PREFIX%JOB_EXECUTION_PARAMS"));
jdbcTemplate.update(getQuery("delete from %PREFIX%JOB_EXECUTION"));
jdbcTemplate.update(getQuery("delete from %PREFIX%JOB_INSTANCE"));
public void removeJobExecution(JobExecution jobExecution) {
for (StepExecution stepExecution : jobExecution.getStepExecutions()) {
this.jobRepository.deleteStepExecution(stepExecution);
}
this.jobRepository.deleteJobExecution(jobExecution);
}
private String getQuery(String base) {
return StringUtils.replace(base, "%PREFIX%", this.tablePrefix);
/**
* Remove all the {@link JobExecution} instances, and all associated
* {@link JobInstance} and {@link StepExecution} instances from the standard locations
* used by Spring Batch.
*/
public void removeJobExecutions() {
List<String> jobNames = this.jobRepository.getJobNames();
for (String jobName : jobNames) {
int start = 0;
int count = 100;
List<JobInstance> jobInstances = this.jobRepository.findJobInstancesByName(jobName, start, count);
while (!jobInstances.isEmpty()) {
for (JobInstance jobInstance : jobInstances) {
List<JobExecution> jobExecutions = this.jobRepository.findJobExecutions(jobInstance);
if (jobExecutions != null && !jobExecutions.isEmpty()) {
removeJobExecutions(jobExecutions);
}
}
start += count;
jobInstances = this.jobRepository.findJobInstancesByName(jobName, start, count);
}
}
}
}

View File

@@ -63,12 +63,8 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
* &#064;Autowired
* private Job jobUnderTest;
*
* &#064;Autowired
* private DataSource testDatabase;
*
* &#064;Before
* public void setup() {
* this.jobRepositoryTestUtils.setDataSource(this.testDatabase);
* this.jobRepositoryTestUtils.removeJobExecutions();
* this.jobLauncherTestUtils.setJob(this.jobUnderTest);
* }
@@ -104,9 +100,8 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
* private JobRepositoryTestUtils jobRepositoryTestUtils;
*
* &#064;BeforeEach
* public void setup(@Autowired Job jobUnderTest, @Autowired DataSource testDatabase) {
* public void setup(@Autowired Job jobUnderTest) {
* this.jobLauncherTestUtils.setJob(jobUnderTest);
* this.jobRepositoryTestUtils.setDataSource(testDatabase);
* this.jobRepositoryTestUtils.removeJobExecutions();
* }
*
@@ -125,15 +120,6 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
* }
* </pre>
*
* <p>
* <strong> It should be noted that {@link JobRepositoryTestUtils} requires a
* {@link javax.sql.DataSource} bean. Since this annotation registers a
* {@link JobRepositoryTestUtils} in the test context, it is expected that the test
* context contains a single autowire candidate for a {@link javax.sql.DataSource} (either
* a single bean definition or one that is annotated with
* {@link org.springframework.context.annotation.Primary}). </strong>
* </p>
*
* @author Mahmoud Ben Hassine
* @since 4.1
* @see JobLauncherTestUtils

View File

@@ -68,7 +68,7 @@ class JobRepositoryTestUtilsTests {
@Test
void testCreateJobExecutions() throws Exception {
utils = new JobRepositoryTestUtils(jobRepository, dataSource);
utils = new JobRepositoryTestUtils(jobRepository);
List<JobExecution> list = utils.createJobExecutions(3);
assertEquals(3, list.size());
assertEquals(beforeJobs + 3, JdbcTestUtils.countRowsInTable(jdbcTemplate, "BATCH_JOB_EXECUTION"));
@@ -80,7 +80,7 @@ class JobRepositoryTestUtilsTests {
@Test
void testRemoveJobExecutionsWithSameJobInstance() throws Exception {
utils = new JobRepositoryTestUtils(jobRepository, dataSource);
utils = new JobRepositoryTestUtils(jobRepository);
List<JobExecution> list = new ArrayList<>();
JobExecution jobExecution = jobRepository.createJobExecution("job", new JobParameters());
jobExecution.setEndTime(new Date());
@@ -95,7 +95,7 @@ class JobRepositoryTestUtilsTests {
@Test
void testCreateJobExecutionsByName() throws Exception {
utils = new JobRepositoryTestUtils(jobRepository, dataSource);
utils = new JobRepositoryTestUtils(jobRepository);
List<JobExecution> list = utils.createJobExecutions("foo", new String[] { "bar", "spam" }, 3);
assertEquals(3, list.size());
assertEquals(beforeJobs + 3, JdbcTestUtils.countRowsInTable(jdbcTemplate, "BATCH_JOB_EXECUTION"));
@@ -107,7 +107,7 @@ class JobRepositoryTestUtilsTests {
@Test
void testRemoveJobExecutionsIncrementally() throws Exception {
utils = new JobRepositoryTestUtils(jobRepository, dataSource);
utils = new JobRepositoryTestUtils(jobRepository);
List<JobExecution> list1 = utils.createJobExecutions(3);
List<JobExecution> list2 = utils.createJobExecutions(2);
assertEquals(beforeJobs + 5, JdbcTestUtils.countRowsInTable(jdbcTemplate, "BATCH_JOB_EXECUTION"));
@@ -119,7 +119,7 @@ class JobRepositoryTestUtilsTests {
@Test
void testCreateJobExecutionsWithIncrementer() throws Exception {
utils = new JobRepositoryTestUtils(jobRepository, dataSource);
utils = new JobRepositoryTestUtils(jobRepository);
utils.setJobParametersIncrementer(new JobParametersIncrementer() {
@Override
public JobParameters getNext(@Nullable JobParameters parameters) {

View File

@@ -70,12 +70,8 @@ public class SpringBatchTestJUnit4Tests {
@Autowired
private Job jobUnderTest;
@Autowired
private DataSource testDatabase;
@Before
public void setUp() {
this.jobRepositoryTestUtils.setDataSource(this.testDatabase);
this.jobRepositoryTestUtils.removeJobExecutions();
}

View File

@@ -70,9 +70,8 @@ public class SpringBatchTestJUnit5Tests {
private ItemReader<String> jobScopedItemReader;
@BeforeEach
void setup(@Autowired Job jobUnderTest, @Autowired DataSource testDatabase) {
void setup(@Autowired Job jobUnderTest) {
this.jobLauncherTestUtils.setJob(jobUnderTest);
this.jobRepositoryTestUtils.setDataSource(testDatabase);
this.jobRepositoryTestUtils.removeJobExecutions();
}