Concurrency and exception message refinements for test transactions
(cherry picked from commit a0cc800)
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2016 the original author or authors.
|
* Copyright 2002-2018 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -28,15 +28,15 @@ import java.lang.annotation.Target;
|
|||||||
* configured to run within a transaction via Spring's {@code @Transactional}
|
* configured to run within a transaction via Spring's {@code @Transactional}
|
||||||
* annotation.
|
* annotation.
|
||||||
*
|
*
|
||||||
* <p>As of Spring Framework 4.3, {@code @AfterTransaction} may be declared on
|
|
||||||
* Java 8 based interface default methods.
|
|
||||||
*
|
|
||||||
* <p>{@code @AfterTransaction} methods declared in superclasses or as interface
|
* <p>{@code @AfterTransaction} methods declared in superclasses or as interface
|
||||||
* default methods will be executed after those of the current test class.
|
* default methods will be executed after those of the current test class.
|
||||||
*
|
*
|
||||||
* <p>As of Spring Framework 4.0, this annotation may be used as a
|
* <p>As of Spring Framework 4.0, this annotation may be used as a
|
||||||
* <em>meta-annotation</em> to create custom <em>composed annotations</em>.
|
* <em>meta-annotation</em> to create custom <em>composed annotations</em>.
|
||||||
*
|
*
|
||||||
|
* <p>As of Spring Framework 4.3, {@code @AfterTransaction} may also be
|
||||||
|
* declared on Java 8 based interface default methods.
|
||||||
|
*
|
||||||
* @author Sam Brannen
|
* @author Sam Brannen
|
||||||
* @since 2.5
|
* @since 2.5
|
||||||
* @see org.springframework.transaction.annotation.Transactional
|
* @see org.springframework.transaction.annotation.Transactional
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2016 the original author or authors.
|
* Copyright 2002-2018 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -28,15 +28,15 @@ import java.lang.annotation.Target;
|
|||||||
* configured to run within a transaction via Spring's {@code @Transactional}
|
* configured to run within a transaction via Spring's {@code @Transactional}
|
||||||
* annotation.
|
* annotation.
|
||||||
*
|
*
|
||||||
* <p>As of Spring Framework 4.3, {@code @BeforeTransaction} may be declared on
|
|
||||||
* Java 8 based interface default methods.
|
|
||||||
*
|
|
||||||
* <p>{@code @BeforeTransaction} methods declared in superclasses or as interface
|
* <p>{@code @BeforeTransaction} methods declared in superclasses or as interface
|
||||||
* default methods will be executed before those of the current test class.
|
* default methods will be executed before those of the current test class.
|
||||||
*
|
*
|
||||||
* <p>As of Spring Framework 4.0, this annotation may be used as a
|
* <p>As of Spring Framework 4.0, this annotation may be used as a
|
||||||
* <em>meta-annotation</em> to create custom <em>composed annotations</em>.
|
* <em>meta-annotation</em> to create custom <em>composed annotations</em>.
|
||||||
*
|
*
|
||||||
|
* <p>As of Spring Framework 4.3, {@code @BeforeTransaction} may also be
|
||||||
|
* declared on Java 8 based interface default methods.
|
||||||
|
*
|
||||||
* @author Sam Brannen
|
* @author Sam Brannen
|
||||||
* @since 2.5
|
* @since 2.5
|
||||||
* @see org.springframework.transaction.annotation.Transactional
|
* @see org.springframework.transaction.annotation.Transactional
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2016 the original author or authors.
|
* Copyright 2002-2018 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -38,6 +38,7 @@ import org.springframework.util.StringUtils;
|
|||||||
/**
|
/**
|
||||||
* Utility methods for working with transactions and data access related beans
|
* Utility methods for working with transactions and data access related beans
|
||||||
* within the <em>Spring TestContext Framework</em>.
|
* within the <em>Spring TestContext Framework</em>.
|
||||||
|
*
|
||||||
* <p>Mainly for internal use within the framework.
|
* <p>Mainly for internal use within the framework.
|
||||||
*
|
*
|
||||||
* @author Sam Brannen
|
* @author Sam Brannen
|
||||||
@@ -46,8 +47,6 @@ import org.springframework.util.StringUtils;
|
|||||||
*/
|
*/
|
||||||
public abstract class TestContextTransactionUtils {
|
public abstract class TestContextTransactionUtils {
|
||||||
|
|
||||||
private static final Log logger = LogFactory.getLog(TestContextTransactionUtils.class);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default bean name for a {@link DataSource}: {@code "dataSource"}.
|
* Default bean name for a {@link DataSource}: {@code "dataSource"}.
|
||||||
*/
|
*/
|
||||||
@@ -60,9 +59,8 @@ public abstract class TestContextTransactionUtils {
|
|||||||
public static final String DEFAULT_TRANSACTION_MANAGER_NAME = "transactionManager";
|
public static final String DEFAULT_TRANSACTION_MANAGER_NAME = "transactionManager";
|
||||||
|
|
||||||
|
|
||||||
private TestContextTransactionUtils() {
|
private static final Log logger = LogFactory.getLog(TestContextTransactionUtils.class);
|
||||||
/* prevent instantiation */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the {@link DataSource} to use for the supplied {@linkplain TestContext
|
* Retrieve the {@link DataSource} to use for the supplied {@linkplain TestContext
|
||||||
@@ -80,8 +78,8 @@ public abstract class TestContextTransactionUtils {
|
|||||||
* {@linkplain #DEFAULT_DATA_SOURCE_NAME default data source name}.
|
* {@linkplain #DEFAULT_DATA_SOURCE_NAME default data source name}.
|
||||||
* @param testContext the test context for which the {@code DataSource}
|
* @param testContext the test context for which the {@code DataSource}
|
||||||
* should be retrieved; never {@code null}
|
* should be retrieved; never {@code null}
|
||||||
* @param name the name of the {@code DataSource} to retrieve; may be {@code null}
|
* @param name the name of the {@code DataSource} to retrieve
|
||||||
* or <em>empty</em>
|
* (may be {@code null} or <em>empty</em>)
|
||||||
* @return the {@code DataSource} to use, or {@code null} if not found
|
* @return the {@code DataSource} to use, or {@code null} if not found
|
||||||
* @throws BeansException if an error occurs while retrieving an explicitly
|
* @throws BeansException if an error occurs while retrieving an explicitly
|
||||||
* named {@code DataSource}
|
* named {@code DataSource}
|
||||||
@@ -91,14 +89,14 @@ public abstract class TestContextTransactionUtils {
|
|||||||
BeanFactory bf = testContext.getApplicationContext().getAutowireCapableBeanFactory();
|
BeanFactory bf = testContext.getApplicationContext().getAutowireCapableBeanFactory();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// look up by type and explicit name
|
// Look up by type and explicit name
|
||||||
if (StringUtils.hasText(name)) {
|
if (StringUtils.hasText(name)) {
|
||||||
return bf.getBean(name, DataSource.class);
|
return bf.getBean(name, DataSource.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (BeansException ex) {
|
catch (BeansException ex) {
|
||||||
logger.error(
|
logger.error(String.format("Failed to retrieve DataSource named '%s' for test context %s",
|
||||||
String.format("Failed to retrieve DataSource named '%s' for test context %s", name, testContext), ex);
|
name, testContext), ex);
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,9 +104,9 @@ public abstract class TestContextTransactionUtils {
|
|||||||
if (bf instanceof ListableBeanFactory) {
|
if (bf instanceof ListableBeanFactory) {
|
||||||
ListableBeanFactory lbf = (ListableBeanFactory) bf;
|
ListableBeanFactory lbf = (ListableBeanFactory) bf;
|
||||||
|
|
||||||
// look up single bean by type
|
// Look up single bean by type
|
||||||
Map<String, DataSource> dataSources = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf,
|
Map<String, DataSource> dataSources =
|
||||||
DataSource.class);
|
BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, DataSource.class);
|
||||||
if (dataSources.size() == 1) {
|
if (dataSources.size() == 1) {
|
||||||
return dataSources.values().iterator().next();
|
return dataSources.values().iterator().next();
|
||||||
}
|
}
|
||||||
@@ -150,8 +148,8 @@ public abstract class TestContextTransactionUtils {
|
|||||||
* name}.
|
* name}.
|
||||||
* @param testContext the test context for which the transaction manager
|
* @param testContext the test context for which the transaction manager
|
||||||
* should be retrieved; never {@code null}
|
* should be retrieved; never {@code null}
|
||||||
* @param name the name of the transaction manager to retrieve; may be
|
* @param name the name of the transaction manager to retrieve
|
||||||
* {@code null} or <em>empty</em>
|
* (may be {@code null} or <em>empty</em>)
|
||||||
* @return the transaction manager to use, or {@code null} if not found
|
* @return the transaction manager to use, or {@code null} if not found
|
||||||
* @throws BeansException if an error occurs while retrieving an explicitly
|
* @throws BeansException if an error occurs while retrieving an explicitly
|
||||||
* named transaction manager
|
* named transaction manager
|
||||||
@@ -163,14 +161,14 @@ public abstract class TestContextTransactionUtils {
|
|||||||
BeanFactory bf = testContext.getApplicationContext().getAutowireCapableBeanFactory();
|
BeanFactory bf = testContext.getApplicationContext().getAutowireCapableBeanFactory();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// look up by type and explicit name
|
// Look up by type and explicit name
|
||||||
if (StringUtils.hasText(name)) {
|
if (StringUtils.hasText(name)) {
|
||||||
return bf.getBean(name, PlatformTransactionManager.class);
|
return bf.getBean(name, PlatformTransactionManager.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (BeansException ex) {
|
catch (BeansException ex) {
|
||||||
logger.error(String.format("Failed to retrieve transaction manager named '%s' for test context %s", name,
|
logger.error(String.format("Failed to retrieve transaction manager named '%s' for test context %s",
|
||||||
testContext), ex);
|
name, testContext), ex);
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,28 +176,26 @@ public abstract class TestContextTransactionUtils {
|
|||||||
if (bf instanceof ListableBeanFactory) {
|
if (bf instanceof ListableBeanFactory) {
|
||||||
ListableBeanFactory lbf = (ListableBeanFactory) bf;
|
ListableBeanFactory lbf = (ListableBeanFactory) bf;
|
||||||
|
|
||||||
// look up single bean by type
|
// Look up single bean by type
|
||||||
Map<String, PlatformTransactionManager> txMgrs = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf,
|
Map<String, PlatformTransactionManager> txMgrs =
|
||||||
PlatformTransactionManager.class);
|
BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, PlatformTransactionManager.class);
|
||||||
if (txMgrs.size() == 1) {
|
if (txMgrs.size() == 1) {
|
||||||
return txMgrs.values().iterator().next();
|
return txMgrs.values().iterator().next();
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// look up single bean by type, with support for 'primary' beans
|
// Look up single bean by type, with support for 'primary' beans
|
||||||
return bf.getBean(PlatformTransactionManager.class);
|
return bf.getBean(PlatformTransactionManager.class);
|
||||||
}
|
}
|
||||||
catch (BeansException ex) {
|
catch (BeansException ex) {
|
||||||
logBeansException(testContext, ex, PlatformTransactionManager.class);
|
logBeansException(testContext, ex, PlatformTransactionManager.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
// look up single TransactionManagementConfigurer
|
// Look up single TransactionManagementConfigurer
|
||||||
Map<String, TransactionManagementConfigurer> configurers = BeanFactoryUtils.beansOfTypeIncludingAncestors(
|
Map<String, TransactionManagementConfigurer> configurers =
|
||||||
lbf, TransactionManagementConfigurer.class);
|
BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, TransactionManagementConfigurer.class);
|
||||||
if (configurers.size() > 1) {
|
Assert.state(configurers.size() <= 1,
|
||||||
throw new IllegalStateException(
|
|
||||||
"Only one TransactionManagementConfigurer may exist in the ApplicationContext");
|
"Only one TransactionManagementConfigurer may exist in the ApplicationContext");
|
||||||
}
|
|
||||||
if (configurers.size() == 1) {
|
if (configurers.size() == 1) {
|
||||||
return configurers.values().iterator().next().annotationDrivenTransactionManager();
|
return configurers.values().iterator().next().annotationDrivenTransactionManager();
|
||||||
}
|
}
|
||||||
@@ -225,13 +221,13 @@ public abstract class TestContextTransactionUtils {
|
|||||||
* Create a delegating {@link TransactionAttribute} for the supplied target
|
* Create a delegating {@link TransactionAttribute} for the supplied target
|
||||||
* {@link TransactionAttribute} and {@link TestContext}, using the names of
|
* {@link TransactionAttribute} and {@link TestContext}, using the names of
|
||||||
* the test class and test method to build the name of the transaction.
|
* the test class and test method to build the name of the transaction.
|
||||||
*
|
* @param testContext the {@code TestContext} upon which to base the name
|
||||||
* @param testContext the {@code TestContext} upon which to base the name; never {@code null}
|
* @param targetAttribute the {@code TransactionAttribute} to delegate to
|
||||||
* @param targetAttribute the {@code TransactionAttribute} to delegate to; never {@code null}
|
|
||||||
* @return the delegating {@code TransactionAttribute}
|
* @return the delegating {@code TransactionAttribute}
|
||||||
*/
|
*/
|
||||||
public static TransactionAttribute createDelegatingTransactionAttribute(TestContext testContext,
|
public static TransactionAttribute createDelegatingTransactionAttribute(
|
||||||
TransactionAttribute targetAttribute) {
|
TestContext testContext, TransactionAttribute targetAttribute) {
|
||||||
|
|
||||||
Assert.notNull(testContext, "TestContext must not be null");
|
Assert.notNull(testContext, "TestContext must not be null");
|
||||||
Assert.notNull(targetAttribute, "Target TransactionAttribute must not be null");
|
Assert.notNull(targetAttribute, "Target TransactionAttribute must not be null");
|
||||||
return new TestContextTransactionAttribute(targetAttribute, testContext);
|
return new TestContextTransactionAttribute(targetAttribute, testContext);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2014 the original author or authors.
|
* Copyright 2002-2018 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -18,6 +18,7 @@ package org.springframework.test.context.transaction;
|
|||||||
|
|
||||||
import org.springframework.test.context.TestExecutionListeners;
|
import org.springframework.test.context.TestExecutionListeners;
|
||||||
import org.springframework.transaction.TransactionStatus;
|
import org.springframework.transaction.TransactionStatus;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@code TestTransaction} provides a collection of static utility methods for
|
* {@code TestTransaction} provides a collection of static utility methods for
|
||||||
@@ -49,10 +50,8 @@ public class TestTransaction {
|
|||||||
TransactionContext transactionContext = TransactionContextHolder.getCurrentTransactionContext();
|
TransactionContext transactionContext = TransactionContextHolder.getCurrentTransactionContext();
|
||||||
if (transactionContext != null) {
|
if (transactionContext != null) {
|
||||||
TransactionStatus transactionStatus = transactionContext.getTransactionStatus();
|
TransactionStatus transactionStatus = transactionContext.getTransactionStatus();
|
||||||
return (transactionStatus != null) && (!transactionStatus.isCompleted());
|
return (transactionStatus != null && !transactionStatus.isCompleted());
|
||||||
}
|
}
|
||||||
|
|
||||||
// else
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,8 +78,7 @@ public class TestTransaction {
|
|||||||
* Rather, the value of this flag will be used to determine whether or not
|
* Rather, the value of this flag will be used to determine whether or not
|
||||||
* the current test-managed transaction should be rolled back or committed
|
* the current test-managed transaction should be rolled back or committed
|
||||||
* once it is {@linkplain #end ended}.
|
* once it is {@linkplain #end ended}.
|
||||||
* @throws IllegalStateException if a transaction is not active for the
|
* @throws IllegalStateException if no transaction is active for the current test
|
||||||
* current test
|
|
||||||
* @see #isActive()
|
* @see #isActive()
|
||||||
* @see #isFlaggedForRollback()
|
* @see #isFlaggedForRollback()
|
||||||
* @see #start()
|
* @see #start()
|
||||||
@@ -96,8 +94,7 @@ public class TestTransaction {
|
|||||||
* Rather, the value of this flag will be used to determine whether or not
|
* Rather, the value of this flag will be used to determine whether or not
|
||||||
* the current test-managed transaction should be rolled back or committed
|
* the current test-managed transaction should be rolled back or committed
|
||||||
* once it is {@linkplain #end ended}.
|
* once it is {@linkplain #end ended}.
|
||||||
* @throws IllegalStateException if a transaction is not active for the
|
* @throws IllegalStateException if no transaction is active for the current test
|
||||||
* current test
|
|
||||||
* @see #isActive()
|
* @see #isActive()
|
||||||
* @see #isFlaggedForRollback()
|
* @see #isFlaggedForRollback()
|
||||||
* @see #start()
|
* @see #start()
|
||||||
@@ -121,9 +118,9 @@ public class TestTransaction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Immediately force a <em>commit</em> or <em>rollback</em> of the current
|
* Immediately force a <em>commit</em> or <em>rollback</em> of the
|
||||||
* test-managed transaction, according to the {@linkplain #isFlaggedForRollback
|
* current test-managed transaction, according to the
|
||||||
* rollback flag}.
|
* {@linkplain #isFlaggedForRollback rollback flag}.
|
||||||
* @throws IllegalStateException if the transaction context could not be
|
* @throws IllegalStateException if the transaction context could not be
|
||||||
* retrieved or if a transaction is not active for the current test
|
* retrieved or if a transaction is not active for the current test
|
||||||
* @see #isActive()
|
* @see #isActive()
|
||||||
@@ -133,11 +130,10 @@ public class TestTransaction {
|
|||||||
requireCurrentTransactionContext().endTransaction();
|
requireCurrentTransactionContext().endTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static TransactionContext requireCurrentTransactionContext() {
|
private static TransactionContext requireCurrentTransactionContext() {
|
||||||
TransactionContext txContext = TransactionContextHolder.getCurrentTransactionContext();
|
TransactionContext txContext = TransactionContextHolder.getCurrentTransactionContext();
|
||||||
if (txContext == null) {
|
Assert.state(txContext != null, "TransactionContext is not active");
|
||||||
throw new IllegalStateException("TransactionContext is not active");
|
|
||||||
}
|
|
||||||
return txContext;
|
return txContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2017 the original author or authors.
|
* Copyright 2002-2018 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package org.springframework.test.context.transaction;
|
package org.springframework.test.context.transaction;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
@@ -24,6 +26,7 @@ import org.springframework.transaction.PlatformTransactionManager;
|
|||||||
import org.springframework.transaction.TransactionDefinition;
|
import org.springframework.transaction.TransactionDefinition;
|
||||||
import org.springframework.transaction.TransactionException;
|
import org.springframework.transaction.TransactionException;
|
||||||
import org.springframework.transaction.TransactionStatus;
|
import org.springframework.transaction.TransactionStatus;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transaction context for a specific {@link TestContext}.
|
* Transaction context for a specific {@link TestContext}.
|
||||||
@@ -50,7 +53,7 @@ class TransactionContext {
|
|||||||
|
|
||||||
private TransactionStatus transactionStatus;
|
private TransactionStatus transactionStatus;
|
||||||
|
|
||||||
private volatile int transactionsStarted = 0;
|
private final AtomicInteger transactionsStarted = new AtomicInteger(0);
|
||||||
|
|
||||||
|
|
||||||
TransactionContext(TestContext testContext, PlatformTransactionManager transactionManager,
|
TransactionContext(TestContext testContext, PlatformTransactionManager transactionManager,
|
||||||
@@ -79,32 +82,30 @@ class TransactionContext {
|
|||||||
|
|
||||||
void setFlaggedForRollback(boolean flaggedForRollback) {
|
void setFlaggedForRollback(boolean flaggedForRollback) {
|
||||||
if (this.transactionStatus == null) {
|
if (this.transactionStatus == null) {
|
||||||
throw new IllegalStateException(String.format(
|
throw new IllegalStateException(
|
||||||
"Failed to set rollback flag for test context %s: transaction does not exist.", this.testContext));
|
"Failed to set rollback flag - transaction does not exist: " + this.testContext);
|
||||||
}
|
}
|
||||||
this.flaggedForRollback = flaggedForRollback;
|
this.flaggedForRollback = flaggedForRollback;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start a new transaction for the configured {@linkplain #getTestContext test context}.
|
* Start a new transaction for the configured test context.
|
||||||
* <p>Only call this method if {@link #endTransaction} has been called or if no
|
* <p>Only call this method if {@link #endTransaction} has been called or if no
|
||||||
* transaction has been previously started.
|
* transaction has been previously started.
|
||||||
* @throws TransactionException if starting the transaction fails
|
* @throws TransactionException if starting the transaction fails
|
||||||
*/
|
*/
|
||||||
void startTransaction() {
|
void startTransaction() {
|
||||||
if (this.transactionStatus != null) {
|
Assert.state(this.transactionStatus == null,
|
||||||
throw new IllegalStateException(
|
"Cannot start a new transaction without ending the existing transaction first");
|
||||||
"Cannot start a new transaction without ending the existing transaction first.");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.flaggedForRollback = this.defaultRollback;
|
this.flaggedForRollback = this.defaultRollback;
|
||||||
this.transactionStatus = this.transactionManager.getTransaction(this.transactionDefinition);
|
this.transactionStatus = this.transactionManager.getTransaction(this.transactionDefinition);
|
||||||
++this.transactionsStarted;
|
int transactionsStarted = this.transactionsStarted.incrementAndGet();
|
||||||
|
|
||||||
if (logger.isInfoEnabled()) {
|
if (logger.isInfoEnabled()) {
|
||||||
logger.info(String.format(
|
logger.info(String.format(
|
||||||
"Began transaction (%s) for test context %s; transaction manager [%s]; rollback [%s]",
|
"Began transaction (%s) for test context %s; transaction manager [%s]; rollback [%s]",
|
||||||
this.transactionsStarted, this.testContext, this.transactionManager, flaggedForRollback));
|
transactionsStarted, this.testContext, this.transactionManager, flaggedForRollback));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,8 +120,8 @@ class TransactionContext {
|
|||||||
this.testContext, this.transactionStatus, this.flaggedForRollback));
|
this.testContext, this.transactionStatus, this.flaggedForRollback));
|
||||||
}
|
}
|
||||||
if (this.transactionStatus == null) {
|
if (this.transactionStatus == null) {
|
||||||
throw new IllegalStateException(String.format(
|
throw new IllegalStateException(
|
||||||
"Failed to end transaction for test context %s: transaction does not exist.", this.testContext));
|
"Failed to end transaction - transaction does not exist: " + this.testContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -136,8 +137,8 @@ class TransactionContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (logger.isInfoEnabled()) {
|
if (logger.isInfoEnabled()) {
|
||||||
logger.info(String.format("%s transaction for test context %s.",
|
logger.info((this.flaggedForRollback ? "Rolled back" : "Committed") +
|
||||||
(this.flaggedForRollback ? "Rolled back" : "Committed"), this.testContext));
|
" transaction for test: " + this.testContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2017 the original author or authors.
|
* Copyright 2002-2018 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -39,11 +39,9 @@ class TransactionContextHolder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static TransactionContext removeCurrentTransactionContext() {
|
static TransactionContext removeCurrentTransactionContext() {
|
||||||
synchronized (currentTransactionContext) {
|
TransactionContext transactionContext = currentTransactionContext.get();
|
||||||
TransactionContext transactionContext = currentTransactionContext.get();
|
currentTransactionContext.remove();
|
||||||
currentTransactionContext.remove();
|
return transactionContext;
|
||||||
return transactionContext;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2016 the original author or authors.
|
* Copyright 2002-2018 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -163,14 +163,12 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void beforeTestMethod(final TestContext testContext) throws Exception {
|
public void beforeTestMethod(final TestContext testContext) throws Exception {
|
||||||
final Method testMethod = testContext.getTestMethod();
|
Method testMethod = testContext.getTestMethod();
|
||||||
final Class<?> testClass = testContext.getTestClass();
|
Class<?> testClass = testContext.getTestClass();
|
||||||
Assert.notNull(testMethod, "The test method of the supplied TestContext must not be null");
|
Assert.notNull(testMethod, "Test method of supplied TestContext must not be null");
|
||||||
|
|
||||||
TransactionContext txContext = TransactionContextHolder.removeCurrentTransactionContext();
|
TransactionContext txContext = TransactionContextHolder.removeCurrentTransactionContext();
|
||||||
if (txContext != null) {
|
Assert.state(txContext == null, "Cannot start new transaction without ending existing transaction");
|
||||||
throw new IllegalStateException("Cannot start a new transaction without ending the existing transaction.");
|
|
||||||
}
|
|
||||||
|
|
||||||
PlatformTransactionManager tm = null;
|
PlatformTransactionManager tm = null;
|
||||||
TransactionAttribute transactionAttribute = this.attributeSource.getTransactionAttribute(testMethod, testClass);
|
TransactionAttribute transactionAttribute = this.attributeSource.getTransactionAttribute(testMethod, testClass);
|
||||||
@@ -180,8 +178,8 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
|||||||
transactionAttribute);
|
transactionAttribute);
|
||||||
|
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Explicit transaction definition [" + transactionAttribute + "] found for test context " +
|
logger.debug("Explicit transaction definition [" + transactionAttribute +
|
||||||
testContext);
|
"] found for test context " + testContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (transactionAttribute.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
|
if (transactionAttribute.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
|
||||||
@@ -191,9 +189,8 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
|||||||
tm = getTransactionManager(testContext, transactionAttribute.getQualifier());
|
tm = getTransactionManager(testContext, transactionAttribute.getQualifier());
|
||||||
|
|
||||||
if (tm == null) {
|
if (tm == null) {
|
||||||
throw new IllegalStateException(String.format(
|
throw new IllegalStateException(
|
||||||
"Failed to retrieve PlatformTransactionManager for @Transactional test for test context %s.",
|
"Failed to retrieve PlatformTransactionManager for @Transactional test: " + testContext);
|
||||||
testContext));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,7 +220,7 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
|||||||
TransactionStatus transactionStatus = txContext.getTransactionStatus();
|
TransactionStatus transactionStatus = txContext.getTransactionStatus();
|
||||||
try {
|
try {
|
||||||
// If the transaction is still active...
|
// If the transaction is still active...
|
||||||
if ((transactionStatus != null) && !transactionStatus.isCompleted()) {
|
if (transactionStatus != null && !transactionStatus.isCompleted()) {
|
||||||
txContext.endTransaction();
|
txContext.endTransaction();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -380,15 +377,15 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
|||||||
TransactionConfigurationAttributes txConfigAttributes = retrieveConfigurationAttributes(testContext);
|
TransactionConfigurationAttributes txConfigAttributes = retrieveConfigurationAttributes(testContext);
|
||||||
|
|
||||||
if (rollbackPresent && txConfigAttributes != defaultTxConfigAttributes) {
|
if (rollbackPresent && txConfigAttributes != defaultTxConfigAttributes) {
|
||||||
throw new IllegalStateException(String.format("Test class [%s] is annotated with both @Rollback "
|
throw new IllegalStateException(String.format("Test class [%s] is annotated with both @Rollback " +
|
||||||
+ "and @TransactionConfiguration, but only one is permitted.", testClass.getName()));
|
"and @TransactionConfiguration, but only one is permitted.", testClass.getName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rollbackPresent) {
|
if (rollbackPresent) {
|
||||||
boolean defaultRollback = rollback.value();
|
boolean defaultRollback = rollback.value();
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug(String.format("Retrieved default @Rollback(%s) for test class [%s].", defaultRollback,
|
logger.debug(String.format("Retrieved default @Rollback(%s) for test class [%s].",
|
||||||
testClass.getName()));
|
defaultRollback, testClass.getName()));
|
||||||
}
|
}
|
||||||
return defaultRollback;
|
return defaultRollback;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2016 the original author or authors.
|
* Copyright 2002-2018 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -53,6 +53,42 @@ import static org.junit.Assert.*;
|
|||||||
@DirtiesContext
|
@DirtiesContext
|
||||||
public class PrimaryTransactionManagerTests {
|
public class PrimaryTransactionManagerTests {
|
||||||
|
|
||||||
|
private JdbcTemplate jdbcTemplate;
|
||||||
|
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public void setDataSource(DataSource dataSource1) {
|
||||||
|
this.jdbcTemplate = new JdbcTemplate(dataSource1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@BeforeTransaction
|
||||||
|
public void beforeTransaction() {
|
||||||
|
assertNumUsers(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterTransaction
|
||||||
|
public void afterTransaction() {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertNumUsers(int expected) {
|
||||||
|
assertEquals("Number of rows in the 'user' table", expected,
|
||||||
|
JdbcTestUtils.countRowsInTable(this.jdbcTemplate, "user"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
static class Config {
|
static class Config {
|
||||||
|
|
||||||
@@ -69,54 +105,16 @@ public class PrimaryTransactionManagerTests {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public DataSource dataSource1() {
|
public DataSource dataSource1() {
|
||||||
// @formatter:off
|
|
||||||
return new EmbeddedDatabaseBuilder()
|
return new EmbeddedDatabaseBuilder()
|
||||||
.generateUniqueName(true)
|
.generateUniqueName(true)
|
||||||
.addScript("classpath:/org/springframework/test/context/jdbc/schema.sql")
|
.addScript("classpath:/org/springframework/test/context/jdbc/schema.sql")
|
||||||
.build();
|
.build();
|
||||||
// @formatter:on
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public DataSource dataSource2() {
|
public DataSource dataSource2() {
|
||||||
return new EmbeddedDatabaseBuilder().generateUniqueName(true).build();
|
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"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2016 the original author or authors.
|
* Copyright 2002-2018 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -23,7 +23,6 @@ import org.junit.After;
|
|||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.rules.ExpectedException;
|
import org.junit.rules.ExpectedException;
|
||||||
|
|
||||||
import org.mockito.BDDMockito;
|
import org.mockito.BDDMockito;
|
||||||
|
|
||||||
import org.springframework.core.annotation.AliasFor;
|
import org.springframework.core.annotation.AliasFor;
|
||||||
@@ -53,7 +52,6 @@ public class TransactionalTestExecutionListenerTests {
|
|||||||
private final PlatformTransactionManager tm = mock(PlatformTransactionManager.class);
|
private final PlatformTransactionManager tm = mock(PlatformTransactionManager.class);
|
||||||
|
|
||||||
private final TransactionalTestExecutionListener listener = new TransactionalTestExecutionListener() {
|
private final TransactionalTestExecutionListener listener = new TransactionalTestExecutionListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected PlatformTransactionManager getTransactionManager(TestContext testContext, String qualifier) {
|
protected PlatformTransactionManager getTransactionManager(TestContext testContext, String qualifier) {
|
||||||
return tm;
|
return tm;
|
||||||
@@ -66,110 +64,21 @@ public class TransactionalTestExecutionListenerTests {
|
|||||||
public ExpectedException exception = ExpectedException.none();
|
public ExpectedException exception = ExpectedException.none();
|
||||||
|
|
||||||
|
|
||||||
private void assertBeforeTestMethod(Class<? extends Invocable> clazz) throws Exception {
|
|
||||||
assertBeforeTestMethodWithTransactionalTestMethod(clazz);
|
|
||||||
assertBeforeTestMethodWithNonTransactionalTestMethod(clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertBeforeTestMethodWithTransactionalTestMethod(Class<? extends Invocable> clazz) throws Exception {
|
|
||||||
assertBeforeTestMethodWithTransactionalTestMethod(clazz, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertBeforeTestMethodWithTransactionalTestMethod(Class<? extends Invocable> clazz, boolean invokedInTx)
|
|
||||||
throws Exception {
|
|
||||||
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
|
|
||||||
Invocable instance = clazz.newInstance();
|
|
||||||
given(testContext.getTestInstance()).willReturn(instance);
|
|
||||||
given(testContext.getTestMethod()).willReturn(clazz.getDeclaredMethod("transactionalTest"));
|
|
||||||
|
|
||||||
assertFalse("callback should not have been invoked", instance.invoked());
|
|
||||||
TransactionContextHolder.removeCurrentTransactionContext();
|
|
||||||
listener.beforeTestMethod(testContext);
|
|
||||||
assertEquals(invokedInTx, instance.invoked());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertBeforeTestMethodWithNonTransactionalTestMethod(Class<? extends Invocable> clazz)
|
|
||||||
throws Exception {
|
|
||||||
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
|
|
||||||
Invocable instance = clazz.newInstance();
|
|
||||||
given(testContext.getTestInstance()).willReturn(instance);
|
|
||||||
given(testContext.getTestMethod()).willReturn(clazz.getDeclaredMethod("nonTransactionalTest"));
|
|
||||||
|
|
||||||
assertFalse("callback should not have been invoked", instance.invoked());
|
|
||||||
TransactionContextHolder.removeCurrentTransactionContext();
|
|
||||||
listener.beforeTestMethod(testContext);
|
|
||||||
assertFalse("callback should not have been invoked", instance.invoked());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertAfterTestMethod(Class<? extends Invocable> clazz) throws Exception {
|
|
||||||
assertAfterTestMethodWithTransactionalTestMethod(clazz);
|
|
||||||
assertAfterTestMethodWithNonTransactionalTestMethod(clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertAfterTestMethodWithTransactionalTestMethod(Class<? extends Invocable> clazz) throws Exception {
|
|
||||||
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
|
|
||||||
Invocable instance = clazz.newInstance();
|
|
||||||
given(testContext.getTestInstance()).willReturn(instance);
|
|
||||||
given(testContext.getTestMethod()).willReturn(clazz.getDeclaredMethod("transactionalTest"));
|
|
||||||
|
|
||||||
given(tm.getTransaction(BDDMockito.any(TransactionDefinition.class))).willReturn(new SimpleTransactionStatus());
|
|
||||||
|
|
||||||
assertFalse("callback should not have been invoked", instance.invoked());
|
|
||||||
TransactionContextHolder.removeCurrentTransactionContext();
|
|
||||||
listener.beforeTestMethod(testContext);
|
|
||||||
assertFalse("callback should not have been invoked", instance.invoked());
|
|
||||||
listener.afterTestMethod(testContext);
|
|
||||||
assertTrue("callback should have been invoked", instance.invoked());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertAfterTestMethodWithNonTransactionalTestMethod(Class<? extends Invocable> clazz) throws Exception {
|
|
||||||
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
|
|
||||||
Invocable instance = clazz.newInstance();
|
|
||||||
given(testContext.getTestInstance()).willReturn(instance);
|
|
||||||
given(testContext.getTestMethod()).willReturn(clazz.getDeclaredMethod("nonTransactionalTest"));
|
|
||||||
|
|
||||||
assertFalse("callback should not have been invoked", instance.invoked());
|
|
||||||
TransactionContextHolder.removeCurrentTransactionContext();
|
|
||||||
listener.beforeTestMethod(testContext);
|
|
||||||
listener.afterTestMethod(testContext);
|
|
||||||
assertFalse("callback should not have been invoked", instance.invoked());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertTransactionConfigurationAttributes(Class<?> clazz, String transactionManagerName,
|
|
||||||
boolean defaultRollback) {
|
|
||||||
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
|
|
||||||
|
|
||||||
TransactionConfigurationAttributes attributes = listener.retrieveConfigurationAttributes(testContext);
|
|
||||||
assertNotNull(attributes);
|
|
||||||
assertEquals(transactionManagerName, attributes.getTransactionManagerName());
|
|
||||||
assertEquals(defaultRollback, attributes.isDefaultRollback());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertIsRollback(Class<?> clazz, boolean rollback) throws NoSuchMethodException, Exception {
|
|
||||||
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
|
|
||||||
given(testContext.getTestMethod()).willReturn(clazz.getDeclaredMethod("test"));
|
|
||||||
assertEquals(rollback, listener.isRollback(testContext));
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void cleanUpThreadLocalStateForSubsequentTestClassesInSuite() {
|
public void cleanUpThreadLocalStateForSubsequentTestClassesInSuite() {
|
||||||
TransactionContextHolder.removeCurrentTransactionContext();
|
TransactionContextHolder.removeCurrentTransactionContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* SPR-13895
|
@Test // SPR-13895
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void transactionalTestWithoutTransactionManager() throws Exception {
|
public void transactionalTestWithoutTransactionManager() throws Exception {
|
||||||
TransactionalTestExecutionListener listener = new TransactionalTestExecutionListener() {
|
TransactionalTestExecutionListener listener = new TransactionalTestExecutionListener() {
|
||||||
|
|
||||||
protected PlatformTransactionManager getTransactionManager(TestContext testContext, String qualifier) {
|
protected PlatformTransactionManager getTransactionManager(TestContext testContext, String qualifier) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Class<? extends Invocable> clazz = TransactionalDeclaredOnClassLocallyTestCase.class;
|
Class<? extends Invocable> clazz = TransactionalDeclaredOnClassLocallyTestCase.class;
|
||||||
|
|
||||||
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
|
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
|
||||||
Invocable instance = clazz.newInstance();
|
Invocable instance = clazz.newInstance();
|
||||||
given(testContext.getTestInstance()).willReturn(instance);
|
given(testContext.getTestInstance()).willReturn(instance);
|
||||||
@@ -184,7 +93,7 @@ public class TransactionalTestExecutionListenerTests {
|
|||||||
}
|
}
|
||||||
catch (IllegalStateException e) {
|
catch (IllegalStateException e) {
|
||||||
assertTrue(e.getMessage().startsWith(
|
assertTrue(e.getMessage().startsWith(
|
||||||
"Failed to retrieve PlatformTransactionManager for @Transactional test for test context"));
|
"Failed to retrieve PlatformTransactionManager for @Transactional test"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,7 +112,7 @@ public class TransactionalTestExecutionListenerTests {
|
|||||||
// Note: not actually invoked within a transaction since the test class is
|
// Note: not actually invoked within a transaction since the test class is
|
||||||
// annotated with @MetaTxWithOverride(propagation = NOT_SUPPORTED)
|
// annotated with @MetaTxWithOverride(propagation = NOT_SUPPORTED)
|
||||||
assertBeforeTestMethodWithTransactionalTestMethod(
|
assertBeforeTestMethodWithTransactionalTestMethod(
|
||||||
TransactionalDeclaredOnClassViaMetaAnnotationWithOverrideTestCase.class, false);
|
TransactionalDeclaredOnClassViaMetaAnnotationWithOverrideTestCase.class, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -211,7 +120,7 @@ public class TransactionalTestExecutionListenerTests {
|
|||||||
// Note: not actually invoked within a transaction since the method is
|
// Note: not actually invoked within a transaction since the method is
|
||||||
// annotated with @MetaTxWithOverride(propagation = NOT_SUPPORTED)
|
// annotated with @MetaTxWithOverride(propagation = NOT_SUPPORTED)
|
||||||
assertBeforeTestMethodWithTransactionalTestMethod(
|
assertBeforeTestMethodWithTransactionalTestMethod(
|
||||||
TransactionalDeclaredOnMethodViaMetaAnnotationWithOverrideTestCase.class, false);
|
TransactionalDeclaredOnMethodViaMetaAnnotationWithOverrideTestCase.class, false);
|
||||||
assertBeforeTestMethodWithNonTransactionalTestMethod(TransactionalDeclaredOnMethodViaMetaAnnotationWithOverrideTestCase.class);
|
assertBeforeTestMethodWithNonTransactionalTestMethod(TransactionalDeclaredOnMethodViaMetaAnnotationWithOverrideTestCase.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,8 +224,7 @@ public class TransactionalTestExecutionListenerTests {
|
|||||||
// @TransactionConfiguration. So we actually expect "" as the qualifier here,
|
// @TransactionConfiguration. So we actually expect "" as the qualifier here,
|
||||||
// relying on beforeTestMethod() to properly obtain the actual qualifier via the
|
// relying on beforeTestMethod() to properly obtain the actual qualifier via the
|
||||||
// TransactionAttribute.
|
// TransactionAttribute.
|
||||||
assertTransactionConfigurationAttributes(TransactionalViaMetaAnnotationWithExplicitQualifierTestCase.class, "",
|
assertTransactionConfigurationAttributes(TransactionalViaMetaAnnotationWithExplicitQualifierTestCase.class, "", true);
|
||||||
true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -375,11 +283,95 @@ public class TransactionalTestExecutionListenerTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
private void assertBeforeTestMethod(Class<? extends Invocable> clazz) throws Exception {
|
||||||
|
assertBeforeTestMethodWithTransactionalTestMethod(clazz);
|
||||||
|
assertBeforeTestMethodWithNonTransactionalTestMethod(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertBeforeTestMethodWithTransactionalTestMethod(Class<? extends Invocable> clazz) throws Exception {
|
||||||
|
assertBeforeTestMethodWithTransactionalTestMethod(clazz, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertBeforeTestMethodWithTransactionalTestMethod(Class<? extends Invocable> clazz, boolean invokedInTx)
|
||||||
|
throws Exception {
|
||||||
|
|
||||||
|
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
|
||||||
|
Invocable instance = clazz.newInstance();
|
||||||
|
given(testContext.getTestInstance()).willReturn(instance);
|
||||||
|
given(testContext.getTestMethod()).willReturn(clazz.getDeclaredMethod("transactionalTest"));
|
||||||
|
|
||||||
|
assertFalse("callback should not have been invoked", instance.invoked());
|
||||||
|
TransactionContextHolder.removeCurrentTransactionContext();
|
||||||
|
listener.beforeTestMethod(testContext);
|
||||||
|
assertEquals(invokedInTx, instance.invoked());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertBeforeTestMethodWithNonTransactionalTestMethod(Class<? extends Invocable> clazz) throws Exception {
|
||||||
|
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
|
||||||
|
Invocable instance = clazz.newInstance();
|
||||||
|
given(testContext.getTestInstance()).willReturn(instance);
|
||||||
|
given(testContext.getTestMethod()).willReturn(clazz.getDeclaredMethod("nonTransactionalTest"));
|
||||||
|
|
||||||
|
assertFalse("callback should not have been invoked", instance.invoked());
|
||||||
|
TransactionContextHolder.removeCurrentTransactionContext();
|
||||||
|
listener.beforeTestMethod(testContext);
|
||||||
|
assertFalse("callback should not have been invoked", instance.invoked());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertAfterTestMethod(Class<? extends Invocable> clazz) throws Exception {
|
||||||
|
assertAfterTestMethodWithTransactionalTestMethod(clazz);
|
||||||
|
assertAfterTestMethodWithNonTransactionalTestMethod(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertAfterTestMethodWithTransactionalTestMethod(Class<? extends Invocable> clazz) throws Exception {
|
||||||
|
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
|
||||||
|
Invocable instance = clazz.newInstance();
|
||||||
|
given(testContext.getTestInstance()).willReturn(instance);
|
||||||
|
given(testContext.getTestMethod()).willReturn(clazz.getDeclaredMethod("transactionalTest"));
|
||||||
|
given(tm.getTransaction(BDDMockito.any(TransactionDefinition.class))).willReturn(new SimpleTransactionStatus());
|
||||||
|
|
||||||
|
assertFalse("callback should not have been invoked", instance.invoked());
|
||||||
|
TransactionContextHolder.removeCurrentTransactionContext();
|
||||||
|
listener.beforeTestMethod(testContext);
|
||||||
|
assertFalse("callback should not have been invoked", instance.invoked());
|
||||||
|
listener.afterTestMethod(testContext);
|
||||||
|
assertTrue("callback should have been invoked", instance.invoked());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertAfterTestMethodWithNonTransactionalTestMethod(Class<? extends Invocable> clazz) throws Exception {
|
||||||
|
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
|
||||||
|
Invocable instance = clazz.newInstance();
|
||||||
|
given(testContext.getTestInstance()).willReturn(instance);
|
||||||
|
given(testContext.getTestMethod()).willReturn(clazz.getDeclaredMethod("nonTransactionalTest"));
|
||||||
|
|
||||||
|
assertFalse("callback should not have been invoked", instance.invoked());
|
||||||
|
TransactionContextHolder.removeCurrentTransactionContext();
|
||||||
|
listener.beforeTestMethod(testContext);
|
||||||
|
listener.afterTestMethod(testContext);
|
||||||
|
assertFalse("callback should not have been invoked", instance.invoked());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertTransactionConfigurationAttributes(
|
||||||
|
Class<?> clazz, String transactionManagerName, boolean defaultRollback) {
|
||||||
|
|
||||||
|
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
|
||||||
|
TransactionConfigurationAttributes attributes = listener.retrieveConfigurationAttributes(testContext);
|
||||||
|
|
||||||
|
assertNotNull(attributes);
|
||||||
|
assertEquals(transactionManagerName, attributes.getTransactionManagerName());
|
||||||
|
assertEquals(defaultRollback, attributes.isDefaultRollback());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertIsRollback(Class<?> clazz, boolean rollback) throws NoSuchMethodException, Exception {
|
||||||
|
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
|
||||||
|
given(testContext.getTestMethod()).willReturn(clazz.getDeclaredMethod("test"));
|
||||||
|
assertEquals(rollback, listener.isRollback(testContext));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
private static @interface MetaTransactional {
|
private @interface MetaTransactional {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@@ -394,17 +386,17 @@ public class TransactionalTestExecutionListenerTests {
|
|||||||
|
|
||||||
@BeforeTransaction
|
@BeforeTransaction
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
private static @interface MetaBeforeTransaction {
|
private @interface MetaBeforeTransaction {
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterTransaction
|
@AfterTransaction
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
private static @interface MetaAfterTransaction {
|
private @interface MetaAfterTransaction {
|
||||||
}
|
}
|
||||||
|
|
||||||
@TransactionConfiguration
|
@TransactionConfiguration
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
private static @interface MetaTxConfig {
|
private @interface MetaTxConfig {
|
||||||
|
|
||||||
String transactionManager() default "metaTxMgr";
|
String transactionManager() default "metaTxMgr";
|
||||||
}
|
}
|
||||||
@@ -441,7 +433,6 @@ public class TransactionalTestExecutionListenerTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void transactionalTest() {
|
public void transactionalTest() {
|
||||||
/* no-op */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -454,11 +445,9 @@ public class TransactionalTestExecutionListenerTests {
|
|||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public void transactionalTest() {
|
public void transactionalTest() {
|
||||||
/* no-op */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void nonTransactionalTest() {
|
public void nonTransactionalTest() {
|
||||||
/* no-op */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -471,7 +460,6 @@ public class TransactionalTestExecutionListenerTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void transactionalTest() {
|
public void transactionalTest() {
|
||||||
/* no-op */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -484,11 +472,9 @@ public class TransactionalTestExecutionListenerTests {
|
|||||||
|
|
||||||
@MetaTransactional
|
@MetaTransactional
|
||||||
public void transactionalTest() {
|
public void transactionalTest() {
|
||||||
/* no-op */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void nonTransactionalTest() {
|
public void nonTransactionalTest() {
|
||||||
/* no-op */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -501,7 +487,6 @@ public class TransactionalTestExecutionListenerTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void transactionalTest() {
|
public void transactionalTest() {
|
||||||
/* no-op */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -514,11 +499,9 @@ public class TransactionalTestExecutionListenerTests {
|
|||||||
|
|
||||||
@MetaTxWithOverride(propagation = NOT_SUPPORTED)
|
@MetaTxWithOverride(propagation = NOT_SUPPORTED)
|
||||||
public void transactionalTest() {
|
public void transactionalTest() {
|
||||||
/* no-op */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void nonTransactionalTest() {
|
public void nonTransactionalTest() {
|
||||||
/* no-op */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -531,11 +514,9 @@ public class TransactionalTestExecutionListenerTests {
|
|||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public void transactionalTest() {
|
public void transactionalTest() {
|
||||||
/* no-op */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void nonTransactionalTest() {
|
public void nonTransactionalTest() {
|
||||||
/* no-op */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -548,11 +529,9 @@ public class TransactionalTestExecutionListenerTests {
|
|||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public void transactionalTest() {
|
public void transactionalTest() {
|
||||||
/* no-op */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void nonTransactionalTest() {
|
public void nonTransactionalTest() {
|
||||||
/* no-op */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -565,11 +544,9 @@ public class TransactionalTestExecutionListenerTests {
|
|||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public void transactionalTest() {
|
public void transactionalTest() {
|
||||||
/* no-op */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void nonTransactionalTest() {
|
public void nonTransactionalTest() {
|
||||||
/* no-op */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -582,11 +559,9 @@ public class TransactionalTestExecutionListenerTests {
|
|||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public void transactionalTest() {
|
public void transactionalTest() {
|
||||||
/* no-op */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void nonTransactionalTest() {
|
public void nonTransactionalTest() {
|
||||||
/* no-op */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -611,11 +586,9 @@ public class TransactionalTestExecutionListenerTests {
|
|||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public void transactionalTest() {
|
public void transactionalTest() {
|
||||||
/* no-op */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void nonTransactionalTest() {
|
public void nonTransactionalTest() {
|
||||||
/* no-op */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -624,11 +597,9 @@ public class TransactionalTestExecutionListenerTests {
|
|||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public void transactionalTest() {
|
public void transactionalTest() {
|
||||||
/* no-op */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void nonTransactionalTest() {
|
public void nonTransactionalTest() {
|
||||||
/* no-op */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user