From 6c2b305516f96eacca248cf9a7d5088f47fe19d3 Mon Sep 17 00:00:00 2001 From: Rafal Niesler Date: Thu, 30 Jun 2016 17:08:26 +0200 Subject: [PATCH] Do not rollback transaction in jUnit @Before and @After methods --- .../transform/TransactionalTransform.groovy | 18 ++++++++- .../TransactionalTransformSpec.groovy | 40 +++++++++++++++++++ 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/grails-core/src/main/groovy/org/grails/transaction/transform/TransactionalTransform.groovy b/grails-core/src/main/groovy/org/grails/transaction/transform/TransactionalTransform.groovy index b6895c99201..62af23822d2 100644 --- a/grails-core/src/main/groovy/org/grails/transaction/transform/TransactionalTransform.groovy +++ b/grails-core/src/main/groovy/org/grails/transaction/transform/TransactionalTransform.groovy @@ -75,6 +75,7 @@ class TransactionalTransform implements ASTTransformation{ private static final String METHOD_EXECUTE = "execute" private static final Set METHOD_NAME_EXCLUDES = new HashSet(Arrays.asList("afterPropertiesSet", "destroy")); private static final Set ANNOTATION_NAME_EXCLUDES = new HashSet(Arrays.asList(PostConstruct.class.getName(), PreDestroy.class.getName(), Transactional.class.getName(), Rollback.class.getName(), "grails.web.controllers.ControllerMethod", NotTransactional.class.getName())); + private static final Set JUNIT_ANNOTATION_NAMES = new HashSet(Arrays.asList("org.junit.Before", "org.junit.After")); private static final String SPEC_CLASS = "spock.lang.Specification"; public static final String PROPERTY_DATA_SOURCE = "datasource" @@ -116,7 +117,8 @@ class TransactionalTransform implements ASTTransformation{ for (MethodNode md in methods) { String methodName = md.getName() int modifiers = md.modifiers - if (!md.isSynthetic() && Modifier.isPublic(modifiers) && !Modifier.isAbstract(modifiers) && !Modifier.isStatic(modifiers)) { + if (!md.isSynthetic() && Modifier.isPublic(modifiers) && !Modifier.isAbstract(modifiers) && + !Modifier.isStatic(modifiers) && !hasJunitAnnotation(md)) { if(hasExcludedAnnotation(md)) continue def startsWithSpock = methodName.startsWith('$spock') @@ -138,7 +140,8 @@ class TransactionalTransform implements ASTTransformation{ if(hasAnnotation(md, DelegatingMethod.class)) continue weaveTransactionalMethod(source, classNode, annotationNode, md); } - else if(("setup".equals(methodName) || "cleanup".equals(methodName)) && isSpockTest(classNode)) { + else if ((("setup".equals(methodName) || "cleanup".equals(methodName)) && isSpockTest(classNode)) || + hasJunitAnnotation(md)) { def requiresNewTransaction = new AnnotationNode(annotationNode.classNode) requiresNewTransaction.addMember("propagation", new PropertyExpression(new ClassExpression(ClassHelper.make(Propagation.class)), "REQUIRES_NEW")) weaveTransactionalMethod(source, classNode, requiresNewTransaction, md, "execute") @@ -161,6 +164,17 @@ class TransactionalTransform implements ASTTransformation{ excludedAnnotation } + private boolean hasJunitAnnotation(MethodNode md) { + boolean excludedAnnotation = false; + for (AnnotationNode annotation : md.getAnnotations()) { + if(JUNIT_ANNOTATION_NAMES.contains(annotation.getClassNode().getName())) { + excludedAnnotation = true; + break; + } + } + excludedAnnotation + } + ClassNode getAnnotationClassNode(String annotationName) { try { final classLoader = Thread.currentThread().contextClassLoader diff --git a/grails-core/src/test/groovy/grails/transaction/TransactionalTransformSpec.groovy b/grails-core/src/test/groovy/grails/transaction/TransactionalTransformSpec.groovy index efda46447fb..b02639a2601 100644 --- a/grails-core/src/test/groovy/grails/transaction/TransactionalTransformSpec.groovy +++ b/grails-core/src/test/groovy/grails/transaction/TransactionalTransformSpec.groovy @@ -94,6 +94,46 @@ class TransactionalTransformSpec extends Specification { } + void "Test @Rollback when applied to JUnit specifications"() { + when: + Class mySpec = new GroovyShell().evaluate(''' + import grails.transaction.* + import org.junit.Test + import org.junit.Before + import org.junit.After + + @Rollback + class MyJunitTest { + @Before + def junitSetup() { + + } + + @After + def junitCleanup() { + + } + + @Test + void junitTest() { + expect: + 1 == 1 + } + } + MyJunitTest + ''') + + then: "It implements TransactionManagerAware" + TransactionManagerAware.isAssignableFrom(mySpec) + mySpec.getDeclaredMethod('junitSetup') + mySpec.getDeclaredMethod('$tt__junitSetup', TransactionStatus) + mySpec.getDeclaredMethod('junitCleanup') + mySpec.getDeclaredMethod('$tt__junitCleanup', TransactionStatus) + + mySpec.getDeclaredMethod('junitTest') + mySpec.getDeclaredMethod('$tt__junitTest', TransactionStatus) + } + void "Test @Rollback when applied to Spock specifications"() { when: "A new instance of a class with a @Transactional method is created that subclasses another transactional class" Class mySpec = new GroovyShell().evaluate('''