/*
* 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.core.repository.dao;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobInstance;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.StepSupport;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
import org.springframework.transaction.annotation.Transactional;
/**
* Tests for {@link StepExecutionDao} implementations.
*
* @see #getStepExecutionDao()
*/
public abstract class AbstractStepExecutionDaoTests extends AbstractTransactionalJUnit4SpringContextTests {
protected StepExecutionDao dao;
protected JobInstance jobInstance;
protected JobExecution jobExecution;
protected Step step;
protected StepExecution stepExecution;
protected JobRepository repository;
/**
* @return {@link StepExecutionDao} implementation ready for use.
*/
protected abstract StepExecutionDao getStepExecutionDao();
/**
* @return {@link JobRepository} that uses the stepExecution DAO.
*/
protected abstract JobRepository getJobRepository();
@Before
public void onSetUp() throws Exception {
repository = getJobRepository();
jobExecution = repository.createJobExecution("job", new JobParameters());
jobInstance = jobExecution.getJobInstance();
step = new StepSupport("foo");
stepExecution = new StepExecution(step.getName(), jobExecution);
dao = getStepExecutionDao();
}
@Transactional
@Test
public void testSaveExecutionAssignsIdAndVersion() throws Exception {
assertNull(stepExecution.getId());
assertNull(stepExecution.getVersion());
dao.saveStepExecution(stepExecution);
assertNotNull(stepExecution.getId());
assertNotNull(stepExecution.getVersion());
}
@Transactional
@Test
public void testSaveAndGetExecution() {
stepExecution.setStatus(BatchStatus.STARTED);
stepExecution.setReadSkipCount(7);
stepExecution.setProcessSkipCount(2);
stepExecution.setWriteSkipCount(5);
stepExecution.setProcessSkipCount(11);
stepExecution.setRollbackCount(3);
stepExecution.setLastUpdated(new Date(System.currentTimeMillis()));
stepExecution.setReadCount(17);
stepExecution.setFilterCount(15);
stepExecution.setWriteCount(13);
dao.saveStepExecution(stepExecution);
StepExecution retrieved = dao.getStepExecution(jobExecution, stepExecution.getId());
assertStepExecutionsAreEqual(stepExecution, retrieved);
assertNotNull(retrieved.getVersion());
assertNotNull(retrieved.getJobExecution());
assertNotNull(retrieved.getJobExecution().getId());
assertNotNull(retrieved.getJobExecution().getJobId());
assertNotNull(retrieved.getJobExecution().getJobInstance());
}
@Transactional
@Test
public void testSaveAndGetExecutions() {
List<StepExecution> stepExecutions = new ArrayList<StepExecution>();
for (int i = 0; i < 3; i++) {
StepExecution se = new StepExecution("step" + i, jobExecution);
se.setStatus(BatchStatus.STARTED);
se.setReadSkipCount(i);
se.setProcessSkipCount(i);
se.setWriteSkipCount(i);
se.setProcessSkipCount(i);
se.setRollbackCount(i);
se.setLastUpdated(new Date(System.currentTimeMillis()));
se.setReadCount(i);
se.setFilterCount(i);
se.setWriteCount(i);
stepExecutions.add(se);
}
dao.saveStepExecutions(stepExecutions);
for (int i = 0; i < 3; i++) {
StepExecution retrieved = dao.getStepExecution(jobExecution, stepExecutions.get(i).getId());
assertStepExecutionsAreEqual(stepExecutions.get(i), retrieved);
assertNotNull(retrieved.getVersion());
assertNotNull(retrieved.getJobExecution());
assertNotNull(retrieved.getJobExecution().getId());
assertNotNull(retrieved.getJobExecution().getJobId());
assertNotNull(retrieved.getJobExecution().getJobInstance());
}
}
@Transactional
@Test(expected = IllegalArgumentException.class)
public void testSaveNullCollectionThrowsException() {
dao.saveStepExecutions(null);
}
@Transactional
@Test
public void testSaveEmptyCollection() {
dao.saveStepExecutions(new ArrayList<StepExecution>());
}
@Transactional
@Test
public void testSaveAndGetNonExistentExecution() {
assertNull(dao.getStepExecution(jobExecution, 45677L));
}
@Transactional
@Test
public void testSaveAndFindExecution() {
stepExecution.setStatus(BatchStatus.STARTED);
stepExecution.setReadSkipCount(7);
stepExecution.setWriteSkipCount(5);
stepExecution.setRollbackCount(3);
dao.saveStepExecution(stepExecution);
dao.addStepExecutions(jobExecution);
Collection<StepExecution> retrieved = jobExecution.getStepExecutions();
assertStepExecutionsAreEqual(stepExecution, retrieved.iterator().next());
}
@Transactional
@Test
public void testGetForNotExistingJobExecution() {
assertNull(dao.getStepExecution(new JobExecution(jobInstance, (long) 777, new JobParameters(), null), 11L));
}
/**
* To-be-saved execution must not already have an id.
*/
@Transactional
@Test
public void testSaveExecutionWithIdAlreadySet() {
stepExecution.setId((long) 7);
try {
dao.saveStepExecution(stepExecution);
fail();
}
catch (IllegalArgumentException e) {
// expected
}
}
/**
* To-be-saved execution must not already have a version.
*/
@Transactional
@Test
public void testSaveExecutionWithVersionAlreadySet() {
stepExecution.incrementVersion();
try {
dao.saveStepExecution(stepExecution);
fail();
}
catch (IllegalArgumentException e) {
// expected
}
}
/**
* Update and retrieve updated StepExecution - make sure the update is
* reflected as expected and version number has been incremented
*/
@Transactional
@Test
public void testUpdateExecution() {
stepExecution.setStatus(BatchStatus.STARTED);
dao.saveStepExecution(stepExecution);
Integer versionAfterSave = stepExecution.getVersion();
stepExecution.setStatus(BatchStatus.ABANDONED);
stepExecution.setLastUpdated(new Date(System.currentTimeMillis()));
dao.updateStepExecution(stepExecution);
assertEquals(versionAfterSave + 1, stepExecution.getVersion().intValue());
StepExecution retrieved = dao.getStepExecution(jobExecution, stepExecution.getId());
assertEquals(stepExecution, retrieved);
assertEquals(stepExecution.getLastUpdated(), retrieved.getLastUpdated());
assertEquals(BatchStatus.ABANDONED, retrieved.getStatus());
}
/**
* Exception should be raised when the version of update argument doesn't
* match the version of persisted entity.
*/
@Transactional
@Test
public void testConcurrentModificationException() {
step = new StepSupport("foo");
StepExecution exec1 = new StepExecution(step.getName(), jobExecution);
dao.saveStepExecution(exec1);
StepExecution exec2 = new StepExecution(step.getName(), jobExecution);
exec2.setId(exec1.getId());
exec2.incrementVersion();
assertEquals(new Integer(0), exec1.getVersion());
assertEquals(exec1.getVersion(), exec2.getVersion());
dao.updateStepExecution(exec1);
assertEquals(new Integer(1), exec1.getVersion());
try {
dao.updateStepExecution(exec2);
fail();
}
catch (OptimisticLockingFailureException e) {
// expected
}
}
@Test
public void testGetStepExecutionsWhenNoneExist() throws Exception {
int count = jobExecution.getStepExecutions().size();
dao.addStepExecutions(jobExecution);
assertEquals("Incorrect size of collection", count, jobExecution.getStepExecutions().size());
}
private void assertStepExecutionsAreEqual(StepExecution expected, StepExecution actual) {
assertEquals(expected.getId(), actual.getId());
assertEquals(expected.getStartTime(), actual.getStartTime());
assertEquals(expected.getEndTime(), actual.getEndTime());
assertEquals(expected.getSkipCount(), actual.getSkipCount());
assertEquals(expected.getCommitCount(), actual.getCommitCount());
assertEquals(expected.getReadCount(), actual.getReadCount());
assertEquals(expected.getWriteCount(), actual.getWriteCount());
assertEquals(expected.getFilterCount(), actual.getFilterCount());
assertEquals(expected.getWriteSkipCount(), actual.getWriteSkipCount());
assertEquals(expected.getReadSkipCount(), actual.getReadSkipCount());
assertEquals(expected.getProcessSkipCount(), actual.getProcessSkipCount());
assertEquals(expected.getRollbackCount(), actual.getRollbackCount());
assertEquals(expected.getExitStatus(), actual.getExitStatus());
assertEquals(expected.getLastUpdated(), actual.getLastUpdated());
assertEquals(expected.getExitStatus(), actual.getExitStatus());
assertEquals(expected.getJobExecutionId(), actual.getJobExecutionId());
}
}