77
88package 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+
1022import org .hibernate .cfg .AvailableSettings ;
1123import org .hibernate .dialect .H2Dialect ;
1224import org .hibernate .engine .jdbc .connections .internal .UserSuppliedConnectionProviderImpl ;
1325import org .hibernate .engine .jdbc .connections .spi .ConnectionProvider ;
1426import org .hibernate .jpa .test .BaseEntityManagerFunctionalTestCase ;
27+ import org .hibernate .resource .jdbc .spi .LogicalConnectionImplementor ;
1528import org .hibernate .resource .jdbc .spi .PhysicalConnectionHandlingMode ;
1629import org .hibernate .testing .RequiresDialect ;
30+ import org .hibernate .testing .TestForIssue ;
1731import org .hibernate .testing .env .ConnectionProviderBuilder ;
1832import org .hibernate .testing .jta .TestingJtaBootstrap ;
1933import org .hibernate .testing .jta .TestingJtaPlatformImpl ;
20- import org .hibernate .testing .transaction .TransactionUtil ;
34+ import org .hibernate .testing .transaction .TransactionUtil2 ;
35+ import org .junit .Rule ;
2136import 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 )
4254public 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
0 commit comments