From c425137eec91211f135f488cae470649c7786f55 Mon Sep 17 00:00:00 2001 From: Mahmoud Ben Hassine Date: Tue, 23 Aug 2022 21:16:50 +0200 Subject: [PATCH] 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 --- .../batch/core/repository/JobRepository.java | 68 +++++++++++- .../repository/dao/ExecutionContextDao.java | 21 +++- .../dao/JdbcExecutionContextDao.java | 22 ++++ .../repository/dao/JdbcJobExecutionDao.java | 22 +++- .../repository/dao/JdbcJobInstanceDao.java | 12 +- .../repository/dao/JdbcStepExecutionDao.java | 11 ++ .../core/repository/dao/JobExecutionDao.java | 21 +++- .../core/repository/dao/JobInstanceDao.java | 11 +- .../core/repository/dao/StepExecutionDao.java | 9 ++ .../support/SimpleJobRepository.java | 18 +++ .../dao/AbstractExecutionContextDaoTests.java | 37 +++++++ .../dao/JdbcJobExecutionDaoTests.java | 33 ++++++ .../dao/JdbcJobInstanceDaoTests.java | 14 +++ .../dao/JdbcStepExecutionDaoTests.java | 14 +++ .../batch/test/JobRepositoryTestUtils.java | 104 +++++++----------- .../batch/test/context/SpringBatchTest.java | 16 +-- .../test/JobRepositoryTestUtilsTests.java | 10 +- .../test/SpringBatchTestJUnit4Tests.java | 4 - .../test/SpringBatchTestJUnit5Tests.java | 3 +- 19 files changed, 354 insertions(+), 96 deletions(-) diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/JobRepository.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/JobRepository.java index 8174ced46e..6242116f9b 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/JobRepository.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/JobRepository.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2021 the original author or authors. + * Copyright 2006-2022 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. @@ -29,6 +29,8 @@ import org.springframework.transaction.annotation.Isolation; import java.util.Collection; +import java.util.Collections; +import java.util.List; /** *

@@ -47,6 +49,41 @@ */ public interface JobRepository { + /** + * Retrieve the names of all job instances sorted alphabetically - i.e. jobs that have + * ever been executed. + * @return the names of all job instances + * @since 5.0 + */ + default List getJobNames() { + return Collections.emptyList(); + } + + /** + * Fetch the last job instances with the provided name, sorted backwards by primary + * key, using a 'like' criteria + * @param jobName {@link String} containing the name of the job. + * @param start int containing the offset of where list of job instances results + * should begin. + * @param count int containing the number of job instances to return. + * @return a list of {@link JobInstance} for the job name requested. + * @since 5.0 + */ + default List findJobInstancesByName(String jobName, int start, int count) { + return Collections.emptyList(); + } + + /** + * Return all {@link JobExecution}s for given {@link JobInstance}, sorted backwards by + * creation order (so the first element is the most recent). + * @param jobInstance parent {@link JobInstance} of the {@link JobExecution}s to find. + * @return {@link List} containing JobExecutions for the jobInstance. + * @since 5.0 + */ + default List findJobExecutions(JobInstance jobInstance) { + return Collections.emptyList(); + } + /** * Check if an instance of this job already exists with the parameters provided. * @param jobName the name of the job @@ -172,4 +209,33 @@ JobExecution createJobExecution(String jobName, JobParameters jobParameters) @Nullable JobExecution getLastJobExecution(String jobName, JobParameters jobParameters); + /** + * Delete the step execution along with its execution context. + * @param stepExecution the step execution to delete + * @since 5.0 + */ + default void deleteStepExecution(StepExecution stepExecution) { + throw new UnsupportedOperationException(); + } + + /** + * Delete the job execution object graph (ie the job execution with its execution + * context, all related step executions and their executions contexts, as well as + * associated job parameters) + * @param jobExecution the job execution to delete + * @since 5.0 + */ + default void deleteJobExecution(JobExecution jobExecution) { + throw new UnsupportedOperationException(); + } + + /** + * Delete the job instance. + * @param jobInstance the job instance to delete + * @since 5.0 + */ + default void deleteJobInstance(JobInstance jobInstance) { + throw new UnsupportedOperationException(); + } + } diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/ExecutionContextDao.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/ExecutionContextDao.java index 9a086cbc2e..c27b7b264f 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/ExecutionContextDao.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/ExecutionContextDao.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2013 the original author or authors. + * Copyright 2006-2022 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. @@ -27,6 +27,7 @@ * * @author Robert Kasanicky * @author David Turanski + * @author Mahmoud Ben Hassine */ public interface ExecutionContextDao { @@ -78,4 +79,22 @@ public interface ExecutionContextDao { */ void updateExecutionContext(final StepExecution stepExecution); + /** + * Delete the execution context of the given {@link JobExecution}. + * @param jobExecution {@link JobExecution} that contains the context to delete. + * @since 5.0 + */ + default void deleteExecutionContext(JobExecution jobExecution) { + throw new UnsupportedOperationException(); + } + + /** + * Delete the execution context of the given {@link StepExecution}. + * @param stepExecution {@link StepExecution} that contains the context to delete. + * @since 5.0 + */ + default void deleteExecutionContext(StepExecution stepExecution) { + throw new UnsupportedOperationException(); + } + } diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcExecutionContextDao.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcExecutionContextDao.java index f9c05997a5..3e858e4b0d 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcExecutionContextDao.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcExecutionContextDao.java @@ -77,6 +77,12 @@ public class JdbcExecutionContextDao extends AbstractJdbcBatchMetadataDao implem private static final String UPDATE_STEP_EXECUTION_CONTEXT = "UPDATE %PREFIX%STEP_EXECUTION_CONTEXT " + "SET SHORT_CONTEXT = ?, SERIALIZED_CONTEXT = ? " + "WHERE STEP_EXECUTION_ID = ?"; + private static final String DELETE_STEP_EXECUTION_CONTEXT = "DELETE FROM %PREFIX%STEP_EXECUTION_CONTEXT " + + "WHERE STEP_EXECUTION_ID = ?"; + + private static final String DELETE_JOB_EXECUTION_CONTEXT = "DELETE FROM %PREFIX%JOB_EXECUTION_CONTEXT " + + "WHERE JOB_EXECUTION_ID = ?"; + private Charset charset = StandardCharsets.UTF_8; private static final int DEFAULT_MAX_VARCHAR_LENGTH = 2500; @@ -217,6 +223,22 @@ public void saveExecutionContexts(Collection stepExecutions) { persistSerializedContexts(serializedContexts, INSERT_STEP_EXECUTION_CONTEXT); } + /** + * Delete the execution context of the given {@link JobExecution}. + * @param jobExecution {@link JobExecution} that contains the context to delete. + */ + public void deleteExecutionContext(JobExecution jobExecution) { + getJdbcTemplate().update(getQuery(DELETE_JOB_EXECUTION_CONTEXT), jobExecution.getId()); + } + + /** + * Delete the execution context of the given {@link StepExecution}. + * @param stepExecution {@link StepExecution} that contains the context to delete. + */ + public void deleteExecutionContext(StepExecution stepExecution) { + getJdbcTemplate().update(getQuery(DELETE_STEP_EXECUTION_CONTEXT), stepExecution.getId()); + } + public void setLobHandler(LobHandler lobHandler) { this.lobHandler = lobHandler; } diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcJobExecutionDao.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcJobExecutionDao.java index 3e04fbaead..a17b18503a 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcJobExecutionDao.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcJobExecutionDao.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2021 the original author or authors. + * Copyright 2006-2022 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. @@ -94,6 +94,10 @@ public class JdbcJobExecutionDao extends AbstractJdbcBatchMetadataDao implements private static final String CREATE_JOB_PARAMETERS = "INSERT into %PREFIX%JOB_EXECUTION_PARAMS(JOB_EXECUTION_ID, KEY_NAME, TYPE_CD, " + "STRING_VAL, DATE_VAL, LONG_VAL, DOUBLE_VAL, IDENTIFYING) values (?, ?, ?, ?, ?, ?, ?, ?)"; + private static final String DELETE_JOB_EXECUTION = "DELETE FROM %PREFIX%JOB_EXECUTION WHERE JOB_EXECUTION_ID = ?"; + + private static final String DELETE_JOB_EXECUTION_PARAMETERS = "DELETE FROM %PREFIX%JOB_EXECUTION_PARAMS WHERE JOB_EXECUTION_ID = ?"; + private int exitMessageLength = DEFAULT_EXIT_MESSAGE_LENGTH; private DataFieldMaxValueIncrementer jobExecutionIncrementer; @@ -303,6 +307,22 @@ public void synchronizeStatus(JobExecution jobExecution) { } } + /** + * Delete the given job execution. + * @param jobExecution the job execution to delete + */ + public void deleteJobExecution(JobExecution jobExecution) { + getJdbcTemplate().update(getQuery(DELETE_JOB_EXECUTION), jobExecution.getId()); + } + + /** + * Delete the parameters associated with the given job execution. + * @param jobExecution the job execution for which job parameters should be deleted + */ + public void deleteJobExecutionParameters(JobExecution jobExecution) { + getJdbcTemplate().update(getQuery(DELETE_JOB_EXECUTION_PARAMETERS), jobExecution.getId()); + } + /** * Convenience method that inserts all parameters from the provided JobParameters. * diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcJobInstanceDao.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcJobInstanceDao.java index f0307c7a8c..8e13c9c7cf 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcJobInstanceDao.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcJobInstanceDao.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2021 the original author or authors. + * Copyright 2006-2022 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. @@ -85,6 +85,8 @@ public class JdbcJobInstanceDao extends AbstractJdbcBatchMetadataDao implements private static final String FIND_LAST_JOBS_LIKE_NAME = "SELECT JOB_INSTANCE_ID, JOB_NAME from %PREFIX%JOB_INSTANCE where JOB_NAME like ? order by JOB_INSTANCE_ID desc"; + private static final String DELETE_JOB_INSTANCE = "DELETE FROM %PREFIX%JOB_INSTANCE WHERE JOB_INSTANCE_ID = ?"; + private DataFieldMaxValueIncrementer jobInstanceIncrementer; private JobKeyGenerator jobKeyGenerator = new DefaultJobKeyGenerator(); @@ -276,6 +278,14 @@ public int getJobInstanceCount(@Nullable String jobName) throws NoSuchJobExcepti } } + /** + * Delete the job instance. + * @param jobInstance the job instance to delete + */ + public void deleteJobInstance(JobInstance jobInstance) { + getJdbcTemplate().update(getQuery(DELETE_JOB_INSTANCE), jobInstance.getId()); + } + /** * Setter for {@link DataFieldMaxValueIncrementer} to be used when generating primary * keys for {@link JobInstance} instances. diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcStepExecutionDao.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcStepExecutionDao.java index 3661e23951..6a19d72fd3 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcStepExecutionDao.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcStepExecutionDao.java @@ -105,6 +105,9 @@ public class JdbcStepExecutionDao extends AbstractJdbcBatchMetadataDao implement + " on SE.JOB_EXECUTION_ID = JE.JOB_EXECUTION_ID " + "where JE.JOB_INSTANCE_ID = ?" + " and SE.STEP_NAME = ?"; + private static final String DELETE_STEP_EXECUTION = "DELETE FROM %PREFIX%STEP_EXECUTION " + + "WHERE STEP_EXECUTION_ID = ?"; + private int exitMessageLength = DEFAULT_EXIT_MESSAGE_LENGTH; private DataFieldMaxValueIncrementer stepExecutionIncrementer; @@ -353,6 +356,14 @@ public int countStepExecutions(JobInstance jobInstance, String stepName) { jobInstance.getInstanceId(), stepName); } + /** + * Delete the given step execution. + * @param stepExecution the step execution to delete + */ + public void deleteStepExecution(StepExecution stepExecution) { + getJdbcTemplate().update(getQuery(DELETE_STEP_EXECUTION), stepExecution.getId()); + } + private static class StepExecutionRowMapper implements RowMapper { private final JobExecution jobExecution; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JobExecutionDao.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JobExecutionDao.java index 5ca024b0b2..874a6ee256 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JobExecutionDao.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JobExecutionDao.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2018 the original author or authors. + * Copyright 2006-2022 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. @@ -21,6 +21,7 @@ import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.JobInstance; +import org.springframework.batch.core.StepExecution; import org.springframework.lang.Nullable; /** @@ -88,4 +89,22 @@ public interface JobExecutionDao { */ void synchronizeStatus(JobExecution jobExecution); + /** + * Delete the given job execution. + * @param jobExecution the job execution to delete + * @since 5.0 + */ + default void deleteJobExecution(JobExecution jobExecution) { + throw new UnsupportedOperationException(); + } + + /** + * Delete the parameters associated with the given job execution. + * @param jobExecution the job execution for which job parameters should be deleted + * @since 5.0 + */ + default void deleteJobExecutionParameters(JobExecution jobExecution) { + throw new UnsupportedOperationException(); + } + } diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JobInstanceDao.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JobInstanceDao.java index 441b544015..4c3989947e 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JobInstanceDao.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JobInstanceDao.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2019 the original author or authors. + * Copyright 2006-2022 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. @@ -130,4 +130,13 @@ default JobInstance getLastJobInstance(String jobName) { */ int getJobInstanceCount(@Nullable String jobName) throws NoSuchJobException; + /** + * Delete the job instance. + * @param jobInstance the job instance to delete + * @since 5.0 + */ + default void deleteJobInstance(JobInstance jobInstance) { + throw new UnsupportedOperationException(); + } + } diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/StepExecutionDao.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/StepExecutionDao.java index 4e30398242..1dd127e4cb 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/StepExecutionDao.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/StepExecutionDao.java @@ -91,4 +91,13 @@ default int countStepExecutions(JobInstance jobInstance, String stepName) { throw new UnsupportedOperationException(); } + /** + * Delete the given step execution. + * @param stepExecution the step execution to delete + * @since 5.0 + */ + default void deleteStepExecution(StepExecution stepExecution) { + throw new UnsupportedOperationException(); + } + } diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/support/SimpleJobRepository.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/support/SimpleJobRepository.java index ff8007c027..b96f9856cd 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/support/SimpleJobRepository.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/support/SimpleJobRepository.java @@ -279,6 +279,24 @@ public JobExecution getLastJobExecution(String jobName, JobParameters jobParamet } + @Override + public void deleteStepExecution(StepExecution stepExecution) { + this.ecDao.deleteExecutionContext(stepExecution); + this.stepExecutionDao.deleteStepExecution(stepExecution); + } + + @Override + public void deleteJobExecution(JobExecution jobExecution) { + this.ecDao.deleteExecutionContext(jobExecution); + this.jobExecutionDao.deleteJobExecutionParameters(jobExecution); + this.jobExecutionDao.deleteJobExecution(jobExecution); + } + + @Override + public void deleteJobInstance(JobInstance jobInstance) { + this.jobInstanceDao.deleteJobInstance(jobInstance); + } + @Override public JobInstance createJobInstance(String jobName, JobParameters jobParameters) { Assert.notNull(jobName, "A job name is required to create a JobInstance"); diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/AbstractExecutionContextDaoTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/AbstractExecutionContextDaoTests.java index 0093728278..5935323322 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/AbstractExecutionContextDaoTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/AbstractExecutionContextDaoTests.java @@ -16,6 +16,7 @@ package org.springframework.batch.core.repository.dao; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import java.util.ArrayList; @@ -221,4 +222,40 @@ void testStoreInteger() { assertEquals(ec, restoredEc); } + @Transactional + @Test + void testDeleteStepExecutionContext() { + // given + ExecutionContext ec = new ExecutionContext(); + stepExecution.setExecutionContext(ec); + contextDao.saveExecutionContext(stepExecution); + + // when + contextDao.deleteExecutionContext(stepExecution); + + // then + ExecutionContext restoredEc = contextDao.getExecutionContext(stepExecution); + // FIXME contextDao.getExecutionContext should return null and not an empty + // context + assertEquals(new ExecutionContext(), restoredEc); + } + + @Transactional + @Test + void testDeleteJobExecutionContext() { + // given + ExecutionContext ec = new ExecutionContext(); + jobExecution.setExecutionContext(ec); + contextDao.saveExecutionContext(jobExecution); + + // when + contextDao.deleteExecutionContext(jobExecution); + + // then + ExecutionContext restoredEc = contextDao.getExecutionContext(jobExecution); + // FIXME contextDao.getExecutionContext should return null and not an empty + // context + assertEquals(new ExecutionContext(), restoredEc); + } + } diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/JdbcJobExecutionDaoTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/JdbcJobExecutionDaoTests.java index b67e196631..b0d6a441d0 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/JdbcJobExecutionDaoTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/JdbcJobExecutionDaoTests.java @@ -23,6 +23,8 @@ import javax.sql.DataSource; import static org.junit.jupiter.api.Assertions.assertNull; + +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.springframework.batch.core.JobExecution; @@ -39,6 +41,7 @@ /** * @author Parikshit Dutta + * @author Mahmoud Ben Hassine */ @SpringJUnitConfig(locations = { "sql-dao-test.xml" }) public class JdbcJobExecutionDaoTests extends AbstractJobExecutionDaoTests { @@ -108,4 +111,34 @@ void testSavedDateIsNullForNonDateTypeJobParams() { } } + @Transactional + @Test + void testDeleteJobExecution() { + // given + JobExecution execution = new JobExecution(jobInstance, new JobParameters()); + dao.saveJobExecution(execution); + + // when + dao.deleteJobExecution(execution); + + // then + Assertions.assertNull(dao.getJobExecution(execution.getId())); + } + + @Transactional + @Test + void testDeleteJobExecutionParameters() { + // given + Map parameters = new HashMap<>(); + parameters.put("string-param", new JobParameter("value")); + JobExecution execution = new JobExecution(jobInstance, new JobParameters(parameters)); + dao.saveJobExecution(execution); + + // when + dao.deleteJobExecutionParameters(execution); + + // then + Assertions.assertEquals(0, JdbcTestUtils.countRowsInTable(jdbcTemplate, "BATCH_JOB_EXECUTION_PARAMS")); + } + } diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/JdbcJobInstanceDaoTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/JdbcJobInstanceDaoTests.java index 5e2a442376..fe3826ecc9 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/JdbcJobInstanceDaoTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/JdbcJobInstanceDaoTests.java @@ -24,6 +24,7 @@ import javax.sql.DataSource; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.JobInstance; @@ -100,4 +101,17 @@ void testJobInstanceWildcard() { assertTrue(jobInstances.isEmpty()); } + @Transactional + @Test + void testDeleteJobInstance() { + // given + JobInstance jobInstance = dao.createJobInstance("someTestInstance", new JobParameters()); + + // when + dao.deleteJobInstance(jobInstance); + + // then + Assertions.assertNull(dao.getJobInstance(jobInstance.getId())); + } + } diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/JdbcStepExecutionDaoTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/JdbcStepExecutionDaoTests.java index 989b4b7272..4f790a2180 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/JdbcStepExecutionDaoTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/JdbcStepExecutionDaoTests.java @@ -16,6 +16,7 @@ package org.springframework.batch.core.repository.dao; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; @@ -86,4 +87,17 @@ void testCountStepExecutions() { assertEquals(1, result); } + @Transactional + @Test + void testDeleteStepExecution() { + // Given + dao.saveStepExecution(stepExecution); + + // When + dao.deleteStepExecution(stepExecution); + + // Then + assertNull(dao.getStepExecution(jobExecution, stepExecution.getId())); + } + } diff --git a/spring-batch-test/src/main/java/org/springframework/batch/test/JobRepositoryTestUtils.java b/spring-batch-test/src/main/java/org/springframework/batch/test/JobRepositoryTestUtils.java index d577aef4fa..4ce17c453b 100644 --- a/spring-batch-test/src/main/java/org/springframework/batch/test/JobRepositoryTestUtils.java +++ b/spring-batch-test/src/main/java/org/springframework/batch/test/JobRepositoryTestUtils.java @@ -68,10 +68,6 @@ public JobParameters getNext(@Nullable JobParameters parameters) { }; - private JdbcOperations jdbcTemplate; - - private String tablePrefix = AbstractJdbcBatchMetadataDao.DEFAULT_TABLE_PREFIX; - /** * Default constructor. */ @@ -80,16 +76,10 @@ public 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 void setJobParametersIncrementer(JobParametersIncrementer jobParametersIn 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 List createJobExecutions(int count) /** * 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 list) throws DataAccessException { - for (JobExecution jobExecution : list) { - List stepExecutionIds = jdbcTemplate.query( - getQuery("select STEP_EXECUTION_ID from %PREFIX%STEP_EXECUTION where JOB_EXECUTION_ID=?"), - new RowMapper() { - @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 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 jobNames = this.jobRepository.getJobNames(); + for (String jobName : jobNames) { + int start = 0; + int count = 100; + List jobInstances = this.jobRepository.findJobInstancesByName(jobName, start, count); + while (!jobInstances.isEmpty()) { + for (JobInstance jobInstance : jobInstances) { + List jobExecutions = this.jobRepository.findJobExecutions(jobInstance); + if (jobExecutions != null && !jobExecutions.isEmpty()) { + removeJobExecutions(jobExecutions); + } + } + start += count; + jobInstances = this.jobRepository.findJobInstancesByName(jobName, start, count); + } + } } } diff --git a/spring-batch-test/src/main/java/org/springframework/batch/test/context/SpringBatchTest.java b/spring-batch-test/src/main/java/org/springframework/batch/test/context/SpringBatchTest.java index 352ff604ae..d9a4c3a450 100644 --- a/spring-batch-test/src/main/java/org/springframework/batch/test/context/SpringBatchTest.java +++ b/spring-batch-test/src/main/java/org/springframework/batch/test/context/SpringBatchTest.java @@ -63,12 +63,8 @@ * @Autowired * private Job jobUnderTest; * - * @Autowired - * private DataSource testDatabase; - * * @Before * public void setup() { - * this.jobRepositoryTestUtils.setDataSource(this.testDatabase); * this.jobRepositoryTestUtils.removeJobExecutions(); * this.jobLauncherTestUtils.setJob(this.jobUnderTest); * } @@ -104,9 +100,8 @@ * private JobRepositoryTestUtils jobRepositoryTestUtils; * * @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 @@ * } * * - *

- * 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}). - *

- * * @author Mahmoud Ben Hassine * @since 4.1 * @see JobLauncherTestUtils diff --git a/spring-batch-test/src/test/java/org/springframework/batch/test/JobRepositoryTestUtilsTests.java b/spring-batch-test/src/test/java/org/springframework/batch/test/JobRepositoryTestUtilsTests.java index c5768a8fed..b17174bc32 100644 --- a/spring-batch-test/src/test/java/org/springframework/batch/test/JobRepositoryTestUtilsTests.java +++ b/spring-batch-test/src/test/java/org/springframework/batch/test/JobRepositoryTestUtilsTests.java @@ -68,7 +68,7 @@ void init() { @Test void testCreateJobExecutions() throws Exception { - utils = new JobRepositoryTestUtils(jobRepository, dataSource); + utils = new JobRepositoryTestUtils(jobRepository); List list = utils.createJobExecutions(3); assertEquals(3, list.size()); assertEquals(beforeJobs + 3, JdbcTestUtils.countRowsInTable(jdbcTemplate, "BATCH_JOB_EXECUTION")); @@ -80,7 +80,7 @@ void testCreateJobExecutions() throws Exception { @Test void testRemoveJobExecutionsWithSameJobInstance() throws Exception { - utils = new JobRepositoryTestUtils(jobRepository, dataSource); + utils = new JobRepositoryTestUtils(jobRepository); List list = new ArrayList<>(); JobExecution jobExecution = jobRepository.createJobExecution("job", new JobParameters()); jobExecution.setEndTime(new Date()); @@ -95,7 +95,7 @@ void testRemoveJobExecutionsWithSameJobInstance() throws Exception { @Test void testCreateJobExecutionsByName() throws Exception { - utils = new JobRepositoryTestUtils(jobRepository, dataSource); + utils = new JobRepositoryTestUtils(jobRepository); List 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 @@ void testCreateJobExecutionsByName() throws Exception { @Test void testRemoveJobExecutionsIncrementally() throws Exception { - utils = new JobRepositoryTestUtils(jobRepository, dataSource); + utils = new JobRepositoryTestUtils(jobRepository); List list1 = utils.createJobExecutions(3); List list2 = utils.createJobExecutions(2); assertEquals(beforeJobs + 5, JdbcTestUtils.countRowsInTable(jdbcTemplate, "BATCH_JOB_EXECUTION")); @@ -119,7 +119,7 @@ void testRemoveJobExecutionsIncrementally() throws Exception { @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) { diff --git a/spring-batch-test/src/test/java/org/springframework/batch/test/SpringBatchTestJUnit4Tests.java b/spring-batch-test/src/test/java/org/springframework/batch/test/SpringBatchTestJUnit4Tests.java index 4b03feb9ea..338cf2aa2e 100644 --- a/spring-batch-test/src/test/java/org/springframework/batch/test/SpringBatchTestJUnit4Tests.java +++ b/spring-batch-test/src/test/java/org/springframework/batch/test/SpringBatchTestJUnit4Tests.java @@ -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(); } diff --git a/spring-batch-test/src/test/java/org/springframework/batch/test/SpringBatchTestJUnit5Tests.java b/spring-batch-test/src/test/java/org/springframework/batch/test/SpringBatchTestJUnit5Tests.java index a8c0631bb6..d7d4e67662 100644 --- a/spring-batch-test/src/test/java/org/springframework/batch/test/SpringBatchTestJUnit5Tests.java +++ b/spring-batch-test/src/test/java/org/springframework/batch/test/SpringBatchTestJUnit5Tests.java @@ -70,9 +70,8 @@ public class SpringBatchTestJUnit5Tests { private ItemReader 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(); }