diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/transaction/AbstractTransactionLifecycleTest.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/transaction/AbstractTransactionLifecycleTest.java index d0ae0a106acbf6..3e732a8ebaf559 100644 --- a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/transaction/AbstractTransactionLifecycleTest.java +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/transaction/AbstractTransactionLifecycleTest.java @@ -2,6 +2,9 @@ import static org.assertj.core.api.Assertions.assertThat; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -10,6 +13,8 @@ import java.util.logging.Level; import javax.persistence.EntityManager; +import javax.persistence.ParameterMode; +import javax.persistence.StoredProcedureQuery; import org.hibernate.BaseSessionEventListener; import org.hibernate.Session; @@ -17,13 +22,17 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.jboss.shrinkwrap.api.ShrinkWrap; import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; +import io.agroal.api.AgroalDataSource; +import io.quarkus.arc.Arc; import io.quarkus.test.QuarkusUnitTest; /** - * Check transaction lifecycle, including session flushes and the closing of the session. + * Check transaction lifecycle, including session flushes, the closing of the session, + * and the release of JDBC resources. */ public abstract class AbstractTransactionLifecycleTest { @@ -39,6 +48,17 @@ public abstract class AbstractTransactionLifecycleTest { .setLogRecordPredicate(record -> record.getLevel().intValue() >= Level.WARNING.intValue()) .assertLogRecords(records -> assertThat(records).isEmpty()); + @BeforeAll + public static void installStoredProcedure() throws SQLException { + AgroalDataSource dataSource = Arc.container().instance(AgroalDataSource.class).get(); + try (Connection conn = dataSource.getConnection()) { + try (Statement st = conn.createStatement()) { + st.execute("CREATE ALIAS " + MyStoredProcedure.NAME + + " FOR \"" + MyStoredProcedure.class.getName() + ".execute\""); + } + } + } + @Test public void testLifecycle() { long id = 1L; @@ -73,6 +93,13 @@ public void testLifecycle() { LifecycleOperation.TRANSACTION_COMPLETION); assertThat(retrieved.value).isEqualTo(UPDATED_NAME); + // See https://github.com/quarkusio/quarkus/issues/13273 + ValueAndExecutionMetadata calledStoredProcedure = crud.callStoredProcedure(id); + checkPostConditions(calledStoredProcedure, + // Strangely, calling a stored procedure isn't considered as a statement for Hibernate ORM listeners + LifecycleOperation.TRANSACTION_COMPLETION); + assertThat(calledStoredProcedure.value).isEqualTo(MyStoredProcedure.execute(id)); + ValueAndExecutionMetadata deleted = crud.delete(id); checkPostConditions(deleted, LifecycleOperation.STATEMENT, // select @@ -119,6 +146,16 @@ public ValueAndExecutionMetadata retrieve(long id) { }); } + public ValueAndExecutionMetadata callStoredProcedure(long id) { + return inTransaction(entityManager -> { + StoredProcedureQuery storedProcedure = entityManager.createStoredProcedureQuery(MyStoredProcedure.NAME); + storedProcedure.registerStoredProcedureParameter(0, Long.class, ParameterMode.IN); + storedProcedure.setParameter(0, id); + storedProcedure.execute(); + return (String) storedProcedure.getSingleResult(); + }); + } + public ValueAndExecutionMetadata update(long id, String name) { return inTransaction(entityManager -> { SimpleEntity entity = entityManager.find(SimpleEntity.class, id); @@ -183,4 +220,14 @@ private enum LifecycleOperation { FLUSH, TRANSACTION_COMPLETION; } + + public static class MyStoredProcedure { + private static final String NAME = "myStoredProc"; + private static final String RESULT_PREFIX = "StoredProcResult"; + + @SuppressWarnings("unused") + public static String execute(long id) { + return RESULT_PREFIX + id; + } + } } diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/transaction/TransactionAnnotationLifecycleTest.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/transaction/TransactionAnnotationLifecycleTest.java index da7eabe2504c4c..c1e1c63b927da1 100644 --- a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/transaction/TransactionAnnotationLifecycleTest.java +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/transaction/TransactionAnnotationLifecycleTest.java @@ -22,8 +22,7 @@ protected TestCRUD crud() { @Override protected boolean expectDoubleFlush() { - // FIXME: We expect double flushes in this case, but that's a bug - return true; + return false; } @ApplicationScoped @@ -43,6 +42,12 @@ public ValueAndExecutionMetadata retrieve(long id) { return super.retrieve(id); } + @Override + @Transactional + public ValueAndExecutionMetadata callStoredProcedure(long id) { + return super.callStoredProcedure(id); + } + @Override @Transactional public ValueAndExecutionMetadata update(long id, String name) { diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/transaction/UserTransactionLifecycleTest.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/transaction/UserTransactionLifecycleTest.java index bfd7ebcca69865..0aa6e612f07a1f 100644 --- a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/transaction/UserTransactionLifecycleTest.java +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/transaction/UserTransactionLifecycleTest.java @@ -27,8 +27,7 @@ protected TestCRUD crud() { @Override protected boolean expectDoubleFlush() { - // FIXME: We expect double flushes in this case, but that's a bug - return true; + return false; } @ApplicationScoped