Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix @TestTransaction for self-intercepted invocation #16420

Merged
merged 1 commit into from Apr 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -7,6 +7,7 @@
import javax.inject.Inject;
import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;
import javax.transaction.Status;
import javax.transaction.UserTransaction;

import io.quarkus.narayana.jta.runtime.test.TestTransactionCallback;
Expand All @@ -28,6 +29,14 @@ public class TestTransactionInterceptor {

@AroundInvoke
public Object intercept(InvocationContext context) throws Exception {
// do nothing in case there is already a transaction (e.g. self-intercepted non-private non-test method in test class)
// w/o this check userTransaction.begin() would fail because there is already a tx associated with the current thread
if (userTransaction.getStatus() != Status.STATUS_NO_TRANSACTION) {
return context.proceed();
}

// an exception from proceed() has to be captured to avoid shadowing it in finally() with a exception from rollback()
Throwable caught = null;
try {
userTransaction.begin();
for (TestTransactionCallback i : CALLBACKS) {
Expand All @@ -38,9 +47,19 @@ public Object intercept(InvocationContext context) throws Exception {
i.preRollback();
}
return result;
} catch (Exception | Error e) { // note: "Error" shall mainly address AssertionError
caught = e;
throw e;
} finally {
userTransaction.rollback();
if (caught == null) {
userTransaction.rollback();
} else {
try {
userTransaction.rollback();
} catch (Exception e) {
caught.addSuppressed(e);
}
}
}
}

}
@@ -0,0 +1,44 @@
package io.quarkus.it.panache;

import javax.transaction.Transactional;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.MethodOrderer.MethodName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;

import io.quarkus.test.TestTransaction;
import io.quarkus.test.junit.QuarkusTest;

/**
* Tests that @TestTransaction works as expected when only used for a single test method
*/
@QuarkusTest
@TestMethodOrder(MethodName.class)
public class TestTransactionOnSingleMethodTest {

@Test
@TestTransaction
public void test1() {
Assertions.assertEquals(0, Beer.find("name", "Lager").count());
Beer b = new Beer();
b.name = "Lager";
Beer.persist(b);
}

@Test
@Transactional
public void test2() {
Assertions.assertEquals(0, Beer.find("name", "Lager").count());
Beer b = new Beer();
b.name = "Lager";
Beer.persist(b);
}

@Test
@Transactional
public void test3() {
Assertions.assertEquals(1, Beer.find("name", "Lager").count());
Beer.deleteAll();
}
}
@@ -1,20 +1,22 @@
package io.quarkus.it.panache;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.MethodOrderer.MethodName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;

import io.quarkus.test.TestTransaction;
import io.quarkus.test.junit.QuarkusTest;

/**
* Tests that @TestTransaction works as expected
* Tests that @TestTransaction works as expected when used for the entire class
*/
@QuarkusTest
@TestTransaction
@TestMethodOrder(MethodName.class)
public class TestTransactionTest {

@Test
@TestTransaction
public void test1() {
Assertions.assertEquals(0, Beer.find("name", "Lager").count());
Beer b = new Beer();
Expand All @@ -23,11 +25,20 @@ public void test1() {
}

@Test
@TestTransaction
public void test2() {
Assertions.assertEquals(0, Beer.find("name", "Lager").count());
// interceptor must not choke on this self-intercepted non-test method invocation
intentionallyNonPrivateHelperMethod();
Beer b = new Beer();
b.name = "Lager";
Beer.persist(b);
}

@Test
public void test3() {
Assertions.assertEquals(0, Beer.find("name", "Lager").count());
}

void intentionallyNonPrivateHelperMethod() {
}
}