Skip to content

Commit d726dcb

Browse files
yrodiereSanne
authored andcommitted
HHH-14326 Test JDBC resources are released before closing the connection
Signed-off-by: Yoann Rodière <[email protected]>
1 parent e5c830d commit d726dcb

File tree

2 files changed

+63
-76
lines changed

2 files changed

+63
-76
lines changed

hibernate-core/src/test/java/org/hibernate/test/connections/BeforeCompletionReleaseTest.java

Lines changed: 62 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -7,40 +7,55 @@
77

88
package org.hibernate.test.connections;
99

10+
import java.sql.Connection;
11+
import java.sql.SQLException;
12+
import java.sql.Statement;
13+
import java.util.Map;
14+
import javax.persistence.Entity;
15+
import javax.persistence.Id;
16+
import javax.persistence.Table;
17+
import javax.transaction.RollbackException;
18+
import javax.transaction.SystemException;
19+
import javax.transaction.xa.XAException;
20+
import javax.transaction.xa.XAResource;
21+
1022
import org.hibernate.cfg.AvailableSettings;
1123
import org.hibernate.dialect.H2Dialect;
1224
import org.hibernate.engine.jdbc.connections.internal.UserSuppliedConnectionProviderImpl;
1325
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
1426
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
27+
import org.hibernate.resource.jdbc.spi.LogicalConnectionImplementor;
1528
import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
1629
import org.hibernate.testing.RequiresDialect;
30+
import org.hibernate.testing.TestForIssue;
1731
import org.hibernate.testing.env.ConnectionProviderBuilder;
1832
import org.hibernate.testing.jta.TestingJtaBootstrap;
1933
import org.hibernate.testing.jta.TestingJtaPlatformImpl;
20-
import org.hibernate.testing.transaction.TransactionUtil;
34+
import org.hibernate.testing.transaction.TransactionUtil2;
35+
import org.junit.Rule;
2136
import org.junit.Test;
2237

23-
import javax.persistence.Entity;
24-
import javax.persistence.Id;
25-
import javax.persistence.Table;
26-
import javax.transaction.RollbackException;
27-
import javax.transaction.SystemException;
28-
import javax.transaction.Transaction;
29-
import javax.transaction.xa.XAResource;
30-
import javax.transaction.xa.Xid;
31-
import java.sql.Connection;
32-
import java.sql.SQLException;
33-
import java.util.Map;
38+
import org.mockito.InOrder;
39+
import org.mockito.Mockito;
40+
import org.mockito.junit.MockitoJUnit;
41+
import org.mockito.junit.MockitoRule;
42+
import org.mockito.quality.Strictness;
3443

35-
import static org.junit.Assert.assertTrue;
36-
import static org.junit.Assert.fail;
44+
import static org.mockito.ArgumentMatchers.any;
45+
import static org.mockito.ArgumentMatchers.anyBoolean;
46+
import static org.mockito.Mockito.inOrder;
47+
import static org.mockito.Mockito.mock;
48+
import static org.mockito.Mockito.spy;
3749

3850
/**
3951
* @author Luis Barreiro
4052
*/
4153
@RequiresDialect( H2Dialect.class )
4254
public class BeforeCompletionReleaseTest extends BaseEntityManagerFunctionalTestCase {
4355

56+
@Rule
57+
public MockitoRule mockito = MockitoJUnit.rule().strictness( Strictness.STRICT_STUBS );
58+
4459
@Override
4560
protected Map getConfig() {
4661
Map config = super.getConfig();
@@ -56,12 +71,40 @@ protected Class<?>[] getAnnotatedClasses() {
5671
}
5772

5873
@Test
59-
public void testConnectionAcquisitionCount() {
60-
TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> {
74+
@TestForIssue(jiraKey = {"HHH-13976", "HHH-14326"})
75+
public void testResourcesReleasedThenConnectionClosedThenCommit() throws SQLException, XAException {
76+
XAResource transactionSpy = mock( XAResource.class );
77+
Connection[] connectionSpies = new Connection[1];
78+
Statement statementMock = Mockito.mock( Statement.class );
79+
80+
TransactionUtil2.inTransaction( entityManagerFactory(), session -> {
81+
spyOnTransaction( transactionSpy );
82+
6183
Thing thing = new Thing();
6284
thing.setId( 1 );
63-
entityManager.persist( thing );
64-
});
85+
session.persist( thing );
86+
87+
LogicalConnectionImplementor logicalConnection = session.getJdbcCoordinator().getLogicalConnection();
88+
logicalConnection.getResourceRegistry().register( statementMock, true );
89+
connectionSpies[0] = logicalConnection.getPhysicalConnection();
90+
} );
91+
92+
Connection connectionSpy = connectionSpies[0];
93+
94+
// Must close the resources, then the connection, then commit
95+
InOrder inOrder = inOrder( statementMock, connectionSpy, transactionSpy );
96+
inOrder.verify( statementMock ).close();
97+
inOrder.verify( connectionSpy ).close();
98+
inOrder.verify( transactionSpy ).commit( any(), anyBoolean() );
99+
}
100+
101+
private void spyOnTransaction(XAResource xaResource) {
102+
try {
103+
TestingJtaPlatformImpl.transactionManager().getTransaction().enlistResource( xaResource );
104+
}
105+
catch (RollbackException | SystemException e) {
106+
throw new IllegalStateException( e );
107+
}
65108
}
66109

67110
// --- //
@@ -94,63 +137,7 @@ public ConnectionProviderDecorator() {
94137

95138
@Override
96139
public Connection getConnection() throws SQLException {
97-
Connection connection = dataSource.getConnection();
98-
99-
try {
100-
Transaction tx = TestingJtaPlatformImpl.transactionManager().getTransaction();
101-
if ( tx != null) {
102-
tx.enlistResource( new XAResource() {
103-
104-
@Override public void commit(Xid xid, boolean onePhase) {
105-
try {
106-
assertTrue( "Connection should be closed prior to commit", connection.isClosed() );
107-
} catch ( SQLException e ) {
108-
fail( "Unexpected SQLException: " + e.getMessage() );
109-
}
110-
}
111-
112-
@Override public void end(Xid xid, int flags) {
113-
}
114-
115-
@Override public void forget(Xid xid) {
116-
}
117-
118-
@Override public int getTransactionTimeout() {
119-
return 0;
120-
}
121-
122-
@Override public boolean isSameRM(XAResource xares) {
123-
return false;
124-
}
125-
126-
@Override public int prepare(Xid xid) {
127-
return 0;
128-
}
129-
130-
@Override public Xid[] recover(int flag) {
131-
return new Xid[0];
132-
}
133-
134-
@Override public void rollback(Xid xid) {
135-
try {
136-
assertTrue( "Connection should be closed prior to rollback", connection.isClosed() );
137-
} catch ( SQLException e ) {
138-
fail( "Unexpected SQLException: " + e.getMessage() );
139-
}
140-
}
141-
142-
@Override public boolean setTransactionTimeout(int seconds) {
143-
return false;
144-
}
145-
146-
@Override public void start(Xid xid, int flags) {
147-
}
148-
});
149-
}
150-
} catch ( SystemException | RollbackException e ) {
151-
fail( e.getMessage() );
152-
}
153-
return connection;
140+
return spy( dataSource.getConnection() );
154141
}
155142

156143
@Override

hibernate-testing/src/main/java/org/hibernate/testing/TestForIssue.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,5 @@
2323
* The key of a JIRA issue tested.
2424
* @return The jira issue key
2525
*/
26-
String jiraKey();
26+
String[] jiraKey();
2727
}

0 commit comments

Comments
 (0)