View Javadoc
1   /*
2   
3     Licensed to the Apache Software Foundation (ASF) under one or more
4     contributor license agreements.  See the NOTICE file distributed with
5     this work for additional information regarding copyright ownership.
6     The ASF licenses this file to You under the Apache License, Version 2.0
7     (the "License"); you may not use this file except in compliance with
8     the License.  You may obtain a copy of the License at
9   
10        http://www.apache.org/licenses/LICENSE-2.0
11  
12     Unless required by applicable law or agreed to in writing, software
13     distributed under the License is distributed on an "AS IS" BASIS,
14     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15     See the License for the specific language governing permissions and
16     limitations under the License.
17   */
18  package org.apache.commons.dbcp2.managed;
19  
20  import static org.junit.jupiter.api.Assertions.assertEquals;
21  import static org.junit.jupiter.api.Assertions.assertFalse;
22  import static org.junit.jupiter.api.Assertions.assertNotEquals;
23  import static org.junit.jupiter.api.Assertions.assertNotNull;
24  import static org.junit.jupiter.api.Assertions.assertNull;
25  import static org.junit.jupiter.api.Assertions.assertThrows;
26  import static org.junit.jupiter.api.Assertions.assertTrue;
27  
28  import java.sql.Connection;
29  import java.util.Properties;
30  
31  import javax.transaction.TransactionManager;
32  
33  import org.apache.commons.dbcp2.ConnectionFactory;
34  import org.apache.commons.dbcp2.Constants;
35  import org.apache.commons.dbcp2.DelegatingConnection;
36  import org.apache.commons.dbcp2.DriverConnectionFactory;
37  import org.apache.commons.dbcp2.PoolableConnection;
38  import org.apache.commons.dbcp2.PoolableConnectionFactory;
39  import org.apache.commons.dbcp2.PoolingDataSource;
40  import org.apache.commons.dbcp2.TestConnectionPool;
41  import org.apache.commons.dbcp2.TesterDriver;
42  import org.apache.commons.pool2.impl.GenericObjectPool;
43  import org.apache.geronimo.transaction.manager.TransactionManagerImpl;
44  import org.junit.jupiter.api.AfterEach;
45  import org.junit.jupiter.api.Assertions;
46  import org.junit.jupiter.api.BeforeEach;
47  import org.junit.jupiter.api.Test;
48  
49  /**
50   * TestSuite for ManagedDataSource without a transaction in progress.
51   */
52  public class TestManagedDataSource extends TestConnectionPool {
53  
54      protected PoolingDataSource<PoolableConnection> ds;
55  
56      protected GenericObjectPool<PoolableConnection> pool;
57  
58      protected TransactionManager transactionManager;
59  
60      @Override
61      protected Connection getConnection() throws Exception {
62          return ds.getConnection();
63      }
64  
65      @BeforeEach
66      public void setUp() throws Exception {
67          // create a GeronimoTransactionManager for testing
68          transactionManager = new TransactionManagerImpl();
69  
70          // create a driver connection factory
71          final Properties properties = new Properties();
72          properties.setProperty(Constants.KEY_USER, "userName");
73          properties.setProperty(Constants.KEY_PASSWORD, "password");
74          final ConnectionFactory connectionFactory = new DriverConnectionFactory(new TesterDriver(), "jdbc:apache:commons:testdriver", properties);
75  
76          // wrap it with a LocalXAConnectionFactory
77          final XAConnectionFactory xaConnectionFactory = new LocalXAConnectionFactory(transactionManager, connectionFactory);
78  
79          // create the pool object factory
80          final PoolableConnectionFactory factory =
81              new PoolableConnectionFactory(xaConnectionFactory, null);
82          factory.setValidationQuery("SELECT DUMMY FROM DUAL");
83          factory.setDefaultReadOnly(Boolean.TRUE);
84          factory.setDefaultAutoCommit(Boolean.TRUE);
85  
86          // create the pool
87          pool = new GenericObjectPool<>(factory);
88          factory.setPool(pool);
89          pool.setMaxTotal(getMaxTotal());
90          pool.setMaxWait(getMaxWaitDuration());
91  
92          // finally create the datasource
93          ds = new ManagedDataSource<>(pool, xaConnectionFactory.getTransactionRegistry());
94          ds.setAccessToUnderlyingConnectionAllowed(true);
95      }
96  
97      @Override
98      @AfterEach
99      public void tearDown() throws Exception {
100         pool.close();
101         super.tearDown();
102     }
103 
104     /**
105      * Verify the accessToUnderlyingConnectionAllowed properly limits access to the physical connection.
106      */
107     @Test
108     public void testAccessToUnderlyingConnectionAllowed() throws Exception {
109         ds.setAccessToUnderlyingConnectionAllowed(true);
110         try (ManagedConnection<?> connection = (ManagedConnection<?>) newConnection()) {
111             assertTrue(connection.isAccessToUnderlyingConnectionAllowed());
112             assertNotNull(connection.getDelegate());
113             assertNotNull(connection.getInnermostDelegate());
114         }
115 
116         ds.setAccessToUnderlyingConnectionAllowed(false);
117         try (ManagedConnection<?> connection = (ManagedConnection<?>) newConnection()) {
118             assertFalse(connection.isAccessToUnderlyingConnectionAllowed());
119             assertNull(connection.getDelegate());
120             assertNull(connection.getInnermostDelegate());
121         }
122     }
123 
124     @Test
125     public void testConnectionReturnOnCommit() throws Exception {
126         transactionManager.begin();
127         try (DelegatingConnection<?> connectionA = (DelegatingConnection<?>) newConnection()) {
128             // auto close.
129         }
130         transactionManager.commit();
131         assertEquals(1, pool.getBorrowedCount());
132         assertEquals(1, pool.getReturnedCount());
133         assertEquals(0, pool.getNumActive());
134     }
135 
136     @Test
137     public void testManagedConnectionEqualInnermost() throws Exception {
138         ds.setAccessToUnderlyingConnectionAllowed(true);
139         try (DelegatingConnection<?> con = (DelegatingConnection<?>) getConnection()) {
140             @SuppressWarnings("resource")
141             final Connection inner = con.getInnermostDelegate();
142             ds.setAccessToUnderlyingConnectionAllowed(false);
143             final DelegatingConnection<Connection> con2 = new DelegatingConnection<>(inner);
144             assertNotEquals(con2, con);
145             assertTrue(con.innermostDelegateEquals(con2.getInnermostDelegate()));
146             assertTrue(con2.innermostDelegateEquals(inner));
147             assertNotEquals(con, con2);
148         }
149     }
150 
151     @Test
152     public void testManagedConnectionEqualsFail() throws Exception {
153         try (Connection con1 = getConnection(); final Connection con2 = getConnection()) {
154             assertNotEquals(con1, con2);
155         }
156     }
157 
158     @Test
159     public void testManagedConnectionEqualsNull() throws Exception {
160         try (Connection con1 = getConnection()) {
161             final Connection con2 = null;
162             assertNotEquals(con2, con1);
163         }
164     }
165 
166     /*
167     * JIRA: DBCP-198
168     */
169     @Test
170     public void testManagedConnectionEqualsReflexive() throws Exception {
171         try (Connection con = getConnection()) {
172             @SuppressWarnings("resource")
173             final Connection con2 = con;
174             assertEquals(con2, con);
175             assertEquals(con, con2);
176         }
177     }
178 
179     @Test
180     public void testManagedConnectionEqualsSameDelegate() throws Exception {
181         // Get a maximal set of connections from the pool
182         final Connection[] c = new Connection[getMaxTotal()];
183         for (int i = 0; i < c.length; i++) {
184             c[i] = newConnection();
185         }
186         // Close the delegate of one wrapper in the pool
187         ((DelegatingConnection<?>) c[0]).getDelegate().close();
188 
189         // Grab a new connection - should get c[0]'s closed connection
190         // so should be delegate-equivalent
191         try (Connection con = newConnection()) {
192             Assertions.assertNotEquals(c[0], con);
193             Assertions.assertEquals(((DelegatingConnection<?>) c[0]).getInnermostDelegateInternal(),
194                 ((DelegatingConnection<?>) con).getInnermostDelegateInternal());
195             for (final Connection element : c) {
196                 element.close();
197             }
198         }
199     }
200 
201     @Test
202     public void testManagedConnectionEqualsSameDelegateNoUnderlyingAccess() throws Exception {
203         // Get a maximal set of connections from the pool
204         final Connection[] c = new Connection[getMaxTotal()];
205         for (int i = 0; i < c.length; i++) {
206             c[i] = newConnection();
207         }
208         // Close the delegate of one wrapper in the pool
209         ((DelegatingConnection<?>) c[0]).getDelegate().close();
210 
211         // Disable access for the new connection
212         ds.setAccessToUnderlyingConnectionAllowed(false);
213         // Grab a new connection - should get c[0]'s closed connection
214         // so should be delegate-equivalent
215         try (Connection con = newConnection()) {
216             Assertions.assertNotEquals(c[0], con);
217             Assertions.assertEquals(((DelegatingConnection<?>) c[0]).getInnermostDelegateInternal(),
218                     ((DelegatingConnection<?>) con).getInnermostDelegateInternal());
219             for (final Connection element : c) {
220                 element.close();
221             }
222             ds.setAccessToUnderlyingConnectionAllowed(true);
223         }
224     }
225 
226     @Test
227     public void testManagedConnectionEqualsType() throws Exception {
228         try (Connection con1 = getConnection()) {
229             final Integer con2 = 0;
230             assertNotEquals(con2, con1);
231         }
232     }
233 
234     @Test
235     public void testNestedConnections() throws Exception {
236         transactionManager.begin();
237         try (Connection c1 = newConnection(); final Connection c2 = newConnection()) {
238             transactionManager.commit();
239         }
240     }
241 
242     @Test
243     public void testSetNullTransactionRegistry() throws Exception {
244         try (ManagedDataSource<?> ds = new ManagedDataSource<>(pool, null)) {
245             assertThrows(NullPointerException.class, () -> ds.setTransactionRegistry(null));
246         }
247     }
248 
249     @Test()
250     public void testSetTransactionRegistry() throws Exception {
251         try (ManagedDataSource<?> ds = new ManagedDataSource<>(pool, null)) {
252             ds.setTransactionRegistry(new TransactionRegistry(transactionManager));
253         }
254     }
255 
256     @Test
257     public void testSetTransactionRegistryAlreadySet() {
258         final ManagedDataSource<?> managed = (ManagedDataSource<?>) ds;
259         assertThrows(IllegalStateException.class, () -> managed.setTransactionRegistry(null));
260     }
261 
262     /**
263      * Verify that connection sharing is working (or not working) as expected.
264      */
265     @Test
266     public void testSharedConnection() throws Exception {
267         try (DelegatingConnection<?> connectionA = (DelegatingConnection<?>) newConnection();
268                 final DelegatingConnection<?> connectionB = (DelegatingConnection<?>) newConnection()) {
269             assertNotEquals(connectionA, connectionB);
270             assertNotEquals(connectionB, connectionA);
271             assertFalse(connectionA.innermostDelegateEquals(connectionB.getInnermostDelegate()));
272             assertFalse(connectionB.innermostDelegateEquals(connectionA.getInnermostDelegate()));
273         }
274     }
275 
276     @Test
277     public void testTransactionRegistryNotInitialized() throws Exception {
278         try (ManagedDataSource<?> ds = new ManagedDataSource<>(pool, null)) {
279             assertThrows(IllegalStateException.class, ds::getConnection);
280         }
281     }
282 }