1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.dbcp2;
18
19 import static org.junit.jupiter.api.Assertions.assertEquals;
20 import static org.junit.jupiter.api.Assertions.assertNotNull;
21 import static org.junit.jupiter.api.Assertions.fail;
22
23 import java.sql.Connection;
24 import java.sql.SQLException;
25 import java.util.ArrayList;
26
27 import javax.management.OperationsException;
28
29 import org.apache.commons.pool2.impl.GenericObjectPool;
30 import org.junit.jupiter.api.AfterEach;
31 import org.junit.jupiter.api.Assertions;
32 import org.junit.jupiter.api.BeforeEach;
33 import org.junit.jupiter.api.Test;
34
35
36
37 public class TestPoolableConnection {
38
39 private GenericObjectPool<PoolableConnection> pool;
40
41 @BeforeEach
42 public void setUp() throws Exception {
43 final PoolableConnectionFactory factory = new PoolableConnectionFactory(
44 new DriverConnectionFactory(
45 new TesterDriver(),"jdbc:apache:commons:testdriver", null),
46 null);
47 factory.setDefaultAutoCommit(Boolean.TRUE);
48 factory.setDefaultReadOnly(Boolean.TRUE);
49
50 pool = new GenericObjectPool<>(factory);
51 factory.setPool(pool);
52 }
53
54 @AfterEach
55 public void tearDown() {
56 pool.close();
57 }
58
59 @Test
60 public void testClosingWrappedInDelegate() throws Exception {
61 Assertions.assertEquals(0, pool.getNumActive());
62
63 final Connection conn = pool.borrowObject();
64 final DelegatingConnection<Connection> outer = new DelegatingConnection<>(conn);
65
66 Assertions.assertFalse(outer.isClosed());
67 Assertions.assertFalse(conn.isClosed());
68 Assertions.assertEquals(1, pool.getNumActive());
69
70 outer.close();
71
72 Assertions.assertTrue(outer.isClosed());
73 Assertions.assertTrue(conn.isClosed());
74 Assertions.assertEquals(0, pool.getNumActive());
75 Assertions.assertEquals(1, pool.getNumIdle());
76 }
77
78 @Test
79 public void testConnectionPool() throws Exception {
80
81 final Connection c = pool.borrowObject();
82
83 assertNotNull(c, "Connection should be created and should not be null");
84 assertEquals(1, pool.getNumActive(), "There should be exactly one active object in the pool");
85
86
87 c.close();
88
89 assertEquals(0, pool.getNumActive(), "There should now be zero active objects in the pool");
90 }
91
92 @Test
93 public void testFastFailValidation() throws Exception {
94 pool.setTestOnReturn(true);
95 final PoolableConnectionFactory factory = (PoolableConnectionFactory) pool.getFactory();
96 factory.setFastFailValidation(true);
97 final PoolableConnection conn = pool.borrowObject();
98 final TesterConnection nativeConnection = (TesterConnection) conn.getInnermostDelegate();
99
100
101 nativeConnection.setFailure(new SQLException("Not fatal error.", "Invalid syntax."));
102 try {
103 conn.createStatement();
104 fail("Should throw SQL exception.");
105 } catch (final SQLException ignored) {
106
107 nativeConnection.setFailure(null);
108 }
109
110
111 conn.validate("SELECT 1", 1000);
112
113
114 nativeConnection.setFailure(new SQLException("Fatal connection error.", "01002"));
115
116 try {
117 conn.createStatement();
118 fail("Should throw SQL exception.");
119 } catch (final SQLException ignored) {
120
121 nativeConnection.setFailure(null);
122 }
123
124
125 try {
126 conn.validate("SELECT 1", 1000);
127 fail("Should throw SQL exception on validation.");
128 } catch (final SQLException notValid){
129
130 }
131
132
133 conn.close();
134 assertEquals(0, pool.getNumActive(), "The pool should have no active connections");
135 assertEquals(0, pool.getNumIdle(), "The pool should have no idle connections");
136 }
137
138 @Test
139 public void testFastFailValidationCustomCodes() throws Exception {
140 pool.setTestOnReturn(true);
141 final PoolableConnectionFactory factory = (PoolableConnectionFactory) pool.getFactory();
142 factory.setFastFailValidation(true);
143 final ArrayList<String> disconnectionSqlCodes = new ArrayList<>();
144 disconnectionSqlCodes.add("XXX");
145 factory.setDisconnectionSqlCodes(disconnectionSqlCodes);
146 final PoolableConnection conn = pool.borrowObject();
147 final TesterConnection nativeConnection = (TesterConnection) conn.getInnermostDelegate();
148
149
150 nativeConnection.setFailure(new SQLException("Fatal connection error.", "XXX"));
151
152 try {
153 conn.createStatement();
154 fail("Should throw SQL exception.");
155 } catch (final SQLException ignored) {
156
157 nativeConnection.setFailure(null);
158 }
159
160
161 conn.close();
162 assertEquals(0, pool.getNumActive(), "The pool should have no active connections");
163 assertEquals(0, pool.getNumIdle(), "The pool should have no idle connections");
164 }
165
166 @Test
167 public void testIsDisconnectionSqlExceptionStackOverflow() throws Exception {
168 final int maxDeep = 100_000;
169 final SQLException rootException = new SQLException("Data truncated", "22001");
170 SQLException parentException = rootException;
171 for (int i = 0; i <= maxDeep; i++) {
172 final SQLException childException = new SQLException("Data truncated: " + i, "22001");
173 parentException.setNextException(childException);
174 parentException = childException;
175 }
176 final Connection conn = pool.borrowObject();
177 assertEquals(false, ((PoolableConnection) conn).isDisconnectionSqlException(rootException));
178 assertEquals(false, ((PoolableConnection) conn).isFatalException(rootException));
179 }
180
181
182
183
184
185 @Test
186 public void testMXBeanCompliance() throws OperationsException {
187 TestBasicDataSourceMXBean.testMXBeanCompliance(PoolableConnectionMXBean.class);
188 }
189
190
191
192 @Test
193 public void testPoolableConnectionLeak() throws Exception {
194
195 final Connection conn = pool.borrowObject();
196
197
198
199 ((PoolableConnection)conn).getInnermostDelegate().close();
200
201
202
203
204
205
206 try {
207 conn.close();
208 } catch (final SQLException e) {
209
210
211 }
212
213 assertEquals(0, pool.getNumActive(), "The pool should have no active connections");
214 }
215 }