diff --git a/spring-test/src/main/java/org/springframework/test/context/transaction/TestContextTransactionUtils.java b/spring-test/src/main/java/org/springframework/test/context/transaction/TestContextTransactionUtils.java index 3b65d69056f..b00a9955877 100644 --- a/spring-test/src/main/java/org/springframework/test/context/transaction/TestContextTransactionUtils.java +++ b/spring-test/src/main/java/org/springframework/test/context/transaction/TestContextTransactionUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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. @@ -17,6 +17,7 @@ package org.springframework.test.context.transaction; import java.util.Map; + import javax.sql.DataSource; import org.apache.commons.logging.Log; @@ -73,7 +74,8 @@ public abstract class TestContextTransactionUtils { *
  • Look up the {@code DataSource} by type and name, if the supplied * {@code name} is non-empty, throwing a {@link BeansException} if the named * {@code DataSource} does not exist. - *
  • Attempt to look up a single {@code DataSource} by type. + *
  • Attempt to look up the single {@code DataSource} by type. + *
  • Attempt to look up the primary {@code DataSource} by type. *
  • Attempt to look up the {@code DataSource} by type and the * {@linkplain #DEFAULT_DATA_SOURCE_NAME default data source name}. * @param testContext the test context for which the {@code DataSource} @@ -110,15 +112,21 @@ public abstract class TestContextTransactionUtils { if (dataSources.size() == 1) { return dataSources.values().iterator().next(); } + + try { + // look up single bean by type, with support for 'primary' beans + return bf.getBean(DataSource.class); + } + catch (BeansException ex) { + logBeansException(testContext, ex, PlatformTransactionManager.class); + } } // look up by type and default name return bf.getBean(DEFAULT_DATA_SOURCE_NAME, DataSource.class); } catch (BeansException ex) { - if (logger.isDebugEnabled()) { - logger.debug("Caught exception while retrieving DataSource for test context " + testContext, ex); - } + logBeansException(testContext, ex, DataSource.class); return null; } } @@ -133,7 +141,8 @@ public abstract class TestContextTransactionUtils { *
  • Look up the transaction manager by type and explicit name, if the supplied * {@code name} is non-empty, throwing a {@link BeansException} if the named * transaction manager does not exist. - *
  • Attempt to look up the transaction manager by type. + *
  • Attempt to look up the single transaction manager by type. + *
  • Attempt to look up the primary transaction manager by type. *
  • Attempt to look up the transaction manager via a * {@link TransactionManagementConfigurer}, if present. *
  • Attempt to look up the transaction manager by type and the @@ -176,6 +185,14 @@ public abstract class TestContextTransactionUtils { return txMgrs.values().iterator().next(); } + try { + // look up single bean by type, with support for 'primary' beans + return bf.getBean(PlatformTransactionManager.class); + } + catch (BeansException ex) { + logBeansException(testContext, ex, PlatformTransactionManager.class); + } + // look up single TransactionManagementConfigurer Map configurers = BeanFactoryUtils.beansOfTypeIncludingAncestors( lbf, TransactionManagementConfigurer.class); @@ -192,14 +209,18 @@ public abstract class TestContextTransactionUtils { return bf.getBean(DEFAULT_TRANSACTION_MANAGER_NAME, PlatformTransactionManager.class); } catch (BeansException ex) { - if (logger.isDebugEnabled()) { - logger.debug("Caught exception while retrieving transaction manager for test context " + testContext, - ex); - } + logBeansException(testContext, ex, PlatformTransactionManager.class); return null; } } + private static void logBeansException(TestContext testContext, BeansException ex, Class beanType) { + if (logger.isDebugEnabled()) { + logger.debug(String.format("Caught exception while retrieving %s for test context %s", + beanType.getSimpleName(), testContext), ex); + } + } + /** * Create a delegating {@link TransactionAttribute} for the supplied target * {@link TransactionAttribute} and {@link TestContext}, using the names of diff --git a/spring-test/src/test/java/org/springframework/test/context/jdbc/PrimaryDataSourceTests.java b/spring-test/src/test/java/org/springframework/test/context/jdbc/PrimaryDataSourceTests.java new file mode 100644 index 00000000000..f07167806ce --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/jdbc/PrimaryDataSourceTests.java @@ -0,0 +1,89 @@ +/* + * Copyright 2002-2016 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.jdbc; + +import javax.sql.DataSource; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.jdbc.JdbcTestUtils; +import org.springframework.test.transaction.TransactionTestUtils; + +import static org.junit.Assert.*; + +/** + * Integration tests that ensure that primary data sources are + * supported. + * + * @author Sam Brannen + * @since 4.3 + * @see org.springframework.test.context.transaction.PrimaryTransactionManagerTests + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration +@DirtiesContext +public class PrimaryDataSourceTests { + + @Configuration + static class Config { + + @Primary + @Bean + public DataSource primaryDataSource() { + // @formatter:off + return new EmbeddedDatabaseBuilder() + .generateUniqueName(true) + .addScript("classpath:/org/springframework/test/context/jdbc/schema.sql") + .build(); + // @formatter:on + } + + @Bean + public DataSource additionalDataSource() { + return new EmbeddedDatabaseBuilder().generateUniqueName(true).build(); + } + + } + + + private JdbcTemplate jdbcTemplate; + + + @Autowired + public void setDataSource(DataSource dataSource) { + this.jdbcTemplate = new JdbcTemplate(dataSource); + } + + @Test + @Sql("data.sql") + public void dataSourceTest() { + TransactionTestUtils.assertInTransaction(false); + assertEquals("Number of rows in the 'user' table.", 1, + JdbcTestUtils.countRowsInTable(this.jdbcTemplate, "user")); + } + +} diff --git a/spring-test/src/test/java/org/springframework/test/context/transaction/PrimaryTransactionManagerTests.java b/spring-test/src/test/java/org/springframework/test/context/transaction/PrimaryTransactionManagerTests.java new file mode 100644 index 00000000000..d9cd1526793 --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/transaction/PrimaryTransactionManagerTests.java @@ -0,0 +1,122 @@ +/* + * Copyright 2002-2016 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.transaction; + +import javax.sql.DataSource; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.core.io.ClassPathResource; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.datasource.DataSourceTransactionManager; +import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; +import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.jdbc.JdbcTestUtils; +import org.springframework.test.transaction.TransactionTestUtils; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.Transactional; + +import static org.junit.Assert.*; + +/** + * Integration tests that ensure that primary transaction managers + * are supported. + * + * @author Sam Brannen + * @since 4.3 + * @see org.springframework.test.context.jdbc.PrimaryDataSourceTests + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration +@DirtiesContext +public class PrimaryTransactionManagerTests { + + @Configuration + static class Config { + + @Primary + @Bean + public PlatformTransactionManager primaryTransactionManager() { + return new DataSourceTransactionManager(dataSource1()); + } + + @Bean + public PlatformTransactionManager additionalTransactionManager() { + return new DataSourceTransactionManager(dataSource2()); + } + + @Bean + public DataSource dataSource1() { + // @formatter:off + return new EmbeddedDatabaseBuilder() + .generateUniqueName(true) + .addScript("classpath:/org/springframework/test/context/jdbc/schema.sql") + .build(); + // @formatter:on + } + + @Bean + public DataSource dataSource2() { + return new EmbeddedDatabaseBuilder().generateUniqueName(true).build(); + } + + } + + + private JdbcTemplate jdbcTemplate; + + + @Autowired + public void setDataSource(DataSource dataSource1) { + this.jdbcTemplate = new JdbcTemplate(dataSource1); + } + + @BeforeTransaction + public void beforeTransaction() { + assertNumUsers(0); + } + + @Test + @Transactional + public void transactionalTest() { + TransactionTestUtils.assertInTransaction(true); + + ClassPathResource resource = new ClassPathResource("/org/springframework/test/context/jdbc/data.sql"); + new ResourceDatabasePopulator(resource).execute(jdbcTemplate.getDataSource()); + + assertNumUsers(1); + } + + @AfterTransaction + public void afterTransaction() { + assertNumUsers(0); + } + + private void assertNumUsers(int expected) { + assertEquals("Number of rows in the 'user' table.", expected, + JdbcTestUtils.countRowsInTable(this.jdbcTemplate, "user")); + } + +}