From f8d239e18dbf8ed0b4c7cb58dc91b80c7baa1527 Mon Sep 17 00:00:00 2001 From: dsyer Date: Mon, 5 Jan 2009 11:49:14 +0000 Subject: [PATCH] RESOLVED - issue BATCH-987: Create JobRepositoryTestUtils --- .../batch/test/JobRepositoryTestUtils.java | 158 ++++++++++++++ .../batch/test/MetaDataInstanceFactory.java | 197 ++++++++++++++++++ .../test/JobRepositoryTestUtilsTests.java | 114 ++++++++++ .../test/MetaDataInstanceFactoryTests.java | 168 +++++++++++++++ 4 files changed, 637 insertions(+) create mode 100644 spring-batch-test/src/main/java/org/springframework/batch/test/JobRepositoryTestUtils.java create mode 100644 spring-batch-test/src/main/java/org/springframework/batch/test/MetaDataInstanceFactory.java create mode 100644 spring-batch-test/src/test/java/org/springframework/batch/test/JobRepositoryTestUtilsTests.java create mode 100644 spring-batch-test/src/test/java/org/springframework/batch/test/MetaDataInstanceFactoryTests.java 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 new file mode 100644 index 000000000..d9507263e --- /dev/null +++ b/spring-batch-test/src/main/java/org/springframework/batch/test/JobRepositoryTestUtils.java @@ -0,0 +1,158 @@ +/* + * Copyright 2006-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.batch.test; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import javax.sql.DataSource; + +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.core.JobParameter; +import org.springframework.batch.core.JobParameters; +import org.springframework.batch.core.JobParametersIncrementer; +import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException; +import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.batch.core.repository.JobRestartException; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.core.simple.ParameterizedRowMapper; +import org.springframework.jdbc.core.simple.SimpleJdbcOperations; +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; +import org.springframework.util.Assert; + +/** + * Convenience class for creating and removing {@link JobExecution} instances + * from a database. Typical usage in test case would be to create instances + * before a transaction, save the result, and then use it to remove them after + * the transaction. + * + * @author Dave Syer + */ +public class JobRepositoryTestUtils implements InitializingBean { + + private JobRepository jobRepository; + + private JobParametersIncrementer jobParametersIncrementer = new JobParametersIncrementer() { + + Long count = 0L; + + public JobParameters getNext(JobParameters parameters) { + return new JobParameters(Collections.singletonMap("count", new JobParameter(count++))); + } + + }; + + private SimpleJdbcOperations jdbcTemplate; + + /** + * @see InitializingBean#afterPropertiesSet() + */ + public void afterPropertiesSet() throws Exception { + Assert.notNull(jobRepository, "JobRepository must be set"); + Assert.notNull(jdbcTemplate, "DataSource must be set"); + } + + /** + * Default constructor. + */ + 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} + */ + public JobRepositoryTestUtils(JobRepository jobRepository, DataSource dataSource) { + super(); + this.jobRepository = jobRepository; + setDataSource(dataSource); + } + + public void setDataSource(DataSource dataSource) { + jdbcTemplate = new SimpleJdbcTemplate(dataSource); + } + + /** + * @param jobParametersIncrementer the jobParametersIncrementer to set + */ + public void setJobParametersIncrementer(JobParametersIncrementer jobParametersIncrementer) { + this.jobParametersIncrementer = jobParametersIncrementer; + } + + /** + * @param jobRepository the jobRepository to set + */ + public void setJobRepository(JobRepository jobRepository) { + this.jobRepository = jobRepository; + } + + /** + * Use the {@link JobRepository} to create some {@link JobExecution} + * instances. + * + * @param count the required number of instances + * @return a collection of {@link JobExecution} + * @throws Exception if there is a problem in the {@link JobRepository} + */ + public List createJobExecutions(int count) throws JobExecutionAlreadyRunningException, + JobRestartException, JobInstanceAlreadyCompleteException { + List list = new ArrayList(); + JobParameters jobParameters = new JobParameters(); + for (int i = 0; i < count; i++) { + list.add(jobRepository.createJobExecution("job", jobParametersIncrementer.getNext(jobParameters))); + } + return list; + } + + /** + * Remove the {@link JobExecution} instances provided from the standard + * RDBMS locations used by Spring Batch. + * + * @param list a list of {@link JobExecution} + * @throws DataAccessException if there is a problem + */ + public void removeJobExecutions(Collection list) throws DataAccessException { + for (JobExecution jobExecution : list) { + List stepExecutionIds = jdbcTemplate.query( + "select STEP_EXECUTION_ID from BATCH_STEP_EXECUTION where JOB_EXECUTION_ID=?", + new ParameterizedRowMapper() { + public Long mapRow(ResultSet rs, int rowNum) throws SQLException { + return rs.getLong(1); + } + }, jobExecution.getId()); + for (Long stepExecutionId : stepExecutionIds) { + jdbcTemplate.update("delete from BATCH_STEP_EXECUTION_CONTEXT where STEP_EXECUTION_ID=?", + stepExecutionId); + jdbcTemplate.update("delete from BATCH_STEP_EXECUTION where STEP_EXECUTION_ID=?", stepExecutionId); + } + jdbcTemplate.update("delete from BATCH_JOB_EXECUTION where JOB_EXECUTION_ID=?", jobExecution.getId()); + jdbcTemplate.update("delete from BATCH_JOB_EXECUTION_CONTEXT where JOB_EXECUTION_ID=?", jobExecution + .getId()); + jdbcTemplate.update("delete from BATCH_JOB_PARAMS where JOB_INSTANCE_ID=?", jobExecution.getJobId()); + jdbcTemplate.update("delete from BATCH_JOB_INSTANCE where JOB_INSTANCE_ID=?", jobExecution.getJobId()); + } + } + +} diff --git a/spring-batch-test/src/main/java/org/springframework/batch/test/MetaDataInstanceFactory.java b/spring-batch-test/src/main/java/org/springframework/batch/test/MetaDataInstanceFactory.java new file mode 100644 index 000000000..8ae631672 --- /dev/null +++ b/spring-batch-test/src/main/java/org/springframework/batch/test/MetaDataInstanceFactory.java @@ -0,0 +1,197 @@ +/* + * Copyright 2006-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.batch.test; + +import java.util.Collection; + +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.core.JobInstance; +import org.springframework.batch.core.JobParameters; +import org.springframework.batch.core.StepExecution; +import org.springframework.batch.core.converter.DefaultJobParametersConverter; +import org.springframework.batch.support.PropertiesConverter; + +/** + * Convenience methods for creating test instances of {@link JobExecution}, + * {@link JobInstance} and {@link StepExecution}. + * + * @author Dave Syer + * + */ +public class MetaDataInstanceFactory { + + /** + * Create a {@link JobInstance} with the parameters provided. + * + * @param jobName the name of the job + * @param instanceId the Id of the {@link JobInstance} + * @param jobParameters comma or new line separated name=value pairs + * @return a {@link JobInstance} + */ + public static JobInstance createJobInstance(String jobName, Long instanceId, String jobParameters) { + JobParameters params = new DefaultJobParametersConverter().getJobParameters(PropertiesConverter + .stringToProperties(jobParameters)); + return createJobInstance(jobName, instanceId, params); + } + + /** + * Create a {@link JobInstance} with the parameters provided. + * + * @param jobName the name of the job + * @param instanceId the Id of the {@link JobInstance} + * @param jobParameters an instance of {@link JobParameters} + * @return a {@link JobInstance} + */ + public static JobInstance createJobInstance(String jobName, Long instanceId, JobParameters jobParameters) { + return new JobInstance(instanceId, jobParameters, jobName); + } + + /** + * Create a {@link JobInstance} with the parameters provided. + * + * @param jobName the name of the job + * @param instanceId the Id of the {@link JobInstance} + * @return a {@link JobInstance} with empty {@link JobParameters} + */ + public static JobInstance createJobInstance(String jobName, Long instanceId) { + return new JobInstance(instanceId, new JobParameters(), jobName); + } + + /** + * Create a {@link JobInstance} with default parameters. + * + * @return a {@link JobInstance} with name="job", id=12L and empty + * parameters + */ + public static JobInstance createJobInstance() { + return new JobInstance(12L, new JobParameters(), "job"); + } + + /** + * Create a {@link JobExecution} with default parameters. + * + * @return a {@link JobExecution} with id=123L + */ + public static JobExecution createJobExecution() { + return createJobExecution(123L); + } + + /** + * Create a {@link JobExecution} with the parameters provided. + * + * @param executionId the id for the {@link JobExecution} + * @return a {@link JobExecution} with valid {@link JobInstance} + */ + public static JobExecution createJobExecution(Long executionId) { + return createJobExecution("job", 12L, executionId); + } + + /** + * Create a {@link JobExecution} with the parameters provided. + * + * @param jobName the name of the job + * @param instanceId the id for the {@link JobInstance} + * @param executionId the id for the {@link JobExecution} + * @return a {@link JobExecution} with empty {@link JobParameters} + */ + public static JobExecution createJobExecution(String jobName, Long instanceId, Long executionId) { + return createJobExecution(jobName, instanceId, executionId, new JobParameters()); + } + + /** + * Create a {@link JobExecution} with the parameters provided. + * + * @param jobName the name of the job + * @param instanceId the Id of the {@link JobInstance} + * @param executionId the id for the {@link JobExecution} + * @param jobParameters comma or new line separated name=value pairs + * @return a {@link JobExecution} + */ + public static JobExecution createJobExecution(String jobName, Long instanceId, Long executionId, + String jobParameters) { + JobParameters params = new DefaultJobParametersConverter().getJobParameters(PropertiesConverter + .stringToProperties(jobParameters)); + return createJobExecution(jobName, instanceId, executionId, params); + } + + /** + * Create a {@link JobExecution} with the parameters provided. + * + * @param jobName the name of the job + * @param instanceId the Id of the {@link JobInstance} + * @param executionId the id for the {@link JobExecution} + * @param jobParameters an instance of {@link JobParameters} + * @return a {@link JobExecution} + */ + public static JobExecution createJobExecution(String jobName, Long instanceId, Long executionId, + JobParameters jobParameters) { + return new JobExecution(createJobInstance(jobName, instanceId, jobParameters), executionId); + } + + /** + * Create a {@link StepExecution} with default parameters. + * + * @return a {@link StepExecution} with stepName="step" and id=1234L + */ + public static StepExecution createStepExecution() { + return createStepExecution("step", 1234L); + } + + /** + * Create a {@link StepExecution} with the parameters provided. + * + * @param stepName the stepName for the {@link StepExecution} + * @param executionId the id for the {@link StepExecution} + * @return a {@link StepExecution} with a {@link JobExecution} having + * default properties + */ + public static StepExecution createStepExecution(String stepName, Long executionId) { + return createStepExecution(createJobExecution(), stepName, executionId); + } + + /** + * Create a {@link StepExecution} with the parameters provided. + * + * @param stepName the stepName for the {@link StepExecution} + * @param executionId the id for the {@link StepExecution} + * @return a {@link StepExecution} with the given {@link JobExecution} + */ + public static StepExecution createStepExecution(JobExecution jobExecution, String stepName, Long executionId) { + StepExecution stepExecution = jobExecution.createStepExecution(stepName); + stepExecution.setId(executionId); + return stepExecution; + } + + /** + * Create a {@link JobExecution} with the parameters provided with attached + * step executions. + * + * @param executionId the {@link JobExecution} id + * @param stepNames the names of the step executions + * @return a {@link JobExecution} with step executions as specified, each + * with a unique id + */ + public static JobExecution createJobExecutionWithStepExecutions(Long executionId, Collection stepNames) { + JobExecution jobExecution = createJobExecution("job", 12L, executionId); + Long stepExecutionId = 1234L; + for (String stepName : stepNames) { + createStepExecution(jobExecution, stepName, stepExecutionId); + stepExecutionId++; + } + return jobExecution; + } + +} 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 new file mode 100644 index 000000000..2f133e00f --- /dev/null +++ b/spring-batch-test/src/test/java/org/springframework/batch/test/JobRepositoryTestUtilsTests.java @@ -0,0 +1,114 @@ +/* + * Copyright 2006-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.batch.test; + +import static org.junit.Assert.assertEquals; + +import java.util.List; + +import javax.sql.DataSource; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.core.JobParameters; +import org.springframework.batch.core.JobParametersBuilder; +import org.springframework.batch.core.JobParametersIncrementer; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.jdbc.SimpleJdbcTestUtils; + +/** + * @author Dave Syer + * + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = "/simple-job-launcher-context.xml") +public class JobRepositoryTestUtilsTests { + + private JobRepositoryTestUtils utils; + + @Autowired + private JobRepository jobRepository; + + @Autowired + private DataSource dataSource; + + private SimpleJdbcTemplate jdbcTemplate; + + private int before; + + @Before + public void init() { + jdbcTemplate = new SimpleJdbcTemplate(dataSource); + before = SimpleJdbcTestUtils.countRowsInTable(jdbcTemplate, "BATCH_JOB_EXECUTION"); + } + + @Test(expected=IllegalArgumentException.class) + public void testMandatoryProperties() throws Exception { + utils = new JobRepositoryTestUtils(); + utils.afterPropertiesSet(); + } + + @Test(expected=IllegalArgumentException.class) + public void testMandatoryDataSource() throws Exception { + utils = new JobRepositoryTestUtils(); + utils.setJobRepository(jobRepository); + utils.afterPropertiesSet(); + } + + @Test + public void testCreateJobExecutions() throws Exception { + utils = new JobRepositoryTestUtils(jobRepository, dataSource); + List list = utils.createJobExecutions(3); + assertEquals(3, list.size()); + assertEquals(before + 3, SimpleJdbcTestUtils.countRowsInTable(jdbcTemplate, "BATCH_JOB_EXECUTION")); + utils.removeJobExecutions(list); + assertEquals(before, SimpleJdbcTestUtils.countRowsInTable(jdbcTemplate, "BATCH_JOB_EXECUTION")); + } + + @Test + public void testRemoveJobExecutionsIncrementally() throws Exception { + utils = new JobRepositoryTestUtils(jobRepository, dataSource); + List list1 = utils.createJobExecutions(3); + List list2 = utils.createJobExecutions(2); + assertEquals(before + 5, SimpleJdbcTestUtils.countRowsInTable(jdbcTemplate, "BATCH_JOB_EXECUTION")); + utils.removeJobExecutions(list2); + assertEquals(before + 3, SimpleJdbcTestUtils.countRowsInTable(jdbcTemplate, "BATCH_JOB_EXECUTION")); + utils.removeJobExecutions(list1); + assertEquals(before, SimpleJdbcTestUtils.countRowsInTable(jdbcTemplate, "BATCH_JOB_EXECUTION")); + } + + @Test + public void testCreateJobExecutionsWithIncrementer() throws Exception { + utils = new JobRepositoryTestUtils(jobRepository, dataSource); + utils.setJobParametersIncrementer(new JobParametersIncrementer() { + public JobParameters getNext(JobParameters parameters) { + return new JobParametersBuilder().addString("foo","bar").toJobParameters(); + } + }); + List list = utils.createJobExecutions(1); + assertEquals(1, list.size()); + assertEquals("bar", list.get(0).getJobInstance().getJobParameters().getString("foo")); + utils.removeJobExecutions(list); + assertEquals(before, SimpleJdbcTestUtils.countRowsInTable(jdbcTemplate, "BATCH_JOB_EXECUTION")); + } + +} diff --git a/spring-batch-test/src/test/java/org/springframework/batch/test/MetaDataInstanceFactoryTests.java b/spring-batch-test/src/test/java/org/springframework/batch/test/MetaDataInstanceFactoryTests.java new file mode 100644 index 000000000..f12782c65 --- /dev/null +++ b/spring-batch-test/src/test/java/org/springframework/batch/test/MetaDataInstanceFactoryTests.java @@ -0,0 +1,168 @@ +/* + * Copyright 2006-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.batch.test; + +import static org.junit.Assert.assertNotNull; + +import java.util.Arrays; + +import org.junit.Test; +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.core.JobParameters; +import org.springframework.batch.core.converter.DefaultJobParametersConverter; +import org.springframework.batch.support.PropertiesConverter; + +/** + * @author Dave Syer + * + */ +public class MetaDataInstanceFactoryTests { + + private String jobName = "JOB"; + + private Long instanceId = 321L; + + private String jobParametersString = "foo=bar"; + + private JobParameters jobParameters = new DefaultJobParametersConverter().getJobParameters(PropertiesConverter + .stringToProperties(jobParametersString)); + + private Long executionId = 4321L; + + private String stepName = "step"; + + private Long stepExecutionId = 11L; + + /** + * Test method for + * {@link MetaDataInstanceFactory#createJobInstance(String, Long, String)} . + */ + @Test + public void testCreateJobInstanceStringLongString() { + assertNotNull(MetaDataInstanceFactory.createJobInstance(jobName, instanceId, jobParametersString)); + } + + /** + * Test method for + * {@link MetaDataInstanceFactory#createJobInstance(String, Long, JobParameters)} + * . + */ + @Test + public void testCreateJobInstanceStringLongJobParameters() { + assertNotNull(MetaDataInstanceFactory.createJobInstance(jobName, instanceId, jobParameters)); + } + + /** + * Test method for + * {@link MetaDataInstanceFactory#createJobInstance(String, Long)} . + */ + @Test + public void testCreateJobInstanceStringLong() { + assertNotNull(MetaDataInstanceFactory.createJobInstance(jobName, instanceId)); + } + + /** + * Test method for {@link MetaDataInstanceFactory#createJobInstance()} . + */ + @Test + public void testCreateJobInstance() { + assertNotNull(MetaDataInstanceFactory.createJobInstance()); + } + + /** + * Test method for {@link MetaDataInstanceFactory#createJobExecution()} . + */ + @Test + public void testCreateJobExecution() { + assertNotNull(MetaDataInstanceFactory.createJobExecution()); + } + + /** + * Test method for {@link MetaDataInstanceFactory#createJobExecution(Long)} + * . + */ + @Test + public void testCreateJobExecutionLong() { + assertNotNull(MetaDataInstanceFactory.createJobExecution(instanceId)); + } + + /** + * Test method for + * {@link MetaDataInstanceFactory#createJobExecution(String, Long, Long)} . + */ + @Test + public void testCreateJobExecutionStringLongLong() { + assertNotNull(MetaDataInstanceFactory.createJobExecution(jobName, instanceId, executionId)); + } + + /** + * Test method for + * {@link MetaDataInstanceFactory#createJobExecution(String, Long, Long, String)} + * . + */ + @Test + public void testCreateJobExecutionStringLongLongString() { + assertNotNull(MetaDataInstanceFactory.createJobExecution(jobName, instanceId, executionId, jobParametersString)); + } + + /** + * Test method for + * {@link MetaDataInstanceFactory#createJobExecution(String, Long, Long, JobParameters)} + * . + */ + @Test + public void testCreateJobExecutionStringLongLongJobParameters() { + assertNotNull(MetaDataInstanceFactory.createJobExecution(jobName, instanceId, executionId, jobParameters)); + } + + /** + * Test method for {@link MetaDataInstanceFactory#createStepExecution()} . + */ + @Test + public void testCreateStepExecution() { + assertNotNull(MetaDataInstanceFactory.createStepExecution()); + } + + /** + * Test method for + * {@link MetaDataInstanceFactory#createStepExecution(String, Long)} . + */ + @Test + public void testCreateStepExecutionStringLong() { + assertNotNull(MetaDataInstanceFactory.createStepExecution(stepName, stepExecutionId)); + } + + /** + * Test method for + * {@link MetaDataInstanceFactory#createStepExecution(JobExecution, String, Long)} + * . + */ + @Test + public void testCreateStepExecutionJobExecutionStringLong() { + assertNotNull(MetaDataInstanceFactory.createStepExecution(stepName, stepExecutionId)); + } + + /** + * Test method for + * {@link MetaDataInstanceFactory#createJobExecutionWithStepExecutions(Long, java.util.Collection)} + * . + */ + @Test + public void testCreateJobExecutionWithStepExecutions() { + assertNotNull(MetaDataInstanceFactory.createJobExecutionWithStepExecutions(executionId, Arrays.asList(stepName))); + } + +}