1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.dbcp2.cpdsadapter;
19
20 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
21 import static org.junit.jupiter.api.Assertions.assertEquals;
22 import static org.junit.jupiter.api.Assertions.assertNotNull;
23 import static org.junit.jupiter.api.Assertions.assertNull;
24 import static org.junit.jupiter.api.Assertions.assertThrows;
25 import static org.junit.jupiter.api.Assertions.assertTrue;
26
27 import java.io.PrintWriter;
28 import java.sql.Connection;
29 import java.sql.PreparedStatement;
30 import java.sql.ResultSet;
31 import java.sql.SQLException;
32 import java.sql.SQLFeatureNotSupportedException;
33 import java.sql.Statement;
34 import java.time.Duration;
35 import java.util.Properties;
36
37 import javax.naming.NamingException;
38 import javax.naming.Reference;
39 import javax.naming.StringRefAddr;
40 import javax.sql.DataSource;
41
42 import org.apache.commons.dbcp2.Constants;
43 import org.apache.commons.dbcp2.DelegatingPreparedStatement;
44 import org.apache.commons.dbcp2.DelegatingStatement;
45 import org.apache.commons.dbcp2.PStmtKey;
46 import org.apache.commons.dbcp2.PoolablePreparedStatement;
47 import org.apache.commons.dbcp2.TestUtils;
48 import org.apache.commons.dbcp2.datasources.SharedPoolDataSource;
49 import org.apache.commons.pool2.impl.DefaultPooledObject;
50 import org.junit.jupiter.api.Assertions;
51 import org.junit.jupiter.api.BeforeEach;
52 import org.junit.jupiter.api.Test;
53
54
55
56
57 public class TestDriverAdapterCPDS {
58
59 private static final class ThreadDbcp367 extends Thread {
60
61 private final DataSource dataSource;
62
63 private volatile boolean failed;
64
65 public ThreadDbcp367(final DataSource dataSource) {
66 this.dataSource = dataSource;
67 }
68
69 public boolean isFailed() {
70 return failed;
71 }
72
73 @Override
74 public void run() {
75 Connection conn = null;
76 try {
77 for (int j = 0; j < 5000; j++) {
78 conn = dataSource.getConnection();
79 conn.close();
80 }
81 } catch (final SQLException sqle) {
82 failed = true;
83 sqle.printStackTrace();
84 }
85 }
86 }
87
88 @SuppressWarnings("resource")
89 private static void checkAfterClose(final Connection element, final PStmtKey pStmtKey) throws SQLException {
90 final ConnectionImpl connectionImpl = (ConnectionImpl) element;
91 assertNull(connectionImpl.getInnermostDelegate());
92 assertNotNull(connectionImpl.getInnermostDelegateInternal());
93 final PooledConnectionImpl pooledConnectionImpl = connectionImpl.getPooledConnectionImpl();
94 assertNotNull(pooledConnectionImpl);
95
96 pooledConnectionImpl.destroyObject(pStmtKey, null);
97 pooledConnectionImpl.destroyObject(pStmtKey, new DefaultPooledObject<>(null));
98 pooledConnectionImpl.destroyObject(pStmtKey, new DefaultPooledObject<>(new DelegatingPreparedStatement(null, null)));
99 }
100
101 private DriverAdapterCPDS pcds;
102
103 @BeforeEach
104 public void setUp() throws Exception {
105 pcds = new DriverAdapterCPDS();
106 pcds.setDriver("org.apache.commons.dbcp2.TesterDriver");
107 pcds.setUrl("jdbc:apache:commons:testdriver");
108 pcds.setUser("foo");
109 pcds.setPassword("bar");
110 pcds.setPoolPreparedStatements(true);
111 }
112
113 @Test
114 void testClose()
115 throws Exception {
116 final Connection[] c = new Connection[10];
117 for (int i = 0; i < c.length; i++) {
118 c[i] = pcds.getPooledConnection().getConnection();
119 }
120
121
122 c[0].close();
123 assertTrue(c[0].isClosed());
124
125 c[0] = pcds.getPooledConnection().getConnection();
126
127 for (final Connection element : c) {
128 element.close();
129 checkAfterClose(element, null);
130 }
131
132
133 for (int i = 0; i < c.length; i++) {
134 c[i] = pcds.getPooledConnection().getConnection();
135 }
136 for (final Connection element : c) {
137 element.close();
138 checkAfterClose(element, null);
139 }
140 }
141
142 @Test
143 void testCloseWithUserName()
144 throws Exception {
145 final Connection[] c = new Connection[10];
146 for (int i = 0; i < c.length; i++) {
147 c[i] = pcds.getPooledConnection("u1", "p1").getConnection();
148 }
149
150
151 c[0].close();
152 assertTrue(c[0].isClosed());
153
154 c[0] = pcds.getPooledConnection("u1", "p1").getConnection();
155
156 for (final Connection element : c) {
157 element.close();
158 checkAfterClose(element, null);
159 }
160
161
162 for (int i = 0; i < c.length; i++) {
163 c[i] = pcds.getPooledConnection("u1", "p1").getConnection();
164 }
165 for (final Connection element : c) {
166 element.close();
167 checkAfterClose(element, null);
168 }
169 }
170
171
172
173
174 @Test
175 void testDbcp367() throws Exception {
176 final ThreadDbcp367[] threads = new ThreadDbcp367[200];
177
178 pcds.setPoolPreparedStatements(true);
179 pcds.setMaxPreparedStatements(-1);
180 pcds.setAccessToUnderlyingConnectionAllowed(true);
181
182 try (final SharedPoolDataSource spds = new SharedPoolDataSource()) {
183 spds.setConnectionPoolDataSource(pcds);
184 spds.setMaxTotal(threads.length + 10);
185 spds.setDefaultMaxWait(Duration.ofMillis(-1));
186 spds.setDefaultMaxIdle(10);
187 spds.setDefaultAutoCommit(Boolean.FALSE);
188
189 spds.setValidationQuery("SELECT 1");
190 spds.setDefaultDurationBetweenEvictionRuns(Duration.ofSeconds(10));
191 spds.setDefaultNumTestsPerEvictionRun(-1);
192 spds.setDefaultTestWhileIdle(true);
193 spds.setDefaultTestOnBorrow(true);
194 spds.setDefaultTestOnReturn(false);
195
196 for (int i = 0; i < threads.length; i++) {
197 threads[i] = new ThreadDbcp367(spds);
198 threads[i].start();
199 }
200
201 for (int i = 0; i < threads.length; i++) {
202 threads[i].join();
203 Assertions.assertFalse(threads[i].isFailed(), "Thread " + i + " has failed");
204 }
205 }
206 }
207
208 @SuppressWarnings("deprecation")
209 @Test
210 void testDeprecatedAccessors() {
211 int i = 0;
212
213 i++;
214 pcds.setMinEvictableIdleTimeMillis(i);
215 assertEquals(i, pcds.getMinEvictableIdleTimeMillis());
216 assertEquals(Duration.ofMillis(i), pcds.getMinEvictableIdleDuration());
217
218 i++;
219 pcds.setTimeBetweenEvictionRunsMillis(i);
220 assertEquals(i, pcds.getTimeBetweenEvictionRunsMillis());
221 assertEquals(Duration.ofMillis(i), pcds.getDurationBetweenEvictionRuns());
222 }
223
224 @Test
225 void testGetObjectInstance() throws Exception {
226 final Reference ref = pcds.getReference();
227 final Object o = pcds.getObjectInstance(ref, null, null, null);
228 assertEquals(pcds.getDriver(), ((DriverAdapterCPDS) o).getDriver());
229 }
230
231 @Test
232 void testGetObjectInstanceChangeDescription() throws Exception {
233 final Reference ref = pcds.getReference();
234 for (int i = 0; i < ref.size(); i++) {
235 if (ref.get(i).getType().equals("description")) {
236 ref.remove(i);
237 break;
238 }
239 }
240 ref.add(new StringRefAddr("description", "anything"));
241 final Object o = pcds.getObjectInstance(ref, null, null, null);
242 assertEquals(pcds.getDescription(), ((DriverAdapterCPDS) o).getDescription());
243 }
244
245 @Test
246 void testGetObjectInstanceNull() throws Exception {
247 final Object o = pcds.getObjectInstance(null, null, null, null);
248 assertNull(o);
249 }
250
251 @Test
252 void testGetParentLogger() {
253 assertThrows(SQLFeatureNotSupportedException.class, pcds::getParentLogger);
254 }
255
256 @Test
257 void testGetReference() throws NamingException {
258 final Reference ref = pcds.getReference();
259 assertEquals(pcds.getDriver(), ref.get("driver").getContent());
260 assertEquals(pcds.getDescription(), ref.get("description").getContent());
261 }
262
263 @Test
264 void testGettersAndSetters() {
265 pcds.setUser("foo");
266 assertEquals("foo", pcds.getUser());
267 pcds.setPassword("bar");
268 assertEquals("bar", pcds.getPassword());
269 pcds.setPassword(new char[] {'a', 'b'});
270 assertArrayEquals(new char[] {'a', 'b'}, pcds.getPasswordCharArray());
271 final PrintWriter pw = new PrintWriter(System.err);
272 pcds.setLogWriter(pw);
273 @SuppressWarnings("resource")
274 final PrintWriter logWriter = pcds.getLogWriter();
275 assertEquals(pw, logWriter);
276 pcds.setLoginTimeout(10);
277 assertEquals(10, pcds.getLoginTimeout());
278 pcds.setMaxIdle(100);
279 assertEquals(100, pcds.getMaxIdle());
280 pcds.setDurationBetweenEvictionRuns(Duration.ofMillis(100));
281 assertEquals(100, pcds.getDurationBetweenEvictionRuns().toMillis());
282 pcds.setNumTestsPerEvictionRun(1);
283 assertEquals(1, pcds.getNumTestsPerEvictionRun());
284 pcds.setMinEvictableIdleDuration(Duration.ofMillis(11));
285 assertEquals(Duration.ofMillis(11), pcds.getMinEvictableIdleDuration());
286 pcds.setDescription("jo");
287 assertEquals("jo", pcds.getDescription());
288 }
289
290
291
292
293 @Test
294 void testIncorrectPassword() throws Exception {
295 pcds.getPooledConnection("u2", "p2").close();
296
297 assertThrows(SQLException.class, () -> pcds.getPooledConnection("u1", "zlsafjk"), "Able to retrieve connection with incorrect password");
298
299
300 final SQLException e = assertThrows(SQLException.class, () -> pcds.getPooledConnection("u1", "x"), "Able to retrieve connection with incorrect password");
301 assertTrue(e.getMessage().startsWith("x is not the correct password"));
302
303
304
305 pcds.getPooledConnection("u1", "p1").close();
306 }
307
308
309
310
311 @Test
312 void testNullValidationQuery() throws Exception {
313 try (final SharedPoolDataSource spds = new SharedPoolDataSource()) {
314 spds.setConnectionPoolDataSource(pcds);
315 spds.setDefaultTestOnBorrow(true);
316 try (final Connection c = spds.getConnection()) {
317
318 }
319 }
320 }
321
322 @Test
323 void testSetConnectionProperties() throws Exception {
324
325 pcds.setUser("bad");
326
327
328 final Properties properties = new Properties();
329 properties.put(Constants.KEY_USER, "foo");
330 properties.put(Constants.KEY_PASSWORD, pcds.getPassword());
331 pcds.setConnectionProperties(properties);
332 pcds.getPooledConnection().close();
333 assertEquals("foo", pcds.getUser());
334
335 properties.put("password", "bad");
336
337 assertEquals("bar", pcds.getPassword());
338
339
340 pcds.getPooledConnection("foo", "bar").close();
341 assertEquals("bar", pcds.getConnectionProperties().getProperty("password"));
342 }
343
344 @Test
345 void testSetConnectionPropertiesConnectionCalled() throws Exception {
346 final Properties properties = new Properties();
347
348 pcds.getPooledConnection().close();
349 assertThrows(IllegalStateException.class, () -> pcds.setConnectionProperties(properties));
350 }
351
352 @Test
353 void testSetConnectionPropertiesNull() throws Exception {
354 pcds.setConnectionProperties(null);
355 }
356
357 @Test
358 void testSetPasswordNull() throws Exception {
359 pcds.setPassword("Secret");
360 assertEquals("Secret", pcds.getPassword());
361 pcds.setPassword((char[]) null);
362 assertNull(pcds.getPassword());
363 }
364
365 @Test
366 void testSetPasswordNullWithConnectionProperties() throws Exception {
367 pcds.setConnectionProperties(new Properties());
368 pcds.setPassword("Secret");
369 assertEquals("Secret", pcds.getPassword());
370 pcds.setPassword((char[]) null);
371 assertNull(pcds.getPassword());
372 }
373
374 @Test
375 void testSetPasswordThenModCharArray() {
376 final char[] pwd = {'a'};
377 pcds.setPassword(pwd);
378 assertEquals("a", pcds.getPassword());
379 pwd[0] = 'b';
380 assertEquals("a", pcds.getPassword());
381 }
382
383 @Test
384 void testSetUserNull() throws Exception {
385 pcds.setUser("Alice");
386 assertEquals("Alice", pcds.getUser());
387 pcds.setUser(null);
388 assertNull(pcds.getUser());
389 }
390
391 @Test
392 void testSetUserNullWithConnectionProperties() throws Exception {
393 pcds.setConnectionProperties(new Properties());
394 pcds.setUser("Alice");
395 assertEquals("Alice", pcds.getUser());
396 pcds.setUser(null);
397 assertNull(pcds.getUser());
398 }
399
400 @Test
401 void testSimple() throws Exception {
402 try (final Connection conn = pcds.getPooledConnection().getConnection()) {
403 assertNotNull(conn);
404 try (final PreparedStatement stmt = conn.prepareStatement("select * from dual")) {
405 assertNotNull(stmt);
406 try (final ResultSet resultSet = stmt.executeQuery()) {
407 assertNotNull(resultSet);
408 assertTrue(resultSet.next());
409 }
410 }
411 }
412 }
413
414 @SuppressWarnings("resource")
415 @Test
416 void testSimpleWithUsername() throws Exception {
417 final Connection connCheck;
418 PStmtKey pStmtKey;
419 try (final Connection conn = pcds.getPooledConnection("u1", "p1").getConnection()) {
420 assertNotNull(conn);
421 connCheck = conn;
422 try (final PreparedStatement stmt = conn.prepareStatement("select * from dual")) {
423 assertNotNull(stmt);
424 final DelegatingStatement delegatingStatement = (DelegatingStatement) stmt;
425 final Statement delegateStatement = delegatingStatement.getDelegate();
426 pStmtKey = TestUtils.getPStmtKey((PoolablePreparedStatement) delegateStatement);
427 assertNotNull(pStmtKey);
428 try (final ResultSet resultSet = stmt.executeQuery()) {
429 assertNotNull(resultSet);
430 assertTrue(resultSet.next());
431 }
432 }
433 }
434 checkAfterClose(connCheck, pStmtKey);
435 }
436
437 @Test
438 void testToStringWithoutConnectionProperties() throws ClassNotFoundException {
439 final DriverAdapterCPDS cleanCpds = new DriverAdapterCPDS();
440 cleanCpds.setDriver("org.apache.commons.dbcp2.TesterDriver");
441 cleanCpds.setUrl("jdbc:apache:commons:testdriver");
442 cleanCpds.setUser("foo");
443 cleanCpds.setPassword("bar");
444 cleanCpds.toString();
445 }
446 }