RESOLVED - issue BATCH-503: Not applying declarative transactions around repository causes unstable execution

This commit is contained in:
dsyer
2008-05-26 12:16:05 +00:00
parent 11b4e2a012
commit 7025ff4831
6 changed files with 380 additions and 35 deletions

View File

@@ -15,15 +15,22 @@
*/
package org.springframework.batch.core.repository.support;
import java.sql.Connection;
import javax.sql.DataSource;
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
import org.easymock.MockControl;
import org.springframework.batch.core.repository.support.JobRepositoryFactoryBean;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.job.JobSupport;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.item.database.support.DataFieldMaxValueIncrementerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.support.DefaultTransactionDefinition;
/**
* @author Lucas Ward
@@ -31,23 +38,32 @@ import org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer
*/
public class JobRepositoryFactoryBeanTests extends TestCase {
JobRepositoryFactoryBean factory;
private JobRepositoryFactoryBean factory;
MockControl incrementerControl = MockControl.createControl(DataFieldMaxValueIncrementerFactory.class);
private MockControl incrementerControl = MockControl.createControl(DataFieldMaxValueIncrementerFactory.class);
DataFieldMaxValueIncrementerFactory incrementerFactory;
private DataFieldMaxValueIncrementerFactory incrementerFactory;
DataSource dataSource;
String tablePrefix = "TEST_BATCH_PREFIX_";
private DataSource dataSource;
private PlatformTransactionManager transactionManager;
private String tablePrefix = "TEST_BATCH_PREFIX_";
private MockControl txControl;
private MockControl dataSourceControl;
protected void setUp() throws Exception {
super.setUp();
factory = new JobRepositoryFactoryBean();
MockControl dataSourceControl = MockControl.createControl(DataSource.class);
dataSourceControl = MockControl.createControl(DataSource.class);
dataSource = (DataSource) dataSourceControl.getMock();
txControl = MockControl.createControl(PlatformTransactionManager.class);
transactionManager = (PlatformTransactionManager) txControl.getMock();
factory.setDataSource(dataSource);
factory.setTransactionManager(transactionManager);
incrementerFactory = (DataFieldMaxValueIncrementerFactory) incrementerControl.getMock();
factory.setIncrementerFactory(incrementerFactory);
factory.setTablePrefix(tablePrefix);
@@ -66,14 +82,44 @@ public class JobRepositoryFactoryBeanTests extends TestCase {
}
catch (IllegalArgumentException ex) {
// expected
String message = ex.getMessage();
assertTrue("Wrong message: " + message, message.indexOf("unsupported database type") >= 0);
}
}
public void testMissingDataSource() throws Exception {
factory.setDataSource(null);
try {
factory.afterPropertiesSet();
fail();
}
catch (IllegalArgumentException ex) {
// expected
String message = ex.getMessage();
assertTrue("Wrong message: " + message, message.indexOf("DataSource") >= 0);
}
}
public void testMissingTransactionManager() throws Exception {
factory.setTransactionManager(null);
try {
factory.afterPropertiesSet();
fail();
}
catch (IllegalArgumentException ex) {
// expected
String message = ex.getMessage();
assertTrue("Wrong message: " + message, message.indexOf("TransactionManager") >= 0);
}
}
public void testInvalidDatabaseType() throws Exception {
factory.setDatabaseType("invalid type");
factory.setDatabaseType("foo");
try {
incrementerFactory.isSupportedIncrementerType("invalid type");
incrementerFactory.isSupportedIncrementerType("foo");
incrementerControl.setReturnValue(false);
incrementerFactory.getSupportedIncrementerTypes();
incrementerControl.setReturnValue(new String[0]);
@@ -83,13 +129,19 @@ public class JobRepositoryFactoryBeanTests extends TestCase {
}
catch (IllegalArgumentException ex) {
// expected
String message = ex.getMessage();
assertTrue("Wrong message: " + message, message.indexOf("foo") >= 0);
}
}
public void testCreateRepository() throws Exception {
String databaseType = "databaseType";
String databaseType = "foo";
factory.setDatabaseType(databaseType);
incrementerFactory.isSupportedIncrementerType("foo");
incrementerControl.setReturnValue(true);
incrementerFactory.getSupportedIncrementerTypes();
incrementerControl.setReturnValue(new String[0]);
incrementerFactory.getIncrementer(databaseType, tablePrefix + "JOB_SEQ");
incrementerControl.setReturnValue(new StubIncrementer());
incrementerFactory.getIncrementer(databaseType, tablePrefix + "JOB_EXECUTION_SEQ");
@@ -98,11 +150,79 @@ public class JobRepositoryFactoryBeanTests extends TestCase {
incrementerControl.setReturnValue(new StubIncrementer());
incrementerControl.replay();
factory.afterPropertiesSet();
factory.getObject();
incrementerControl.verify();
}
public void testTransactionAttributesForCreateMethodNullHypothesis() throws Exception {
testCreateRepository();
JobRepository repository = (JobRepository) factory.getObject();
DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition(
DefaultTransactionDefinition.PROPAGATION_REQUIRES_NEW);
txControl.expectAndReturn(transactionManager.getTransaction(transactionDefinition), null);
txControl.replay();
try {
repository.createJobExecution(new JobSupport("job"), new JobParameters());
// we expect an exception from the txControl because we provided the
// wrong meta data
fail("Expected IllegalArgumentException");
}
catch (AssertionFailedError e) {
// expected exception from txControl - wrong isolation level used in
// comparison
assertEquals("Unexpected method call", e.getMessage().substring(3, 25));
}
}
public void testTransactionAttributesForCreateMethod() throws Exception {
testCreateRepository();
JobRepository repository = (JobRepository) factory.getObject();
DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition(
DefaultTransactionDefinition.PROPAGATION_REQUIRES_NEW);
transactionDefinition.setIsolationLevel(DefaultTransactionDefinition.ISOLATION_SERIALIZABLE);
txControl.expectAndReturn(transactionManager.getTransaction(transactionDefinition), null);
dataSourceControl.expectAndReturn(dataSource.getConnection(), MockControl.createControl(Connection.class)
.getMock());
dataSourceControl.replay();
txControl.replay();
try {
repository.createJobExecution(new JobSupport("job"), new JobParameters());
// we expect an exception but not from the txControl because we
// provided the correct meta data
fail("Expected IllegalArgumentException");
}
catch (IllegalArgumentException e) {
// expected exception from DataSourceUtils
assertEquals("No Statement specified", e.getMessage());
}
}
public void testSetTransactionAttributesForCreateMethod() throws Exception {
factory.setIsolationLevelForCreate("ISOLATION_READ_UNCOMMITTED");
testCreateRepository();
JobRepository repository = (JobRepository) factory.getObject();
DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition(
DefaultTransactionDefinition.PROPAGATION_REQUIRES_NEW);
transactionDefinition.setIsolationLevel(DefaultTransactionDefinition.ISOLATION_READ_UNCOMMITTED);
txControl.expectAndReturn(transactionManager.getTransaction(transactionDefinition), null);
dataSourceControl.expectAndReturn(dataSource.getConnection(), MockControl.createControl(Connection.class)
.getMock());
dataSourceControl.replay();
txControl.replay();
try {
repository.createJobExecution(new JobSupport("job"), new JobParameters());
// we expect an exception but not from the txControl because we
// provided the correct meta data
fail("Expected IllegalArgumentException");
}
catch (IllegalArgumentException e) {
// expected exception from DataSourceUtils
assertEquals("No Statement specified", e.getMessage());
}
}
private static class StubIncrementer implements DataFieldMaxValueIncrementer {
public int nextIntValue() throws DataAccessException {

View File

@@ -0,0 +1,65 @@
/*
* 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.step.item;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.transaction.interceptor.TransactionInterceptor;
import junit.framework.TestCase;
/**
* @author Dave Syer
*
*/
public class TransactionInterceptorValidatorTests extends TestCase {
private TransactionInterceptorValidator validator = new TransactionInterceptorValidator(1);
public void testValidateNull() {
try {
validator.validate(null);
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
String message = e.getMessage();
assertTrue("Wrong message: "+message, message.indexOf("JobRepository")>=0);
}
}
public void testValidateWithNoInterceptors() {
validator.validate(new Object());
}
public void testValidateAdvisedWithOneInterceptor() {
validator.validate(ProxyFactory.getProxy(JobRepository.class, new TransactionInterceptor()));
}
public void testValidateAdvisedWithTwoInterceptors() {
Object target = ProxyFactory.getProxy(JobRepository.class, new TransactionInterceptor());
ProxyFactory factory = new ProxyFactory();
factory.setTarget(target);
factory.addInterface(JobRepository.class);
factory.addAdvice(new TransactionInterceptor());
try {
validator.validate(factory.getProxy());
fail("Expected IllegalStateException");
} catch (IllegalStateException e) {
String message = e.getMessage();
assertTrue("Wrong message: "+message, message.indexOf("JobRepository")>=0);
}
}
}