Support single, unqualified tx manager in the TCF

TransactionalTestExecutionListener currently requires that the
PlatformTransactionManager bean be named "transactionManager" by
default. Otherwise, the bean name can only be overridden via the
transactionManager attribute of @TransactionConfiguration or the value
attribute of @Transactional.

However, if there is only a single PlatformTransactionManager in the
test's ApplicationContext, then the requirement to specify the exact
name of that bean (or to name it exactly "transactionManager") is often
superfluous.

This commit addresses this issue by refactoring the
TransactionalTestExecutionListener so that it is comparable to the
algorithm for determining the transaction manager used in
TransactionAspectSupport for "production" code. Specifically, the TTEL
now uses the following algorithm to retrieve the transaction manager.

 - look up by type and qualifier from @Transactional
 - else, look up by type and explicit name from
   @TransactionConfiguration
 - else, look up single bean by type
 - else, look up by type and default name from @TransactionConfiguration

Issue: SPR-9645
This commit is contained in:
Sam Brannen
2012-07-28 00:06:46 +02:00
parent c0b4e368dc
commit f21fe33e74
12 changed files with 885 additions and 338 deletions

View File

@@ -0,0 +1,77 @@
/*
* Copyright 2002-2012 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.test.context.junit4.spr9645;
import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.AfterTransaction;
import org.springframework.test.context.transaction.BeforeTransaction;
import org.springframework.test.transaction.CallCountingTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
/**
* Integration tests that verify the behavior requested in
* <a href="https://jira.springsource.org/browse/SPR-9645">SPR-9645</a>.
*
* @author Sam Brannen
* @since 3.2
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class LookUpNonexistentTxMgrTests {
private static final CallCountingTransactionManager txManager = new CallCountingTransactionManager();
@Configuration
static class Config {
@Bean
public PlatformTransactionManager transactionManager() {
return txManager;
}
}
@BeforeTransaction
public void beforeTransaction() {
txManager.clear();
}
@Test
public void lookUpNothing() {
assertEquals(0, txManager.begun);
assertEquals(0, txManager.inflight);
assertEquals(0, txManager.commits);
assertEquals(0, txManager.rollbacks);
}
@AfterTransaction
public void afterTransaction() {
assertEquals(0, txManager.begun);
assertEquals(0, txManager.inflight);
assertEquals(0, txManager.commits);
assertEquals(0, txManager.rollbacks);
}
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright 2002-2012 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.test.context.junit4.spr9645;
import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.AfterTransaction;
import org.springframework.test.context.transaction.BeforeTransaction;
import org.springframework.test.transaction.CallCountingTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.Transactional;
/**
* Integration tests that verify the behavior requested in
* <a href="https://jira.springsource.org/browse/SPR-9645">SPR-9645</a>.
*
* @author Sam Brannen
* @since 3.2
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@Transactional
public class LookUpTxMgrByTypeAndDefaultNameTests {
private static final CallCountingTransactionManager txManager1 = new CallCountingTransactionManager();
private static final CallCountingTransactionManager txManager2 = new CallCountingTransactionManager();
@Configuration
static class Config {
@Bean
public PlatformTransactionManager transactionManager() {
return txManager1;
}
@Bean
public PlatformTransactionManager txManager2() {
return txManager2;
}
}
@BeforeTransaction
public void beforeTransaction() {
txManager1.clear();
txManager2.clear();
}
@Test
public void lookUpByTypeAndDefaultName() {
assertEquals(1, txManager1.begun);
assertEquals(1, txManager1.inflight);
assertEquals(0, txManager1.commits);
assertEquals(0, txManager1.rollbacks);
}
@AfterTransaction
public void afterTransaction() {
assertEquals(1, txManager1.begun);
assertEquals(0, txManager1.inflight);
assertEquals(0, txManager1.commits);
assertEquals(1, txManager1.rollbacks);
}
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright 2002-2012 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.test.context.junit4.spr9645;
import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.AfterTransaction;
import org.springframework.test.context.transaction.BeforeTransaction;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.test.transaction.CallCountingTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.Transactional;
/**
* Integration tests that verify the behavior requested in
* <a href="https://jira.springsource.org/browse/SPR-9645">SPR-9645</a>.
*
* @author Sam Brannen
* @since 3.2
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@Transactional
@TransactionConfiguration(transactionManager = "txManager1")
public class LookUpTxMgrByTypeAndNameTests {
private static final CallCountingTransactionManager txManager1 = new CallCountingTransactionManager();
private static final CallCountingTransactionManager txManager2 = new CallCountingTransactionManager();
@Configuration
static class Config {
@Bean
public PlatformTransactionManager txManager1() {
return txManager1;
}
@Bean
public PlatformTransactionManager txManager2() {
return txManager2;
}
}
@BeforeTransaction
public void beforeTransaction() {
txManager1.clear();
txManager2.clear();
}
@Test
public void lookUpByTypeAndName() {
assertEquals(1, txManager1.begun);
assertEquals(1, txManager1.inflight);
assertEquals(0, txManager1.commits);
assertEquals(0, txManager1.rollbacks);
}
@AfterTransaction
public void afterTransaction() {
assertEquals(1, txManager1.begun);
assertEquals(0, txManager1.inflight);
assertEquals(0, txManager1.commits);
assertEquals(1, txManager1.rollbacks);
}
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright 2002-2012 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.test.context.junit4.spr9645;
import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.AfterTransaction;
import org.springframework.test.context.transaction.BeforeTransaction;
import org.springframework.test.transaction.CallCountingTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.Transactional;
/**
* Integration tests that verify the behavior requested in
* <a href="https://jira.springsource.org/browse/SPR-9645">SPR-9645</a>.
*
* @author Sam Brannen
* @since 3.2
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@Transactional("txManager1")
public class LookUpTxMgrByTypeAndQualifierAtClassLevelTests {
private static final CallCountingTransactionManager txManager1 = new CallCountingTransactionManager();
private static final CallCountingTransactionManager txManager2 = new CallCountingTransactionManager();
@Configuration
static class Config {
@Bean
public PlatformTransactionManager txManager1() {
return txManager1;
}
@Bean
public PlatformTransactionManager txManager2() {
return txManager2;
}
}
@BeforeTransaction
public void beforeTransaction() {
txManager1.clear();
txManager2.clear();
}
@Test
public void lookUpByTypeAndQualifier() {
assertEquals(1, txManager1.begun);
assertEquals(1, txManager1.inflight);
assertEquals(0, txManager1.commits);
assertEquals(0, txManager1.rollbacks);
}
@AfterTransaction
public void afterTransaction() {
assertEquals(1, txManager1.begun);
assertEquals(0, txManager1.inflight);
assertEquals(0, txManager1.commits);
assertEquals(1, txManager1.rollbacks);
}
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright 2002-2012 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.test.context.junit4.spr9645;
import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.AfterTransaction;
import org.springframework.test.context.transaction.BeforeTransaction;
import org.springframework.test.transaction.CallCountingTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.Transactional;
/**
* Integration tests that verify the behavior requested in
* <a href="https://jira.springsource.org/browse/SPR-9645">SPR-9645</a>.
*
* @author Sam Brannen
* @since 3.2
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class LookUpTxMgrByTypeAndQualifierAtMethodLevelTests {
private static final CallCountingTransactionManager txManager1 = new CallCountingTransactionManager();
private static final CallCountingTransactionManager txManager2 = new CallCountingTransactionManager();
@Configuration
static class Config {
@Bean
public PlatformTransactionManager txManager1() {
return txManager1;
}
@Bean
public PlatformTransactionManager txManager2() {
return txManager2;
}
}
@BeforeTransaction
public void beforeTransaction() {
txManager1.clear();
txManager2.clear();
}
@Transactional("txManager1")
@Test
public void lookUpByTypeAndQualifier() {
assertEquals(1, txManager1.begun);
assertEquals(1, txManager1.inflight);
assertEquals(0, txManager1.commits);
assertEquals(0, txManager1.rollbacks);
}
@AfterTransaction
public void afterTransaction() {
assertEquals(1, txManager1.begun);
assertEquals(0, txManager1.inflight);
assertEquals(0, txManager1.commits);
assertEquals(1, txManager1.rollbacks);
}
}

View File

@@ -0,0 +1,77 @@
/*
* Copyright 2002-2012 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.test.context.junit4.spr9645;
import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.AfterTransaction;
import org.springframework.test.context.transaction.BeforeTransaction;
import org.springframework.test.transaction.CallCountingTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.Transactional;
/**
* Integration tests that verify the behavior requested in
* <a href="https://jira.springsource.org/browse/SPR-9645">SPR-9645</a>.
*
* @author Sam Brannen
* @since 3.2
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@Transactional
public class LookUpTxMgrByTypeTests {
private static final CallCountingTransactionManager txManager = new CallCountingTransactionManager();
@Configuration
static class Config {
@Bean
public PlatformTransactionManager txManager() {
return txManager;
}
}
@BeforeTransaction
public void beforeTransaction() {
txManager.clear();
}
@Test
public void lookUpByType() {
assertEquals(1, txManager.begun);
assertEquals(1, txManager.inflight);
assertEquals(0, txManager.commits);
assertEquals(0, txManager.rollbacks);
}
@AfterTransaction
public void afterTransaction() {
assertEquals(1, txManager.begun);
assertEquals(0, txManager.inflight);
assertEquals(0, txManager.commits);
assertEquals(1, txManager.rollbacks);
}
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright 2002-2012 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.test.transaction;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.support.AbstractPlatformTransactionManager;
import org.springframework.transaction.support.DefaultTransactionStatus;
/**
* @author Rod Johnson
* @author Juergen Hoeller
*/
@SuppressWarnings("serial")
public class CallCountingTransactionManager extends AbstractPlatformTransactionManager {
public TransactionDefinition lastDefinition;
public int begun;
public int commits;
public int rollbacks;
public int inflight;
protected Object doGetTransaction() {
return new Object();
}
protected void doBegin(Object transaction, TransactionDefinition definition) {
this.lastDefinition = definition;
++begun;
++inflight;
}
protected void doCommit(DefaultTransactionStatus status) {
++commits;
--inflight;
}
protected void doRollback(DefaultTransactionStatus status) {
++rollbacks;
--inflight;
}
public void clear() {
begun = commits = rollbacks = inflight = 0;
}
}