From 6c808853645349e4c7037d590db6cc2a1569c397 Mon Sep 17 00:00:00 2001 From: graemerocher Date: Tue, 14 Jul 2020 19:00:08 +0200 Subject: [PATCH] Add transactions to setup / cleanup to restore 1.x behaviour --- .../test/context/TestExecutionListener.java | 40 +++++++++++++++++++ .../AbstractMicronautExtension.java | 20 ++++++++++ ...pringTransactionTestExecutionListener.java | 39 ++++++++++++++---- .../junit5/MicronautJunit5Extension.java | 17 +++++++- .../test/junit5/TransactionalTest.java | 14 +++++++ .../spock/MicronautSpockExtension.java | 15 ++++++- .../GormTransactionalRollbackSpec.groovy | 12 +++++- 7 files changed, 145 insertions(+), 12 deletions(-) diff --git a/test-core/src/main/java/io/micronaut/test/context/TestExecutionListener.java b/test-core/src/main/java/io/micronaut/test/context/TestExecutionListener.java index d585ff091..95e90251c 100644 --- a/test-core/src/main/java/io/micronaut/test/context/TestExecutionListener.java +++ b/test-core/src/main/java/io/micronaut/test/context/TestExecutionListener.java @@ -33,6 +33,46 @@ default void beforeTestClass(TestContext testContext) throws Exception { } + /** + * Executed before the setup method of a test method. + * + * @param testContext the test context + * @throws Exception allows any exception to propagate + */ + default void beforeSetupTest(TestContext testContext) throws Exception { + + } + + /** + * Executed after the setup method of a test method. + * + * @param testContext the test context + * @throws Exception allows any exception to propagate + */ + default void afterSetupTest(TestContext testContext) throws Exception { + + } + + /** + * Executed before the setup method of a test method. + * + * @param testContext the test context + * @throws Exception allows any exception to propagate + */ + default void beforeCleanupTest(TestContext testContext) throws Exception { + + } + + /** + * Executed after the setup method of a test method. + * + * @param testContext the test context + * @throws Exception allows any exception to propagate + */ + default void afterCleanupTest(TestContext testContext) throws Exception { + + } + /** * Executed before a test method is executed (a test method may contain multiple iterations). * diff --git a/test-core/src/main/java/io/micronaut/test/extensions/AbstractMicronautExtension.java b/test-core/src/main/java/io/micronaut/test/extensions/AbstractMicronautExtension.java index 245ad800a..ebcf5daba 100644 --- a/test-core/src/main/java/io/micronaut/test/extensions/AbstractMicronautExtension.java +++ b/test-core/src/main/java/io/micronaut/test/extensions/AbstractMicronautExtension.java @@ -73,6 +73,16 @@ public void beforeTestExecution(TestContext testContext) throws Exception { fireListeners(TestExecutionListener::beforeTestExecution, testContext); } + @Override + public void beforeCleanupTest(TestContext testContext) throws Exception { + fireListeners(TestExecutionListener::beforeCleanupTest, testContext); + } + + @Override + public void afterCleanupTest(TestContext testContext) throws Exception { + fireListeners(TestExecutionListener::afterCleanupTest, testContext); + } + /** {@inheritDoc} */ @Override public void afterTestExecution(TestContext testContext) throws Exception { @@ -91,6 +101,16 @@ public void afterTestClass(TestContext testContext) throws Exception { fireListeners(TestExecutionListener::afterTestClass, testContext); } + @Override + public void beforeSetupTest(TestContext testContext) throws Exception { + fireListeners(TestExecutionListener::beforeSetupTest, testContext); + } + + @Override + public void afterSetupTest(TestContext testContext) throws Exception { + fireListeners(TestExecutionListener::afterSetupTest, testContext); + } + /** {@inheritDoc} */ @Override public void beforeTestMethod(TestContext testContext) throws Exception { diff --git a/test-core/src/main/java/io/micronaut/test/transaction/spring/SpringTransactionTestExecutionListener.java b/test-core/src/main/java/io/micronaut/test/transaction/spring/SpringTransactionTestExecutionListener.java index 8e4ec5bd8..a44cfad35 100644 --- a/test-core/src/main/java/io/micronaut/test/transaction/spring/SpringTransactionTestExecutionListener.java +++ b/test-core/src/main/java/io/micronaut/test/transaction/spring/SpringTransactionTestExecutionListener.java @@ -50,22 +50,35 @@ public class SpringTransactionTestExecutionListener implements TestExecutionList */ public SpringTransactionTestExecutionListener( PlatformTransactionManager transactionManager, - @Property(name = AbstractMicronautExtension.TEST_ROLLBACK) boolean rollback) { + @Property(name = AbstractMicronautExtension.TEST_ROLLBACK, defaultValue = "true") boolean rollback) { this.transactionManager = transactionManager; this.rollback = rollback; + } + + @Override + public void beforeSetupTest(TestContext testContext) { + beforeTestExecution(testContext); + } + + @Override + public void afterSetupTest(TestContext testContext) { + afterTestExecution(false); + } + @Override + public void beforeCleanupTest(TestContext testContext) throws Exception { + beforeTestExecution(testContext); + } + + @Override + public void afterCleanupTest(TestContext testContext) throws Exception { + afterTestExecution(false); } @Override public void afterTestExecution(TestContext testContext) { - if (counter.decrementAndGet() == 0) { - if (rollback) { - transactionManager.rollback(tx); - } else { - transactionManager.commit(tx); - } - } + afterTestExecution(this.rollback); } @Override @@ -74,4 +87,14 @@ public void beforeTestExecution(TestContext testContext) { tx = transactionManager.getTransaction(new DefaultTransactionDefinition()); } } + + private void afterTestExecution(boolean rollback) { + if (counter.decrementAndGet() == 0) { + if (rollback) { + transactionManager.rollback(tx); + } else { + transactionManager.commit(tx); + } + } + } } diff --git a/test-junit5/src/main/java/io/micronaut/test/extensions/junit5/MicronautJunit5Extension.java b/test-junit5/src/main/java/io/micronaut/test/extensions/junit5/MicronautJunit5Extension.java index a7632a895..46e06c54e 100644 --- a/test-junit5/src/main/java/io/micronaut/test/extensions/junit5/MicronautJunit5Extension.java +++ b/test-junit5/src/main/java/io/micronaut/test/extensions/junit5/MicronautJunit5Extension.java @@ -33,6 +33,7 @@ import javax.inject.Named; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.util.*; /** @@ -41,7 +42,7 @@ * @author graemerocher * @since 1.0 */ -public class MicronautJunit5Extension extends AbstractMicronautExtension implements BeforeAllCallback, AfterAllCallback, BeforeEachCallback, AfterEachCallback, ExecutionCondition, BeforeTestExecutionCallback, AfterTestExecutionCallback, ParameterResolver { +public class MicronautJunit5Extension extends AbstractMicronautExtension implements BeforeAllCallback, AfterAllCallback, BeforeEachCallback, AfterEachCallback, ExecutionCondition, BeforeTestExecutionCallback, AfterTestExecutionCallback, ParameterResolver, InvocationInterceptor { private static final ExtensionContext.Namespace NAMESPACE = ExtensionContext.Namespace.create(MicronautJunit5Extension.class); @Override @@ -60,6 +61,20 @@ public void beforeAll(ExtensionContext extensionContext) throws Exception { beforeTestClass(buildContext(extensionContext)); } + @Override + public void interceptBeforeEachMethod(Invocation invocation, ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext) throws Throwable { + beforeSetupTest(buildContext(extensionContext)); + invocation.proceed(); + afterSetupTest(buildContext(extensionContext)); + } + + @Override + public void interceptAfterEachMethod(Invocation invocation, ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext) throws Throwable { + beforeCleanupTest(buildContext(extensionContext)); + invocation.proceed(); + afterCleanupTest(buildContext(extensionContext)); + } + @Override public void afterAll(ExtensionContext extensionContext) throws Exception { afterTestClass(buildContext(extensionContext)); diff --git a/test-junit5/src/test/java/io/micronaut/test/junit5/TransactionalTest.java b/test-junit5/src/test/java/io/micronaut/test/junit5/TransactionalTest.java index bb5ea2bcf..c4611a74c 100644 --- a/test-junit5/src/test/java/io/micronaut/test/junit5/TransactionalTest.java +++ b/test-junit5/src/test/java/io/micronaut/test/junit5/TransactionalTest.java @@ -19,8 +19,12 @@ import io.micronaut.test.annotation.MicronautTest; import io.micronaut.test.transaction.spring.SpringTransactionTestExecutionListener; import javax.inject.Inject; + +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.transaction.support.TransactionSynchronizationManager; @MicronautTest(transactional = true) @DbProperties @@ -29,6 +33,16 @@ class TransactionalTest { @Inject ApplicationContext applicationContext; + @BeforeEach + void setup() { + Assertions.assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + } + + @AfterEach + void cleanup() { + Assertions.assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); + } + @Test void testSpringTransactionListenerMissing() { Assertions.assertTrue(applicationContext.containsBean(SpringTransactionTestExecutionListener.class)); diff --git a/test-spock/src/main/java/io/micronaut/test/extensions/spock/MicronautSpockExtension.java b/test-spock/src/main/java/io/micronaut/test/extensions/spock/MicronautSpockExtension.java index cc9b12e4b..173c7ff74 100644 --- a/test-spock/src/main/java/io/micronaut/test/extensions/spock/MicronautSpockExtension.java +++ b/test-spock/src/main/java/io/micronaut/test/extensions/spock/MicronautSpockExtension.java @@ -108,6 +108,7 @@ public void visitSpecAnnotation(MicronautTest annotation, SpecInfo spec) { spec.addCleanupSpecInterceptor(invocation -> { afterTestClass(buildContext(invocation, null)); afterClass(invocation); + invocation.proceed(); singletonMocks.clear(); }); @@ -123,7 +124,12 @@ public void visitSpecAnnotation(MicronautTest annotation, SpecInfo spec) { for (Object mock : singletonMocks) { mockUtil.attachMock(mock, (Specification) instance); } - invocation.proceed(); + try { + beforeSetupTest(buildContext(invocation, null)); + invocation.proceed(); + } finally { + afterSetupTest(buildContext(invocation, null)); + } }); spec.addCleanupInterceptor(invocation -> { @@ -135,7 +141,12 @@ public void visitSpecAnnotation(MicronautTest annotation, SpecInfo spec) { } creatableMocks.clear(); afterEach(invocation); - invocation.proceed(); + try { + beforeCleanupTest(buildContext(invocation, null)); + invocation.proceed(); + } finally { + afterCleanupTest(buildContext(invocation, null)); + } }); } diff --git a/test-spock/src/test/groovy/io/micronaut/test/spock/GormTransactionalRollbackSpec.groovy b/test-spock/src/test/groovy/io/micronaut/test/spock/GormTransactionalRollbackSpec.groovy index b8a79a3cd..a85330bdd 100644 --- a/test-spock/src/test/groovy/io/micronaut/test/spock/GormTransactionalRollbackSpec.groovy +++ b/test-spock/src/test/groovy/io/micronaut/test/spock/GormTransactionalRollbackSpec.groovy @@ -18,10 +18,10 @@ package io.micronaut.test.spock import io.micronaut.context.ApplicationContext import io.micronaut.context.annotation.Property import io.micronaut.core.util.StringUtils -import io.micronaut.inject.qualifiers.Qualifiers import io.micronaut.test.annotation.MicronautTest import io.micronaut.test.spock.entities.Book import io.micronaut.test.transaction.spring.SpringTransactionTestExecutionListener +import org.springframework.transaction.support.TransactionSynchronizationManager import spock.lang.Specification import spock.lang.Stepwise @@ -44,6 +44,16 @@ class GormTransactionalRollbackSpec extends Specification { @Inject ApplicationContext applicationContext + def setup() { + // check transaction is present in setup + assert TransactionSynchronizationManager.isSynchronizationActive() + } + + def cleanup() { + // check transaction is present in setup + assert TransactionSynchronizationManager.isSynchronizationActive() + } + void "bean SpringTransactionTestExecutionListener exists"() { expect: applicationContext.containsBean(SpringTransactionTestExecutionListener)