View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.dbcp2.datasources;
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.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.ByteArrayInputStream;
28  import java.io.ByteArrayOutputStream;
29  import java.io.ObjectInputStream;
30  import java.io.ObjectOutputStream;
31  import java.sql.Connection;
32  import java.sql.PreparedStatement;
33  import java.sql.ResultSet;
34  import java.sql.SQLException;
35  import java.time.Duration;
36  import java.util.HashMap;
37  import java.util.Map;
38  import java.util.NoSuchElementException;
39  
40  import javax.sql.DataSource;
41  
42  import org.apache.commons.dbcp2.TestConnectionPool;
43  import org.apache.commons.dbcp2.TesterDriver;
44  import org.apache.commons.dbcp2.cpdsadapter.DriverAdapterCPDS;
45  import org.junit.jupiter.api.AfterEach;
46  import org.junit.jupiter.api.BeforeEach;
47  import org.junit.jupiter.api.Test;
48  
49  /**
50   */
51  public class TestPerUserPoolDataSource extends TestConnectionPool {
52  
53      private static final Duration DURATION_1_MILLISECOND = Duration.ofMillis(1);
54  
55      private DataSource ds;
56  
57      private String user;
58  
59      @Override
60      protected Connection getConnection() throws SQLException {
61          return ds.getConnection(user, "bar");
62      }
63  
64      @BeforeEach
65      public void setUp() throws Exception {
66          user = "foo";
67          final DriverAdapterCPDS pcds = new DriverAdapterCPDS();
68          pcds.setDriver("org.apache.commons.dbcp2.TesterDriver");
69          pcds.setUrl("jdbc:apache:commons:testdriver");
70          pcds.setUser(user);
71          pcds.setPassword("bar");
72          pcds.setAccessToUnderlyingConnectionAllowed(true);
73  
74          final PerUserPoolDataSource tds = new PerUserPoolDataSource();
75          tds.setConnectionPoolDataSource(pcds);
76          tds.setDefaultMaxTotal(getMaxTotal());
77          tds.setDefaultMaxWait(getMaxWaitDuration());
78          tds.setPerUserMaxTotal(user, getMaxTotal());
79          tds.setPerUserMaxWait(user, getMaxWaitDuration());
80          tds.setDefaultTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
81          tds.setDefaultAutoCommit(Boolean.TRUE);
82          ds = tds;
83      }
84  
85      @Override
86      @AfterEach
87      public void tearDown() throws Exception {
88          super.tearDown();
89          ((PerUserPoolDataSource) ds).close();
90      }
91  
92      /**
93       * See DBCP-8
94       */
95      @Test
96      void testChangePassword() throws Exception {
97          assertThrows(SQLException.class, () -> ds.getConnection(user, "bay"));
98          final Connection con1 = ds.getConnection(user, "bar");
99          final Connection con2 = ds.getConnection(user, "bar");
100         final Connection con3 = ds.getConnection(user, "bar");
101         con1.close();
102         con2.close();
103         TesterDriver.addUser(user, "bay"); // change the user/password setting
104         try {
105             final Connection con4 = ds.getConnection(user, "bay"); // new password
106             // Idle instances with old password should have been cleared
107             assertEquals(0, ((PerUserPoolDataSource) ds).getNumIdle(user), "Should be no idle connections in the pool");
108             con4.close();
109             // Should be one idle instance with new pwd
110             assertEquals(1, ((PerUserPoolDataSource) ds).getNumIdle(user), "Should be one idle connection in the pool");
111             // old password
112             assertThrows(SQLException.class, () -> ds.getConnection(user, "bar"), "Should have generated SQLException");
113             try (Connection con5 = ds.getConnection(user, "bay")) { // take the idle one
114                 con3.close(); // Return a connection with the old password
115                 ds.getConnection(user, "bay").close(); // will try bad returned connection and destroy it
116                 assertEquals(1, ((PerUserPoolDataSource) ds).getNumIdle(user), "Should be one idle connection in the pool");
117             }
118         } finally {
119             TesterDriver.addUser(user, "bar");
120         }
121     }
122 
123     @Override
124     @Test
125     public void testClosing() throws Exception {
126         final Connection[] c = new Connection[getMaxTotal()];
127         // open the maximum connections
128         for (int i = 0; i < c.length; i++) {
129             c[i] = ds.getConnection();
130         }
131 
132         // close one of the connections
133         c[0].close();
134         assertTrue(c[0].isClosed());
135 
136         // get a new connection
137         c[0] = ds.getConnection();
138 
139         for (final Connection element : c) {
140             element.close();
141         }
142     }
143 
144     @Test
145     void testClosingWithUserName() throws Exception {
146         final Connection[] c = new Connection[getMaxTotal()];
147         // open the maximum connections
148         for (int i = 0; i < c.length; i++) {
149             c[i] = ds.getConnection("u1", "p1");
150         }
151 
152         // close one of the connections
153         c[0].close();
154         assertTrue(c[0].isClosed());
155         // get a new connection
156         c[0] = ds.getConnection("u1", "p1");
157 
158         for (final Connection element : c) {
159             element.close();
160         }
161 
162         // open the maximum connections
163         for (int i = 0; i < c.length; i++) {
164             c[i] = ds.getConnection("u1", "p1");
165         }
166         for (final Connection element : c) {
167             element.close();
168         }
169     }
170 
171     /**
172      * Tests https://issues.apache.org/jira/browse/DBCP-597
173      */
174     @Test
175     void testDbcp597() throws SQLException {
176         final PerUserPoolDataSource tds = (PerUserPoolDataSource) ds;
177         tds.setDefaultTestOnBorrow(true);
178         tds.setValidationQuery("SELECT 1");
179         // The tester statement throws a SQLTimeoutException when the timeout is > 0 and < 5.
180         tds.setValidationQueryTimeout(Duration.ofSeconds(1));
181         // The SQLTimeoutException is lost for now
182         SQLException e = assertThrows(SQLException.class, tds::getConnection);
183         assertEquals(NoSuchElementException.class, e.getCause().getClass());
184         // timeout > 0 and < 1
185         tds.setValidationQueryTimeout(Duration.ofMillis(999));
186         // The SQLTimeoutException is lost for now
187         e = assertThrows(SQLException.class, tds::getConnection);
188         assertEquals(NoSuchElementException.class, e.getCause().getClass());
189     }
190 
191     @Test
192     void testDefaultReadOnly() {
193         try (PerUserPoolDataSource ds = new PerUserPoolDataSource()) {
194             assertNull(ds.isDefaultReadOnly());
195             ds.setDefaultReadOnly(true);
196             assertTrue(ds.isDefaultReadOnly().booleanValue());
197             ds.setDefaultReadOnly(false);
198             assertFalse(ds.isDefaultReadOnly().booleanValue());
199             ds.setDefaultReadOnly(true);
200             assertTrue(ds.isDefaultReadOnly().booleanValue());
201             ds.setDefaultReadOnly(null);
202             assertNull(ds.isDefaultReadOnly());
203         }
204     }
205 
206     // see issue https://issues.apache.org/bugzilla/show_bug.cgi?id=23843
207     @Test
208     void testDefaultUser1() throws Exception {
209         TesterDriver.addUser("mkh", "password");
210         TesterDriver.addUser("hanafey", "password");
211         TesterDriver.addUser("jsmith", "password");
212 
213         final PerUserPoolDataSource puds = (PerUserPoolDataSource) ds;
214         puds.setPerUserMaxTotal("jsmith", 2);
215         final String[] users = { "mkh", "hanafey", "jsmith" };
216         final String password = "password";
217         final Connection[] c = new Connection[users.length];
218         for (int i = 0; i < users.length; i++) {
219             c[i] = puds.getConnection(users[i], password);
220             assertEquals(users[i], getUsername(c[i]));
221         }
222         for (int i = 0; i < users.length; i++) {
223             c[i].close();
224         }
225     }
226 
227     // see issue https://issues.apache.org/bugzilla/show_bug.cgi?id=23843
228     @Test
229     void testDefaultUser2() throws Exception {
230         TesterDriver.addUser("mkh", "password");
231         TesterDriver.addUser("hanafey", "password");
232         TesterDriver.addUser("jsmith", "password");
233 
234         final PerUserPoolDataSource puds = (PerUserPoolDataSource) ds;
235         puds.setPerUserMaxTotal("jsmith", 2);
236         final String[] users = { "jsmith", "hanafey", "mkh" };
237         final String password = "password";
238         final Connection[] c = new Connection[users.length];
239         for (int i = 0; i < users.length; i++) {
240             c[i] = puds.getConnection(users[i], password);
241             assertEquals(users[i], getUsername(c[i]));
242         }
243         for (int i = 0; i < users.length; i++) {
244             c[i].close();
245         }
246     }
247 
248     @SuppressWarnings("deprecation")
249     @Test
250     void testDepreactedAccessors() {
251         try (final PerUserPoolDataSource ds = new PerUserPoolDataSource()) {
252             int i = 0;
253             //
254             i++;
255             ds.setDefaultMaxWaitMillis(i);
256             assertEquals(i, ds.getDefaultMaxWaitMillis());
257             assertEquals(Duration.ofMillis(i), ds.getDefaultMaxWait());
258             //
259             i++;
260             ds.setDefaultMinEvictableIdleTimeMillis(i);
261             assertEquals(i, ds.getDefaultMinEvictableIdleTimeMillis());
262             assertEquals(Duration.ofMillis(i), ds.getDefaultMinEvictableIdleDuration());
263             //
264             i++;
265             ds.setDefaultSoftMinEvictableIdleTimeMillis(i);
266             assertEquals(i, ds.getDefaultSoftMinEvictableIdleTimeMillis());
267             assertEquals(Duration.ofMillis(i), ds.getDefaultSoftMinEvictableIdleDuration());
268             //
269             i++;
270             ds.setDefaultTimeBetweenEvictionRunsMillis(i);
271             assertEquals(i, ds.getDefaultTimeBetweenEvictionRunsMillis());
272             assertEquals(Duration.ofMillis(i), ds.getDefaultDurationBetweenEvictionRuns());
273             //
274             i++;
275             ds.setPerUserMaxWaitMillis(user, Long.valueOf(i));
276             assertEquals(i, ds.getPerUserMaxWaitMillis(user));
277             assertEquals(Duration.ofMillis(i), ds.getPerUserMaxWaitDuration(user));
278             //
279             i++;
280             ds.setPerUserMinEvictableIdleTimeMillis(user, Long.valueOf(i));
281             assertEquals(i, ds.getPerUserMinEvictableIdleTimeMillis(user));
282             assertEquals(Duration.ofMillis(i), ds.getPerUserMinEvictableIdleDuration(user));
283             //
284             i++;
285             ds.setPerUserSoftMinEvictableIdleTimeMillis(user, Long.valueOf(i));
286             assertEquals(i, ds.getPerUserSoftMinEvictableIdleTimeMillis(user));
287             assertEquals(Duration.ofMillis(i), ds.getPerUserSoftMinEvictableIdleDuration(user));
288             //
289             i++;
290             ds.setPerUserTimeBetweenEvictionRunsMillis(user, Long.valueOf(i));
291             assertEquals(i, ds.getPerUserTimeBetweenEvictionRunsMillis(user));
292             assertEquals(Duration.ofMillis(i), ds.getPerUserDurationBetweenEvictionRuns(user));
293         }
294     }
295 
296     /**
297      * Switching 'u1 to 'u2' and 'p1' to 'p2' will exhibit the bug detailed in https://issues.apache.org/bugzilla/show_bug.cgi?id=18905
298      */
299     @Test
300     void testIncorrectPassword() throws SQLException {
301         // Use bad password
302         assertThrows(SQLException.class, () -> ds.getConnection("u1", "zlsafjk"));
303 
304         // Use good password
305         ds.getConnection("u1", "p1").close();
306         final SQLException e = assertThrows(SQLException.class, () -> ds.getConnection("u1", "x"), "Able to retrieve connection with incorrect password");
307         assertTrue(e.getMessage().startsWith("Given password did not match"));
308 
309         // Make sure we can still use our good password.
310         ds.getConnection("u1", "p1").close();
311 
312         // Try related users and passwords
313         ds.getConnection(user, "bar").close();
314         assertThrows(SQLException.class, () -> ds.getConnection("foob", "ar"));
315         assertThrows(SQLException.class, () -> ds.getConnection(user, "baz"));
316     }
317 
318     @Override
319     @Test
320     public void testMaxTotal() throws Exception {
321         final Connection[] c = new Connection[getMaxTotal()];
322         for (int i = 0; i < c.length; i++) {
323             c[i] = ds.getConnection();
324             assertNotNull(c[i]);
325         }
326         // should only be able to open 10 connections, so this test should throw an
327         // exception
328         assertThrows(SQLException.class, ds::getConnection, "Allowed to open more than DefaultMaxTotal connections.");
329         for (final Connection element : c) {
330             element.close();
331         }
332     }
333 
334     /**
335      * Verify that defaultMaxWaitMillis = 0 means immediate failure when pool is exhausted.
336      */
337     @Test
338     void testMaxWaitMillisZero() throws Exception {
339         final PerUserPoolDataSource tds = (PerUserPoolDataSource) ds;
340         tds.setDefaultMaxWait(Duration.ZERO);
341         tds.setPerUserMaxTotal("u1", 1);
342         try (final Connection conn = tds.getConnection("u1", "p1")) {
343             assertThrows(SQLException.class, () -> tds.getConnection("u1", "p1"));
344         }
345     }
346 
347     @Test
348     void testMultipleThreads1() throws Exception {
349         // Override wait time in order to allow for Thread.sleep(1) sometimes taking a lot longer on
350         // some JVMs, e.g. Windows.
351         final Duration defaultMaxWaitDuration = Duration.ofMillis(430);
352         ((PerUserPoolDataSource) ds).setDefaultMaxWait(defaultMaxWaitDuration);
353         ((PerUserPoolDataSource) ds).setPerUserMaxWait(user, defaultMaxWaitDuration);
354         multipleThreads(Duration.ofMillis(1), false, false, defaultMaxWaitDuration);
355     }
356 
357     @Test
358     void testMultipleThreads2() throws Exception {
359         final Duration defaultMaxWaitDuration = Duration.ofMillis(500);
360         ((PerUserPoolDataSource) ds).setDefaultMaxWait(defaultMaxWaitDuration);
361         ((PerUserPoolDataSource) ds).setPerUserMaxWait(user, defaultMaxWaitDuration);
362         multipleThreads(defaultMaxWaitDuration.multipliedBy(2), true, true, defaultMaxWaitDuration);
363     }
364 
365     @Override
366     @Test
367     public void testOpening() throws Exception {
368         final Connection[] c = new Connection[getMaxTotal()];
369         // test that opening new connections is not closing previous
370         for (int i = 0; i < c.length; i++) {
371             c[i] = ds.getConnection();
372             assertNotNull(c[i]);
373             for (int j = 0; j <= i; j++) {
374                 assertFalse(c[j].isClosed());
375             }
376         }
377 
378         for (final Connection element : c) {
379             element.close();
380         }
381     }
382 
383     /**
384      * Test per user block when exhausted, with the backing map initialized before.
385      */
386     @Test
387     void testPerUserBlockWhenExhaustedMapInitialized() {
388         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
389         Map<String, Boolean> userDefaultBlockWhenExhausted = new HashMap<>();
390         userDefaultBlockWhenExhausted.put("key", Boolean.FALSE);
391         ds.setPerUserBlockWhenExhausted(userDefaultBlockWhenExhausted);
392         assertEquals(Boolean.FALSE, ds.getPerUserBlockWhenExhausted("key"));
393         // when the code above is executed, the backing map was initalized
394         // now check if that still works. The backing map is clear'ed.
395         userDefaultBlockWhenExhausted = new HashMap<>();
396         userDefaultBlockWhenExhausted.put("anonymous", Boolean.FALSE);
397         ds.setPerUserBlockWhenExhausted(userDefaultBlockWhenExhausted);
398         // now the previously entered value was cleared, so it will be back to the
399         // default value of TRUE
400         assertEquals(Boolean.TRUE, ds.getPerUserBlockWhenExhausted("key"));
401         // and our new value exists too
402         assertEquals(Boolean.FALSE, ds.getPerUserBlockWhenExhausted("anonymous"));
403     }
404 
405     /**
406      * Test per user block when exhausted, with the backing map not initialized before. Instead we pass the map.
407      */
408     @Test
409     void testPerUserBlockWhenExhaustedMapNotInitialized() {
410         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
411         final Map<String, Boolean> userDefaultBlockWhenExhausted = new HashMap<>();
412         userDefaultBlockWhenExhausted.put("key", Boolean.TRUE);
413         ds.setPerUserBlockWhenExhausted(userDefaultBlockWhenExhausted);
414         assertEquals(Boolean.TRUE, ds.getPerUserBlockWhenExhausted("key"));
415     }
416 
417     /**
418      * Test per user block when exhausted, with the backing map not initialized before. Instead, we pass the map. And furthermore, we are now searching for an
419      * inexistent key, which should return the default value.
420      */
421     @Test
422     void testPerUserBlockWhenExhaustedMapNotInitializedMissingKey() {
423         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
424         final Map<String, Boolean> userDefaultBlockWhenExhausted = new HashMap<>();
425         userDefaultBlockWhenExhausted.put("key", Boolean.FALSE);
426         ds.setPerUserBlockWhenExhausted(userDefaultBlockWhenExhausted);
427         assertEquals(ds.getDefaultBlockWhenExhausted(), ds.getPerUserBlockWhenExhausted("missingkey"));
428     }
429 
430     /**
431      * Test per user block when exhausted, with the backing map not initialized before. Instead we pass the user and value, and hence the map is initialized
432      * beforehand. After that, we pass another user, so both values should still be present. The PerUserPoolDataSource does not clear the perUserPoolDataSource
433      * map, unless you pass a new map, using another internal/package method.
434      */
435     @Test
436     void testPerUserBlockWhenExhaustedWithUserMapInitialized() {
437         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
438         ds.setPerUserBlockWhenExhausted(user, Boolean.FALSE);
439         assertEquals(Boolean.FALSE, ds.getPerUserBlockWhenExhausted(user));
440         // when the code above is executed, the backing map was initalized
441         // now check if that still works. The backing map is NOT clear'ed.
442         ds.setPerUserBlockWhenExhausted("anotheruser", Boolean.FALSE);
443         assertEquals(Boolean.FALSE, ds.getPerUserBlockWhenExhausted(user));
444         assertEquals(Boolean.FALSE, ds.getPerUserBlockWhenExhausted("anotheruser"));
445     }
446 
447     /**
448      * Test per user block when exhausted, with the backing map not initialized before. Instead we pass the user and value, and hence the map is initialized
449      * beforehand.
450      */
451     @Test
452     void testPerUserBlockWhenExhaustedWithUserMapNotInitialized() {
453         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
454         ds.setPerUserBlockWhenExhausted(user, Boolean.FALSE);
455         assertEquals(Boolean.FALSE, ds.getPerUserBlockWhenExhausted(user));
456     }
457 
458     /**
459      * Test per user block when exhausted, with the backing map not initialized before. Instead we pass the user and value, and hence the map is initialized
460      * beforehand. Furthermore, we are now searching for an inexistent key, which should return the default value.
461      */
462     @Test
463     void testPerUserBlockWhenExhaustedWithUserMapNotInitializedMissingKey() {
464         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
465         ds.setPerUserBlockWhenExhausted("whatismyuseragain?", Boolean.FALSE);
466         assertEquals(Boolean.TRUE, ds.getPerUserBlockWhenExhausted("missingkey"));
467     }
468 
469     // getters and setters. Most follow the same pattern. The initial tests contain a more
470     // complete documentation, which can be helpful when write/understanding the other methods.
471 
472     // -- per user block when exhausted
473 
474     @Test
475     void testPerUserDefaultAutoCommitMapInitialized() {
476         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
477         Map<String, Boolean> values = new HashMap<>();
478         values.put("key", Boolean.FALSE);
479         ds.setPerUserDefaultAutoCommit(values);
480         assertEquals(Boolean.FALSE, ds.getPerUserDefaultAutoCommit("key"));
481         values = new HashMap<>();
482         values.put("anonymous", Boolean.FALSE);
483         ds.setPerUserDefaultAutoCommit(values);
484         assertNull(ds.getPerUserDefaultAutoCommit("key"));
485         assertEquals(Boolean.FALSE, ds.getPerUserDefaultAutoCommit("anonymous"));
486     }
487 
488     @Test
489     void testPerUserDefaultAutoCommitMapNotInitialized() {
490         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
491         final Map<String, Boolean> values = new HashMap<>();
492         values.put("key", Boolean.TRUE);
493         ds.setPerUserDefaultAutoCommit(values);
494         assertEquals(Boolean.TRUE, ds.getPerUserDefaultAutoCommit("key"));
495     }
496 
497     @Test
498     void testPerUserDefaultAutoCommitMapNotInitializedMissingKey() {
499         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
500         final Map<String, Boolean> values = new HashMap<>();
501         values.put("key", Boolean.FALSE);
502         ds.setPerUserDefaultAutoCommit(values);
503         // TODO this is not consistent with the other methods
504         assertNull(ds.getPerUserDefaultAutoCommit("missingkey"));
505     }
506 
507     @Test
508     void testPerUserDefaultAutoCommitWithUserMapInitialized() {
509         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
510         ds.setPerUserDefaultAutoCommit(user, Boolean.FALSE);
511         assertEquals(Boolean.FALSE, ds.getPerUserDefaultAutoCommit(user));
512         ds.setPerUserDefaultAutoCommit("anotheruser", Boolean.FALSE);
513         assertEquals(Boolean.FALSE, ds.getPerUserDefaultAutoCommit(user));
514         assertEquals(Boolean.FALSE, ds.getPerUserDefaultAutoCommit("anotheruser"));
515     }
516 
517     @Test
518     void testPerUserDefaultAutoCommitWithUserMapNotInitialized() {
519         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
520         ds.setPerUserDefaultAutoCommit(user, Boolean.FALSE);
521         assertEquals(Boolean.FALSE, ds.getPerUserDefaultAutoCommit(user));
522     }
523 
524     @Test
525     void testPerUserDefaultAutoCommitWithUserMapNotInitializedMissingKey() {
526         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
527         ds.setPerUserDefaultAutoCommit("whatismyuseragain?", Boolean.FALSE);
528         // TODO this is not consistent with the other methods
529         assertNull(ds.getPerUserDefaultAutoCommit("missingkey"));
530     }
531 
532     // -- per user default auto commit
533 
534     @Test
535     void testPerUserDefaultReadOnlyMapInitialized() {
536         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
537         Map<String, Boolean> values = new HashMap<>();
538         values.put("key", Boolean.FALSE);
539         ds.setPerUserDefaultReadOnly(values);
540         assertEquals(Boolean.FALSE, ds.getPerUserDefaultReadOnly("key"));
541         values = new HashMap<>();
542         values.put("anonymous", Boolean.FALSE);
543         ds.setPerUserDefaultReadOnly(values);
544         assertNull(ds.getPerUserDefaultReadOnly("key"));
545         assertEquals(Boolean.FALSE, ds.getPerUserDefaultReadOnly("anonymous"));
546     }
547 
548     @Test
549     void testPerUserDefaultReadOnlyMapNotInitialized() {
550         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
551         final Map<String, Boolean> values = new HashMap<>();
552         values.put("key", Boolean.TRUE);
553         ds.setPerUserDefaultReadOnly(values);
554         assertEquals(Boolean.TRUE, ds.getPerUserDefaultReadOnly("key"));
555     }
556 
557     @Test
558     void testPerUserDefaultReadOnlyMapNotInitializedMissingKey() {
559         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
560         final Map<String, Boolean> values = new HashMap<>();
561         values.put("key", Boolean.FALSE);
562         ds.setPerUserDefaultReadOnly(values);
563         // TODO this is not consistent with the other methods
564         assertNull(ds.getPerUserDefaultReadOnly("missingkey"));
565     }
566 
567     @Test
568     void testPerUserDefaultReadOnlyWithUserMapInitialized() {
569         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
570         ds.setPerUserDefaultReadOnly(user, Boolean.FALSE);
571         assertEquals(Boolean.FALSE, ds.getPerUserDefaultReadOnly(user));
572         ds.setPerUserDefaultReadOnly("anotheruser", Boolean.FALSE);
573         assertEquals(Boolean.FALSE, ds.getPerUserDefaultReadOnly(user));
574         assertEquals(Boolean.FALSE, ds.getPerUserDefaultReadOnly("anotheruser"));
575     }
576 
577     @Test
578     void testPerUserDefaultReadOnlyWithUserMapNotInitialized() {
579         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
580         ds.setPerUserDefaultReadOnly(user, Boolean.FALSE);
581         assertEquals(Boolean.FALSE, ds.getPerUserDefaultReadOnly(user));
582     }
583 
584     @Test
585     void testPerUserDefaultReadOnlyWithUserMapNotInitializedMissingKey() {
586         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
587         ds.setPerUserDefaultReadOnly("whatismyuseragain?", Boolean.FALSE);
588         // TODO this is not consistent with the other methods
589         assertNull(ds.getPerUserDefaultReadOnly("missingkey"));
590     }
591 
592     // -- per user default read only
593 
594     @Test
595     void testPerUserDefaultTransactionIsolationMapInitialized() {
596         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
597         Map<String, Integer> values = new HashMap<>();
598         values.put("key", 0);
599         ds.setPerUserDefaultTransactionIsolation(values);
600         assertEquals((Integer) 0, ds.getPerUserDefaultTransactionIsolation("key"));
601         values = new HashMap<>();
602         values.put("anonymous", 0);
603         ds.setPerUserDefaultTransactionIsolation(values);
604         // TODO this is not consistent with the other methods
605         assertNull(ds.getPerUserDefaultTransactionIsolation("key"));
606         assertEquals((Integer) 0, ds.getPerUserDefaultTransactionIsolation("anonymous"));
607     }
608 
609     @Test
610     void testPerUserDefaultTransactionIsolationMapNotInitialized() {
611         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
612         final Map<String, Integer> values = new HashMap<>();
613         values.put("key", 1);
614         ds.setPerUserDefaultTransactionIsolation(values);
615         assertEquals((Integer) 1, ds.getPerUserDefaultTransactionIsolation("key"));
616     }
617 
618     @Test
619     void testPerUserDefaultTransactionIsolationMapNotInitializedMissingKey() {
620         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
621         final Map<String, Integer> values = new HashMap<>();
622         values.put("key", 0);
623         ds.setPerUserDefaultTransactionIsolation(values);
624         // TODO this is not consistent with the other methods
625         assertNull(ds.getPerUserDefaultTransactionIsolation("missingkey"));
626     }
627 
628     @Test
629     void testPerUserDefaultTransactionIsolationWithUserMapInitialized() {
630         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
631         ds.setPerUserDefaultTransactionIsolation(user, 0);
632         assertEquals((Integer) 0, ds.getPerUserDefaultTransactionIsolation(user));
633         ds.setPerUserDefaultTransactionIsolation("anotheruser", 0);
634         assertEquals((Integer) 0, ds.getPerUserDefaultTransactionIsolation(user));
635         assertEquals((Integer) 0, ds.getPerUserDefaultTransactionIsolation("anotheruser"));
636     }
637 
638     @Test
639     void testPerUserDefaultTransactionIsolationWithUserMapNotInitialized() {
640         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
641         ds.setPerUserDefaultTransactionIsolation(user, 0);
642         assertEquals((Integer) 0, ds.getPerUserDefaultTransactionIsolation(user));
643     }
644 
645     @Test
646     void testPerUserDefaultTransactionIsolationWithUserMapNotInitializedMissingKey() {
647         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
648         ds.setPerUserDefaultTransactionIsolation("whatismyuseragain?", 0);
649         // TODO this is not consistent with the other methods
650         assertNull(ds.getPerUserDefaultTransactionIsolation("missingkey"));
651     }
652 
653     // -- per user default transaction isolation
654 
655     @Test
656     void testPerUserDurationBetweenEvictionRunsMapInitialized() {
657         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
658         Map<String, Duration> values = new HashMap<>();
659         values.put("key", Duration.ZERO);
660         ds.setPerUserDurationBetweenEvictionRuns(values);
661         assertEquals(0L, ds.getPerUserTimeBetweenEvictionRunsMillis("key"));
662         assertEquals(Duration.ZERO, ds.getPerUserDurationBetweenEvictionRuns("key"));
663         values = new HashMap<>();
664         values.put("anonymous", Duration.ZERO);
665         ds.setPerUserDurationBetweenEvictionRuns(values);
666         assertEquals(ds.getDefaultTimeBetweenEvictionRunsMillis(), ds.getPerUserTimeBetweenEvictionRunsMillis("key"));
667         assertEquals(ds.getDefaultDurationBetweenEvictionRuns(), ds.getPerUserDurationBetweenEvictionRuns("key"));
668         assertEquals(0L, ds.getPerUserTimeBetweenEvictionRunsMillis("anonymous"));
669         assertEquals(Duration.ZERO, ds.getPerUserDurationBetweenEvictionRuns("anonymous"));
670     }
671 
672     @Test
673     void testPerUserDurationBetweenEvictionRunsMapNotInitialized() {
674         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
675         final Map<String, Duration> values = new HashMap<>();
676         values.put("key", DURATION_1_MILLISECOND);
677         ds.setPerUserDurationBetweenEvictionRuns(values);
678         assertEquals(1L, ds.getPerUserTimeBetweenEvictionRunsMillis("key"));
679         assertEquals(DURATION_1_MILLISECOND, ds.getPerUserDurationBetweenEvictionRuns("key"));
680     }
681 
682     @Test
683     void testPerUserDurationBetweenEvictionRunsMapNotInitializedMissingKey() {
684         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
685         final Map<String, Duration> values = new HashMap<>();
686         values.put("key", Duration.ZERO);
687         ds.setPerUserDurationBetweenEvictionRuns(values);
688         assertEquals(ds.getDefaultTimeBetweenEvictionRunsMillis(), ds.getPerUserTimeBetweenEvictionRunsMillis("missingkey"));
689         assertEquals(ds.getDefaultDurationBetweenEvictionRuns(), ds.getPerUserDurationBetweenEvictionRuns("missingkey"));
690     }
691 
692     @Test
693     void testPerUserEvictionPolicyClassNameMapInitialized() {
694         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
695         Map<String, String> values = new HashMap<>();
696         values.put("key", "bar");
697         ds.setPerUserEvictionPolicyClassName(values);
698         assertEquals("bar", ds.getPerUserEvictionPolicyClassName("key"));
699         values = new HashMap<>();
700         values.put("anonymous", "bar");
701         ds.setPerUserEvictionPolicyClassName(values);
702         assertEquals(ds.getDefaultEvictionPolicyClassName(), ds.getPerUserEvictionPolicyClassName("key"));
703         assertEquals("bar", ds.getPerUserEvictionPolicyClassName("anonymous"));
704     }
705 
706     @Test
707     void testPerUserEvictionPolicyClassNameMapNotInitialized() {
708         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
709         final Map<String, String> values = new HashMap<>();
710         values.put("key", "test");
711         ds.setPerUserEvictionPolicyClassName(values);
712         assertEquals("test", ds.getPerUserEvictionPolicyClassName("key"));
713     }
714 
715     @Test
716     void testPerUserEvictionPolicyClassNameMapNotInitializedMissingKey() {
717         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
718         final Map<String, String> values = new HashMap<>();
719         values.put("key", "bar");
720         ds.setPerUserEvictionPolicyClassName(values);
721         assertEquals(ds.getDefaultEvictionPolicyClassName(), ds.getPerUserEvictionPolicyClassName("missingkey"));
722     }
723 
724     // -- per user eviction policy class name
725 
726     @Test
727     void testPerUserEvictionPolicyClassNameWithUserMapInitialized() {
728         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
729         ds.setPerUserEvictionPolicyClassName(user, "bar");
730         assertEquals("bar", ds.getPerUserEvictionPolicyClassName(user));
731         ds.setPerUserEvictionPolicyClassName("anotheruser", "bar");
732         assertEquals("bar", ds.getPerUserEvictionPolicyClassName(user));
733         assertEquals("bar", ds.getPerUserEvictionPolicyClassName("anotheruser"));
734     }
735 
736     @Test
737     void testPerUserEvictionPolicyClassNameWithUserMapNotInitialized() {
738         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
739         ds.setPerUserEvictionPolicyClassName(user, "bar");
740         assertEquals("bar", ds.getPerUserEvictionPolicyClassName(user));
741     }
742 
743     @Test
744     void testPerUserEvictionPolicyClassNameWithUserMapNotInitializedMissingKey() {
745         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
746         ds.setPerUserEvictionPolicyClassName("whatismyuseragain?", "bar");
747         assertEquals(ds.getDefaultEvictionPolicyClassName(), ds.getPerUserEvictionPolicyClassName("missingkey"));
748     }
749 
750     @Test
751     void testPerUserLifoMapInitialized() {
752         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
753         Map<String, Boolean> values = new HashMap<>();
754         values.put("key", Boolean.FALSE);
755         ds.setPerUserLifo(values);
756         assertEquals(Boolean.FALSE, ds.getPerUserLifo("key"));
757         values = new HashMap<>();
758         values.put("anonymous", Boolean.FALSE);
759         ds.setPerUserLifo(values);
760         assertEquals(ds.getDefaultLifo(), ds.getPerUserLifo("key"));
761         assertEquals(Boolean.FALSE, ds.getPerUserLifo("anonymous"));
762     }
763 
764     @Test
765     void testPerUserLifoMapNotInitialized() {
766         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
767         final Map<String, Boolean> values = new HashMap<>();
768         values.put("key", Boolean.TRUE);
769         ds.setPerUserLifo(values);
770         assertEquals(Boolean.TRUE, ds.getPerUserLifo("key"));
771     }
772 
773     @Test
774     void testPerUserLifoMapNotInitializedMissingKey() {
775         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
776         final Map<String, Boolean> values = new HashMap<>();
777         values.put("key", Boolean.FALSE);
778         ds.setPerUserLifo(values);
779         assertEquals(ds.getDefaultLifo(), ds.getPerUserLifo("missingkey"));
780     }
781 
782     // -- per user lifo
783 
784     @Test
785     void testPerUserLifoWithUserMapInitialized() {
786         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
787         ds.setPerUserLifo(user, Boolean.FALSE);
788         assertEquals(Boolean.FALSE, ds.getPerUserLifo(user));
789         ds.setPerUserLifo("anotheruser", Boolean.FALSE);
790         assertEquals(Boolean.FALSE, ds.getPerUserLifo(user));
791         assertEquals(Boolean.FALSE, ds.getPerUserLifo("anotheruser"));
792     }
793 
794     @Test
795     void testPerUserLifoWithUserMapNotInitialized() {
796         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
797         ds.setPerUserLifo(user, Boolean.FALSE);
798         assertEquals(Boolean.FALSE, ds.getPerUserLifo(user));
799     }
800 
801     @Test
802     void testPerUserLifoWithUserMapNotInitializedMissingKey() {
803         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
804         ds.setPerUserLifo("whatismyuseragain?", Boolean.FALSE);
805         assertEquals(ds.getDefaultLifo(), ds.getPerUserLifo("missingkey"));
806     }
807 
808     @Test
809     void testPerUserMaxIdleMapInitialized() {
810         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
811         Map<String, Integer> values = new HashMap<>();
812         values.put("key", 0);
813         ds.setPerUserMaxIdle(values);
814         assertEquals((Integer) 0, (Integer) ds.getPerUserMaxIdle("key"));
815         values = new HashMap<>();
816         values.put("anonymous", 0);
817         ds.setPerUserMaxIdle(values);
818         assertEquals((Integer) ds.getDefaultMaxIdle(), (Integer) ds.getPerUserMaxIdle("key"));
819         assertEquals((Integer) 0, (Integer) ds.getPerUserMaxIdle("anonymous"));
820     }
821 
822     @Test
823     void testPerUserMaxIdleMapNotInitialized() {
824         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
825         final Map<String, Integer> values = new HashMap<>();
826         values.put("key", 1);
827         ds.setPerUserMaxIdle(values);
828         assertEquals((Integer) 1, (Integer) ds.getPerUserMaxIdle("key"));
829     }
830 
831     @Test
832     void testPerUserMaxIdleMapNotInitializedMissingKey() {
833         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
834         final Map<String, Integer> values = new HashMap<>();
835         values.put("key", 0);
836         ds.setPerUserMaxIdle(values);
837         assertEquals((Integer) ds.getDefaultMaxIdle(), (Integer) ds.getPerUserMaxIdle("missingkey"));
838     }
839 
840     // -- per user max idle
841 
842     @Test
843     void testPerUserMaxIdleWithUserMapInitialized() {
844         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
845         ds.setPerUserMaxIdle(user, 0);
846         assertEquals((Integer) 0, (Integer) ds.getPerUserMaxIdle(user));
847         ds.setPerUserMaxIdle("anotheruser", 0);
848         assertEquals((Integer) 0, (Integer) ds.getPerUserMaxIdle(user));
849         assertEquals((Integer) 0, (Integer) ds.getPerUserMaxIdle("anotheruser"));
850     }
851 
852     @Test
853     void testPerUserMaxIdleWithUserMapNotInitialized() {
854         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
855         ds.setPerUserMaxIdle(user, 0);
856         assertEquals((Integer) 0, (Integer) ds.getPerUserMaxIdle(user));
857     }
858 
859     @Test
860     void testPerUserMaxIdleWithUserMapNotInitializedMissingKey() {
861         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
862         ds.setPerUserMaxIdle("whatismyuseragain?", 0);
863         assertEquals((Integer) ds.getDefaultMaxIdle(), (Integer) ds.getPerUserMaxIdle("missingkey"));
864     }
865 
866     @Test
867     void testPerUserMaxTotalMapInitialized() {
868         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
869         Map<String, Integer> values = new HashMap<>();
870         values.put("key", 0);
871         ds.setPerUserMaxTotal(values);
872         assertEquals((Integer) 0, (Integer) ds.getPerUserMaxTotal("key"));
873         values = new HashMap<>();
874         values.put("anonymous", 0);
875         ds.setPerUserMaxTotal(values);
876         assertEquals((Integer) ds.getDefaultMaxTotal(), (Integer) ds.getPerUserMaxTotal("key"));
877         assertEquals((Integer) 0, (Integer) ds.getPerUserMaxTotal("anonymous"));
878     }
879 
880     @Test
881     void testPerUserMaxTotalMapNotInitialized() {
882         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
883         final Map<String, Integer> values = new HashMap<>();
884         values.put("key", 1);
885         ds.setPerUserMaxTotal(values);
886         assertEquals((Integer) 1, (Integer) ds.getPerUserMaxTotal("key"));
887     }
888 
889     @Test
890     void testPerUserMaxTotalMapNotInitializedMissingKey() {
891         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
892         final Map<String, Integer> values = new HashMap<>();
893         values.put("key", 0);
894         ds.setPerUserMaxTotal(values);
895         assertEquals((Integer) ds.getDefaultMaxTotal(), (Integer) ds.getPerUserMaxTotal("missingkey"));
896     }
897 
898     @Test
899     void testPerUserMaxTotalWithUserMapInitialized() {
900         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
901         ds.setPerUserMaxTotal(user, 0);
902         assertEquals((Integer) 0, (Integer) ds.getPerUserMaxTotal(user));
903         ds.setPerUserMaxTotal("anotheruser", 0);
904         assertEquals((Integer) 0, (Integer) ds.getPerUserMaxTotal(user));
905         assertEquals((Integer) 0, (Integer) ds.getPerUserMaxTotal("anotheruser"));
906     }
907 
908     @Test
909     void testPerUserMaxTotalWithUserMapNotInitialized() {
910         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
911         ds.setPerUserMaxTotal(user, 0);
912         assertEquals((Integer) 0, (Integer) ds.getPerUserMaxTotal(user));
913     }
914 
915     @Test
916     void testPerUserMaxTotalWithUserMapNotInitializedMissingKey() {
917         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
918         ds.setPerUserMaxTotal("whatismyuseragain?", 0);
919         assertEquals((Integer) ds.getDefaultMaxTotal(), (Integer) ds.getPerUserMaxTotal("missingkey"));
920     }
921 
922     @Test
923     void testPerUserMaxWaitDurationMapInitialized() {
924         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
925         Map<String, Duration> values = new HashMap<>();
926         values.put("key", Duration.ZERO);
927         ds.setPerUserMaxWaitDuration(values);
928         assertEquals(Duration.ZERO, ds.getPerUserMaxWaitDuration("key"));
929         values = new HashMap<>();
930         values.put("anonymous", Duration.ZERO);
931         ds.setPerUserMaxWaitDuration(values);
932         assertEquals(ds.getDefaultMaxWait(), ds.getPerUserMaxWaitDuration("key"));
933         assertEquals(Duration.ZERO, ds.getPerUserMaxWaitDuration("anonymous"));
934     }
935 
936     @Test
937     void testPerUserMaxWaitDurationMapNotInitialized() {
938         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
939         final Map<String, Duration> values = new HashMap<>();
940         values.put("key", DURATION_1_MILLISECOND);
941         ds.setPerUserMaxWaitDuration(values);
942         assertEquals(DURATION_1_MILLISECOND, ds.getPerUserMaxWaitDuration("key"));
943     }
944 
945     @Test
946     void testPerUserMaxWaitDurationMapNotInitializedMissingKey() {
947         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
948         final Map<String, Duration> values = new HashMap<>();
949         values.put("key", Duration.ZERO);
950         ds.setPerUserMaxWaitDuration(values);
951         assertEquals(ds.getDefaultMaxWait(), ds.getPerUserMaxWaitDuration("missingkey"));
952     }
953 
954     // -- per user max wait millis
955 
956     @Test
957     @SuppressWarnings("deprecation")
958     void testPerUserMaxWaitMillisWithUserMapInitializedDeprecated() {
959         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
960         ds.setPerUserMaxWaitMillis(user, 0L);
961         assertEquals(0L, ds.getPerUserMaxWaitMillis(user));
962         ds.setPerUserMaxWaitMillis("anotheruser", 0L);
963         assertEquals(0L, ds.getPerUserMaxWaitMillis(user));
964         assertEquals(0L, ds.getPerUserMaxWaitMillis("anotheruser"));
965     }
966 
967     @Test
968     @SuppressWarnings("deprecation")
969     void testPerUserMaxWaitMillisWithUserMapNotInitializedDeprecated() {
970         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
971         ds.setPerUserMaxWaitMillis(user, 0L);
972         assertEquals(0L, ds.getPerUserMaxWaitMillis(user));
973     }
974 
975     @Test
976     @SuppressWarnings("deprecation")
977     void testPerUserMaxWaitMillisWithUserMapNotInitializedMissingKeyDeprecated() {
978         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
979         ds.setPerUserMaxWaitMillis("whatismyuseragain?", 0L);
980         assertEquals(ds.getDefaultMaxWaitMillis(), ds.getPerUserMaxWaitMillis("missingkey"));
981     }
982 
983     @Test
984     void testPerUserMethods() throws Exception {
985         final PerUserPoolDataSource tds = (PerUserPoolDataSource) ds;
986 
987         // you need to set per user maxTotal otherwise there is no accounting
988         tds.setPerUserMaxTotal("u1", 5);
989         tds.setPerUserMaxTotal("u2", 5);
990 
991         assertEquals(0, tds.getNumActive());
992         assertEquals(0, tds.getNumActive("u1"));
993         assertEquals(0, tds.getNumActive("u2"));
994         assertEquals(0, tds.getNumIdle());
995         assertEquals(0, tds.getNumIdle("u1"));
996         assertEquals(0, tds.getNumIdle("u2"));
997 
998         try (Connection conn = tds.getConnection()) {
999             assertNotNull(conn);
1000             assertEquals(1, tds.getNumActive());
1001             assertEquals(0, tds.getNumActive("u1"));
1002             assertEquals(0, tds.getNumActive("u2"));
1003             assertEquals(0, tds.getNumIdle());
1004             assertEquals(0, tds.getNumIdle("u1"));
1005             assertEquals(0, tds.getNumIdle("u2"));
1006         }
1007         assertEquals(0, tds.getNumActive());
1008         assertEquals(0, tds.getNumActive("u1"));
1009         assertEquals(0, tds.getNumActive("u2"));
1010         assertEquals(1, tds.getNumIdle());
1011         assertEquals(0, tds.getNumIdle("u1"));
1012         assertEquals(0, tds.getNumIdle("u2"));
1013 
1014         try (Connection conn = tds.getConnection("u1", "p1")) {
1015             assertNotNull(conn);
1016             assertEquals(0, tds.getNumActive());
1017             assertEquals(1, tds.getNumActive("u1"));
1018             assertEquals(0, tds.getNumActive("u2"));
1019             assertEquals(1, tds.getNumIdle());
1020             assertEquals(0, tds.getNumIdle("u1"));
1021             assertEquals(0, tds.getNumIdle("u2"));
1022         }
1023 
1024         assertEquals(0, tds.getNumActive());
1025         assertEquals(0, tds.getNumActive("u1"));
1026         assertEquals(0, tds.getNumActive("u2"));
1027         assertEquals(1, tds.getNumIdle());
1028         assertEquals(1, tds.getNumIdle("u1"));
1029         assertEquals(0, tds.getNumIdle("u2"));
1030     }
1031 
1032     @Test
1033     void testPerUserMinEvictableIdleDurationMapInitialized() {
1034         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1035         Map<String, Duration> values = new HashMap<>();
1036         values.put("key", Duration.ZERO);
1037         ds.setPerUserMinEvictableIdle(values);
1038         assertEquals(0L, ds.getPerUserMinEvictableIdleTimeMillis("key"));
1039         assertEquals(Duration.ZERO, ds.getPerUserMinEvictableIdleDuration("key"));
1040         values = new HashMap<>();
1041         values.put("anonymous", Duration.ZERO);
1042         ds.setPerUserMinEvictableIdle(values);
1043         assertEquals(ds.getDefaultMinEvictableIdleTimeMillis(), ds.getPerUserMinEvictableIdleTimeMillis("key"));
1044         assertEquals(ds.getDefaultMinEvictableIdleDuration(), ds.getPerUserMinEvictableIdleDuration("key"));
1045         assertEquals(0L, ds.getPerUserMinEvictableIdleTimeMillis("anonymous"));
1046         assertEquals(Duration.ZERO, ds.getPerUserMinEvictableIdleDuration("anonymous"));
1047     }
1048 
1049     @Test
1050     void testPerUserMinEvictableIdleDurationMapNotInitialized() {
1051         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1052         final Map<String, Duration> values = new HashMap<>();
1053         values.put("key", DURATION_1_MILLISECOND);
1054         ds.setPerUserMinEvictableIdle(values);
1055         assertEquals(1L, ds.getPerUserMinEvictableIdleTimeMillis("key"));
1056         assertEquals(DURATION_1_MILLISECOND, ds.getPerUserMinEvictableIdleDuration("key"));
1057     }
1058 
1059     // -- per user min evictable idle time millis
1060 
1061     @Test
1062     void testPerUserMinEvictableIdleDurationMapNotInitializedMissingKey() {
1063         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1064         final Map<String, Duration> values = new HashMap<>();
1065         values.put("key", Duration.ZERO);
1066         ds.setPerUserMinEvictableIdle(values);
1067         assertEquals(ds.getDefaultMinEvictableIdleTimeMillis(), ds.getPerUserMinEvictableIdleTimeMillis("missingkey"));
1068         assertEquals(ds.getDefaultMinEvictableIdleDuration(), ds.getPerUserMinEvictableIdleDuration("missingkey"));
1069     }
1070 
1071     @Test
1072     void testPerUserMinEvictableIdleTimeMillisWithUserMapInitialized() {
1073         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1074         ds.setPerUserMinEvictableIdleTimeMillis(user, 0L);
1075         assertEquals(0L, ds.getPerUserMinEvictableIdleTimeMillis(user));
1076         ds.setPerUserMinEvictableIdleTimeMillis("anotheruser", 0L);
1077         assertEquals(0L, ds.getPerUserMinEvictableIdleTimeMillis(user));
1078         assertEquals(0L, ds.getPerUserMinEvictableIdleTimeMillis("anotheruser"));
1079     }
1080 
1081     @Test
1082     void testPerUserMinEvictableIdleTimeMillisWithUserMapNotInitialized() {
1083         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1084         ds.setPerUserMinEvictableIdleTimeMillis(user, 0L);
1085         assertEquals(0L, ds.getPerUserMinEvictableIdleTimeMillis(user));
1086     }
1087 
1088     @Test
1089     void testPerUserMinEvictableIdleTimeMillisWithUserMapNotInitializedMissingKey() {
1090         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1091         ds.setPerUserMinEvictableIdleTimeMillis("whatismyuseragain?", 0L);
1092         assertEquals(ds.getDefaultMinEvictableIdleTimeMillis(), ds.getPerUserMinEvictableIdleTimeMillis("missingkey"));
1093     }
1094 
1095     @Test
1096     void testPerUserMinIdleMapInitialized() {
1097         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1098         Map<String, Integer> values = new HashMap<>();
1099         values.put("key", 0);
1100         ds.setPerUserMinIdle(values);
1101         assertEquals((Integer) 0, (Integer) ds.getPerUserMinIdle("key"));
1102         values = new HashMap<>();
1103         values.put("anonymous", 0);
1104         ds.setPerUserMinIdle(values);
1105         assertEquals((Integer) ds.getDefaultMinIdle(), (Integer) ds.getPerUserMinIdle("key"));
1106         assertEquals((Integer) 0, (Integer) ds.getPerUserMinIdle("anonymous"));
1107     }
1108 
1109     @Test
1110     void testPerUserMinIdleMapNotInitialized() {
1111         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1112         final Map<String, Integer> values = new HashMap<>();
1113         values.put("key", 1);
1114         ds.setPerUserMinIdle(values);
1115         assertEquals((Integer) 1, (Integer) ds.getPerUserMinIdle("key"));
1116     }
1117 
1118     // -- per user min idle
1119 
1120     @Test
1121     void testPerUserMinIdleMapNotInitializedMissingKey() {
1122         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1123         final Map<String, Integer> values = new HashMap<>();
1124         values.put("key", 0);
1125         ds.setPerUserMinIdle(values);
1126         assertEquals((Integer) ds.getDefaultMinIdle(), (Integer) ds.getPerUserMinIdle("missingkey"));
1127     }
1128 
1129     @Test
1130     void testPerUserMinIdleWithUserMapInitialized() {
1131         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1132         ds.setPerUserMinIdle(user, 0);
1133         assertEquals((Integer) 0, (Integer) ds.getPerUserMinIdle(user));
1134         ds.setPerUserMinIdle("anotheruser", 0);
1135         assertEquals((Integer) 0, (Integer) ds.getPerUserMinIdle(user));
1136         assertEquals((Integer) 0, (Integer) ds.getPerUserMinIdle("anotheruser"));
1137     }
1138 
1139     @Test
1140     void testPerUserMinIdleWithUserMapNotInitialized() {
1141         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1142         ds.setPerUserMinIdle(user, 0);
1143         assertEquals((Integer) 0, (Integer) ds.getPerUserMinIdle(user));
1144     }
1145 
1146     @Test
1147     void testPerUserMinIdleWithUserMapNotInitializedMissingKey() {
1148         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1149         ds.setPerUserMinIdle("whatismyuseragain?", 0);
1150         assertEquals((Integer) ds.getDefaultMinIdle(), (Integer) ds.getPerUserMinIdle("missingkey"));
1151     }
1152 
1153     @Test
1154     void testPerUserNumTestsPerEvictionRunMapInitialized() {
1155         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1156         Map<String, Integer> values = new HashMap<>();
1157         values.put("key", 0);
1158         ds.setPerUserNumTestsPerEvictionRun(values);
1159         assertEquals((Integer) 0, (Integer) ds.getPerUserNumTestsPerEvictionRun("key"));
1160         values = new HashMap<>();
1161         values.put("anonymous", 0);
1162         ds.setPerUserNumTestsPerEvictionRun(values);
1163         assertEquals((Integer) ds.getDefaultNumTestsPerEvictionRun(), (Integer) ds.getPerUserNumTestsPerEvictionRun("key"));
1164         assertEquals((Integer) 0, (Integer) ds.getPerUserNumTestsPerEvictionRun("anonymous"));
1165     }
1166 
1167     @Test
1168     void testPerUserNumTestsPerEvictionRunMapNotInitialized() {
1169         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1170         final Map<String, Integer> values = new HashMap<>();
1171         values.put("key", 1);
1172         ds.setPerUserNumTestsPerEvictionRun(values);
1173         assertEquals((Integer) 1, (Integer) ds.getPerUserNumTestsPerEvictionRun("key"));
1174     }
1175 
1176     // -- per user num tests per eviction run
1177 
1178     @Test
1179     void testPerUserNumTestsPerEvictionRunMapNotInitializedMissingKey() {
1180         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1181         final Map<String, Integer> values = new HashMap<>();
1182         values.put("key", 0);
1183         ds.setPerUserNumTestsPerEvictionRun(values);
1184         assertEquals((Integer) ds.getDefaultNumTestsPerEvictionRun(), (Integer) ds.getPerUserNumTestsPerEvictionRun("missingkey"));
1185     }
1186 
1187     @Test
1188     void testPerUserNumTestsPerEvictionRunWithUserMapInitialized() {
1189         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1190         ds.setPerUserNumTestsPerEvictionRun(user, 0);
1191         assertEquals((Integer) 0, (Integer) ds.getPerUserNumTestsPerEvictionRun(user));
1192         ds.setPerUserNumTestsPerEvictionRun("anotheruser", 0);
1193         assertEquals((Integer) 0, (Integer) ds.getPerUserNumTestsPerEvictionRun(user));
1194         assertEquals((Integer) 0, (Integer) ds.getPerUserNumTestsPerEvictionRun("anotheruser"));
1195     }
1196 
1197     @Test
1198     void testPerUserNumTestsPerEvictionRunWithUserMapNotInitialized() {
1199         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1200         ds.setPerUserNumTestsPerEvictionRun(user, 0);
1201         assertEquals((Integer) 0, (Integer) ds.getPerUserNumTestsPerEvictionRun(user));
1202     }
1203 
1204     @Test
1205     void testPerUserNumTestsPerEvictionRunWithUserMapNotInitializedMissingKey() {
1206         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1207         ds.setPerUserNumTestsPerEvictionRun("whatismyuseragain?", 0);
1208         assertEquals((Integer) ds.getDefaultNumTestsPerEvictionRun(), (Integer) ds.getPerUserNumTestsPerEvictionRun("missingkey"));
1209     }
1210 
1211     @Test
1212     void testPerUserSoftMinEvictableIdleDurationMapInitialized() {
1213         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1214         Map<String, Duration> values = new HashMap<>();
1215         values.put("key", Duration.ZERO);
1216         ds.setPerUserSoftMinEvictableIdle(values);
1217         assertEquals(0L, ds.getPerUserSoftMinEvictableIdleTimeMillis("key"));
1218         assertEquals(Duration.ZERO, ds.getPerUserSoftMinEvictableIdleDuration("key"));
1219         values = new HashMap<>();
1220         values.put("anonymous", Duration.ZERO);
1221         ds.setPerUserSoftMinEvictableIdle(values);
1222         assertEquals(ds.getDefaultSoftMinEvictableIdleTimeMillis(), ds.getPerUserSoftMinEvictableIdleTimeMillis("key"));
1223         assertEquals(ds.getDefaultSoftMinEvictableIdleDuration(), ds.getPerUserSoftMinEvictableIdleDuration("key"));
1224         assertEquals(0L, ds.getPerUserSoftMinEvictableIdleTimeMillis("anonymous"));
1225         assertEquals(Duration.ZERO, ds.getPerUserSoftMinEvictableIdleDuration("anonymous"));
1226     }
1227 
1228     @Test
1229     void testPerUserSoftMinEvictableIdleDurationMapNotInitialized() {
1230         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1231         final Map<String, Duration> values = new HashMap<>();
1232         values.put("key", DURATION_1_MILLISECOND);
1233         ds.setPerUserSoftMinEvictableIdle(values);
1234         assertEquals(1L, ds.getPerUserSoftMinEvictableIdleTimeMillis("key"));
1235         assertEquals(DURATION_1_MILLISECOND, ds.getPerUserSoftMinEvictableIdleDuration("key"));
1236     }
1237 
1238     // -- per user soft min evictable idle time millis
1239 
1240     @Test
1241     void testPerUserSoftMinEvictableIdleDurationMapNotInitializedMissingKey() {
1242         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1243         final Map<String, Duration> values = new HashMap<>();
1244         values.put("key", Duration.ZERO);
1245         ds.setPerUserSoftMinEvictableIdle(values);
1246         assertEquals(ds.getDefaultSoftMinEvictableIdleTimeMillis(), ds.getPerUserSoftMinEvictableIdleTimeMillis("missingkey"));
1247         assertEquals(ds.getDefaultSoftMinEvictableIdleDuration(), ds.getPerUserSoftMinEvictableIdleDuration("missingkey"));
1248     }
1249 
1250     @Test
1251     void testPerUserSoftMinEvictableIdleTimeMillisWithUserMapInitialized() {
1252         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1253         ds.setPerUserSoftMinEvictableIdleTimeMillis(user, 0L);
1254         assertEquals(0L, ds.getPerUserSoftMinEvictableIdleTimeMillis(user));
1255         ds.setPerUserSoftMinEvictableIdleTimeMillis("anotheruser", 0L);
1256         assertEquals(0L, ds.getPerUserSoftMinEvictableIdleTimeMillis(user));
1257         assertEquals(0L, ds.getPerUserSoftMinEvictableIdleTimeMillis("anotheruser"));
1258     }
1259 
1260     @Test
1261     void testPerUserSoftMinEvictableIdleTimeMillisWithUserMapNotInitialized() {
1262         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1263         ds.setPerUserSoftMinEvictableIdleTimeMillis(user, 0L);
1264         assertEquals(0L, ds.getPerUserSoftMinEvictableIdleTimeMillis(user));
1265     }
1266 
1267     @Test
1268     void testPerUserSoftMinEvictableIdleTimeMillisWithUserMapNotInitializedMissingKey() {
1269         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1270         ds.setPerUserSoftMinEvictableIdleTimeMillis("whatismyuseragain?", 0L);
1271         assertEquals(ds.getDefaultSoftMinEvictableIdleTimeMillis(), ds.getPerUserSoftMinEvictableIdleTimeMillis("missingkey"));
1272     }
1273 
1274     @Test
1275     void testPerUserTestOnBorrowMapInitialized() {
1276         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1277         Map<String, Boolean> values = new HashMap<>();
1278         values.put("key", Boolean.FALSE);
1279         ds.setPerUserTestOnBorrow(values);
1280         assertEquals(Boolean.FALSE, ds.getPerUserTestOnBorrow("key"));
1281         values = new HashMap<>();
1282         values.put("anonymous", Boolean.FALSE);
1283         ds.setPerUserTestOnBorrow(values);
1284         assertEquals(ds.getDefaultTestOnBorrow(), ds.getPerUserTestOnBorrow("key"));
1285         assertEquals(Boolean.FALSE, ds.getPerUserTestOnBorrow("anonymous"));
1286     }
1287 
1288     @Test
1289     void testPerUserTestOnBorrowMapNotInitialized() {
1290         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1291         final Map<String, Boolean> values = new HashMap<>();
1292         values.put("key", Boolean.TRUE);
1293         ds.setPerUserTestOnBorrow(values);
1294         assertEquals(Boolean.TRUE, ds.getPerUserTestOnBorrow("key"));
1295     }
1296 
1297     // -- per user test on borrow
1298 
1299     @Test
1300     void testPerUserTestOnBorrowMapNotInitializedMissingKey() {
1301         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1302         final Map<String, Boolean> values = new HashMap<>();
1303         values.put("key", Boolean.FALSE);
1304         ds.setPerUserTestOnBorrow(values);
1305         assertEquals(ds.getDefaultTestOnBorrow(), ds.getPerUserTestOnBorrow("missingkey"));
1306     }
1307 
1308     @Test
1309     void testPerUserTestOnBorrowWithUserMapInitialized() {
1310         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1311         ds.setPerUserTestOnBorrow(user, Boolean.FALSE);
1312         assertEquals(Boolean.FALSE, ds.getPerUserTestOnBorrow(user));
1313         ds.setPerUserTestOnBorrow("anotheruser", Boolean.FALSE);
1314         assertEquals(Boolean.FALSE, ds.getPerUserTestOnBorrow(user));
1315         assertEquals(Boolean.FALSE, ds.getPerUserTestOnBorrow("anotheruser"));
1316     }
1317 
1318     @Test
1319     void testPerUserTestOnBorrowWithUserMapNotInitialized() {
1320         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1321         ds.setPerUserTestOnBorrow(user, Boolean.FALSE);
1322         assertEquals(Boolean.FALSE, ds.getPerUserTestOnBorrow(user));
1323     }
1324 
1325     @Test
1326     void testPerUserTestOnBorrowWithUserMapNotInitializedMissingKey() {
1327         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1328         ds.setPerUserTestOnBorrow("whatismyuseragain?", Boolean.FALSE);
1329         assertEquals(ds.getDefaultTestOnBorrow(), ds.getPerUserTestOnBorrow("missingkey"));
1330     }
1331 
1332     @Test
1333     void testPerUserTestOnCreateMapInitialized() {
1334         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1335         Map<String, Boolean> values = new HashMap<>();
1336         values.put("key", Boolean.FALSE);
1337         ds.setPerUserTestOnCreate(values);
1338         assertEquals(Boolean.FALSE, ds.getPerUserTestOnCreate("key"));
1339         values = new HashMap<>();
1340         values.put("anonymous", Boolean.FALSE);
1341         ds.setPerUserTestOnCreate(values);
1342         assertEquals(ds.getDefaultTestOnCreate(), ds.getPerUserTestOnCreate("key"));
1343         assertEquals(Boolean.FALSE, ds.getPerUserTestOnCreate("anonymous"));
1344     }
1345 
1346     @Test
1347     void testPerUserTestOnCreateMapNotInitialized() {
1348         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1349         final Map<String, Boolean> values = new HashMap<>();
1350         values.put("key", Boolean.TRUE);
1351         ds.setPerUserTestOnCreate(values);
1352         assertEquals(Boolean.TRUE, ds.getPerUserTestOnCreate("key"));
1353     }
1354 
1355     // -- per user test on create
1356 
1357     @Test
1358     void testPerUserTestOnCreateMapNotInitializedMissingKey() {
1359         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1360         final Map<String, Boolean> values = new HashMap<>();
1361         values.put("key", Boolean.FALSE);
1362         ds.setPerUserTestOnCreate(values);
1363         assertEquals(ds.getDefaultTestOnCreate(), ds.getPerUserTestOnCreate("missingkey"));
1364     }
1365 
1366     @Test
1367     void testPerUserTestOnCreateWithUserMapInitialized() {
1368         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1369         ds.setPerUserTestOnCreate(user, Boolean.FALSE);
1370         assertEquals(Boolean.FALSE, ds.getPerUserTestOnCreate(user));
1371         ds.setPerUserTestOnCreate("anotheruser", Boolean.FALSE);
1372         assertEquals(Boolean.FALSE, ds.getPerUserTestOnCreate(user));
1373         assertEquals(Boolean.FALSE, ds.getPerUserTestOnCreate("anotheruser"));
1374     }
1375 
1376     @Test
1377     void testPerUserTestOnCreateWithUserMapNotInitialized() {
1378         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1379         ds.setPerUserTestOnCreate(user, Boolean.FALSE);
1380         assertEquals(Boolean.FALSE, ds.getPerUserTestOnCreate(user));
1381     }
1382 
1383     @Test
1384     void testPerUserTestOnCreateWithUserMapNotInitializedMissingKey() {
1385         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1386         ds.setPerUserTestOnCreate("whatismyuseragain?", Boolean.FALSE);
1387         assertEquals(ds.getDefaultTestOnCreate(), ds.getPerUserTestOnCreate("missingkey"));
1388     }
1389 
1390     @Test
1391     void testPerUserTestOnReturnMapInitialized() {
1392         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1393         Map<String, Boolean> values = new HashMap<>();
1394         values.put("key", Boolean.FALSE);
1395         ds.setPerUserTestOnReturn(values);
1396         assertEquals(Boolean.FALSE, ds.getPerUserTestOnReturn("key"));
1397         values = new HashMap<>();
1398         values.put("anonymous", Boolean.FALSE);
1399         ds.setPerUserTestOnReturn(values);
1400         assertEquals(ds.getDefaultTestOnReturn(), ds.getPerUserTestOnReturn("key"));
1401         assertEquals(Boolean.FALSE, ds.getPerUserTestOnReturn("anonymous"));
1402     }
1403 
1404     @Test
1405     void testPerUserTestOnReturnMapNotInitialized() {
1406         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1407         final Map<String, Boolean> values = new HashMap<>();
1408         values.put("key", Boolean.TRUE);
1409         ds.setPerUserTestOnReturn(values);
1410         assertEquals(Boolean.TRUE, ds.getPerUserTestOnReturn("key"));
1411     }
1412 
1413     @Test
1414     void testPerUserTestOnReturnMapNotInitializedMissingKey() {
1415         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1416         final Map<String, Boolean> values = new HashMap<>();
1417         values.put("key", Boolean.FALSE);
1418         ds.setPerUserTestOnReturn(values);
1419         assertEquals(ds.getDefaultTestOnReturn(), ds.getPerUserTestOnReturn("missingkey"));
1420     }
1421 
1422     // -- per user test on return
1423 
1424     @Test
1425     void testPerUserTestOnReturnWithUserMapInitialized() {
1426         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1427         ds.setPerUserTestOnReturn(user, Boolean.FALSE);
1428         assertEquals(Boolean.FALSE, ds.getPerUserTestOnReturn(user));
1429         ds.setPerUserTestOnReturn("anotheruser", Boolean.FALSE);
1430         assertEquals(Boolean.FALSE, ds.getPerUserTestOnReturn(user));
1431         assertEquals(Boolean.FALSE, ds.getPerUserTestOnReturn("anotheruser"));
1432     }
1433 
1434     @Test
1435     void testPerUserTestOnReturnWithUserMapNotInitialized() {
1436         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1437         ds.setPerUserTestOnReturn(user, Boolean.FALSE);
1438         assertEquals(Boolean.FALSE, ds.getPerUserTestOnReturn(user));
1439     }
1440 
1441     @Test
1442     void testPerUserTestOnReturnWithUserMapNotInitializedMissingKey() {
1443         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1444         ds.setPerUserTestOnReturn("whatismyuseragain?", Boolean.FALSE);
1445         assertEquals(ds.getDefaultTestOnReturn(), ds.getPerUserTestOnReturn("missingkey"));
1446     }
1447 
1448     @Test
1449     void testPerUserTestWhileIdleMapInitialized() {
1450         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1451         Map<String, Boolean> values = new HashMap<>();
1452         values.put("key", Boolean.FALSE);
1453         ds.setPerUserTestWhileIdle(values);
1454         assertEquals(Boolean.FALSE, ds.getPerUserTestWhileIdle("key"));
1455         values = new HashMap<>();
1456         values.put("anonymous", Boolean.FALSE);
1457         ds.setPerUserTestWhileIdle(values);
1458         assertEquals(ds.getDefaultTestWhileIdle(), ds.getPerUserTestWhileIdle("key"));
1459         assertEquals(Boolean.FALSE, ds.getPerUserTestWhileIdle("anonymous"));
1460     }
1461 
1462     @Test
1463     void testPerUserTestWhileIdleMapNotInitialized() {
1464         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1465         final Map<String, Boolean> values = new HashMap<>();
1466         values.put("key", Boolean.TRUE);
1467         ds.setPerUserTestWhileIdle(values);
1468         assertEquals(Boolean.TRUE, ds.getPerUserTestWhileIdle("key"));
1469     }
1470 
1471     @Test
1472     void testPerUserTestWhileIdleMapNotInitializedMissingKey() {
1473         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1474         final Map<String, Boolean> values = new HashMap<>();
1475         values.put("key", Boolean.FALSE);
1476         ds.setPerUserTestWhileIdle(values);
1477         assertEquals(ds.getDefaultTestWhileIdle(), ds.getPerUserTestWhileIdle("missingkey"));
1478     }
1479 
1480     @Test
1481     void testPerUserTestWhileIdleWithUserMapInitialized() {
1482         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1483         ds.setPerUserTestWhileIdle(user, Boolean.FALSE);
1484         assertEquals(Boolean.FALSE, ds.getPerUserTestWhileIdle(user));
1485         ds.setPerUserTestWhileIdle("anotheruser", Boolean.FALSE);
1486         assertEquals(Boolean.FALSE, ds.getPerUserTestWhileIdle(user));
1487         assertEquals(Boolean.FALSE, ds.getPerUserTestWhileIdle("anotheruser"));
1488     }
1489 
1490     @Test
1491     void testPerUserTestWhileIdleWithUserMapNotInitialized() {
1492         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1493         ds.setPerUserTestWhileIdle(user, Boolean.FALSE);
1494         assertEquals(Boolean.FALSE, ds.getPerUserTestWhileIdle(user));
1495     }
1496 
1497     @Test
1498     void testPerUserTestWhileIdleWithUserMapNotInitializedMissingKey() {
1499         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1500         ds.setPerUserTestWhileIdle("whatismyuseragain?", Boolean.FALSE);
1501         assertEquals(ds.getDefaultTestWhileIdle(), ds.getPerUserTestWhileIdle("missingkey"));
1502     }
1503 
1504     @Test
1505     void testPerUserTimeBetweenEvictionRunsMillisWithUserMapInitialized() {
1506         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1507         ds.setPerUserTimeBetweenEvictionRunsMillis(user, 0L);
1508         assertEquals(0L, ds.getPerUserTimeBetweenEvictionRunsMillis(user));
1509         ds.setPerUserTimeBetweenEvictionRunsMillis("anotheruser", 0L);
1510         assertEquals(0L, ds.getPerUserTimeBetweenEvictionRunsMillis(user));
1511         assertEquals(0L, ds.getPerUserTimeBetweenEvictionRunsMillis("anotheruser"));
1512     }
1513 
1514     @Test
1515     void testPerUserTimeBetweenEvictionRunsMillisWithUserMapNotInitialized() {
1516         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1517         ds.setPerUserTimeBetweenEvictionRunsMillis(user, 0L);
1518         assertEquals(0L, ds.getPerUserTimeBetweenEvictionRunsMillis(user));
1519     }
1520 
1521     @Test
1522     void testPerUserTimeBetweenEvictionRunsMillisWithUserMapNotInitializedMissingKey() {
1523         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1524         ds.setPerUserTimeBetweenEvictionRunsMillis("whatismyuseragain?", 0L);
1525         assertEquals(ds.getDefaultTimeBetweenEvictionRunsMillis(), ds.getPerUserTimeBetweenEvictionRunsMillis("missingkey"));
1526     }
1527 
1528     // -- per user time between eviction runs millis
1529 
1530     @Test
1531     void testSerialization() throws Exception {
1532         // make sure the pool has initialized
1533         final Connection conn = ds.getConnection();
1534         conn.close();
1535 
1536         // serialize
1537         final ByteArrayOutputStream baos = new ByteArrayOutputStream();
1538         final ObjectOutputStream out = new ObjectOutputStream(baos);
1539         out.writeObject(ds);
1540         out.close();
1541         final byte[] b = baos.toByteArray();
1542 
1543         final ByteArrayInputStream bais = new ByteArrayInputStream(b);
1544         final ObjectInputStream in = new ObjectInputStream(bais);
1545         final Object obj = in.readObject();
1546         in.close();
1547 
1548         assertEquals(1, ((PerUserPoolDataSource) obj).getNumIdle());
1549     }
1550 
1551     @Override
1552     @Test
1553     public void testSimple() throws Exception {
1554         try (final Connection conn = ds.getConnection()) {
1555             assertNotNull(conn);
1556             try (final PreparedStatement stmt = conn.prepareStatement("select * from dual")) {
1557                 assertNotNull(stmt);
1558                 try (final ResultSet rset = stmt.executeQuery()) {
1559                     assertNotNull(rset);
1560                     assertTrue(rset.next());
1561                 }
1562             }
1563         }
1564     }
1565 
1566     @Override
1567     @Test
1568     public void testSimple2() throws Exception {
1569         Connection conn = ds.getConnection();
1570         assertNotNull(conn);
1571 
1572         PreparedStatement stmt = conn.prepareStatement("select * from dual");
1573         assertNotNull(stmt);
1574         ResultSet rset = stmt.executeQuery();
1575         assertNotNull(rset);
1576         assertTrue(rset.next());
1577         rset.close();
1578         stmt.close();
1579 
1580         stmt = conn.prepareStatement("select * from dual");
1581         assertNotNull(stmt);
1582         rset = stmt.executeQuery();
1583         assertNotNull(rset);
1584         assertTrue(rset.next());
1585         rset.close();
1586         stmt.close();
1587 
1588         conn.close();
1589         assertThrows(SQLException.class, conn::createStatement, "Can't use closed connections");
1590 
1591         conn = ds.getConnection();
1592         assertNotNull(conn);
1593 
1594         stmt = conn.prepareStatement("select * from dual");
1595         assertNotNull(stmt);
1596         rset = stmt.executeQuery();
1597         assertNotNull(rset);
1598         assertTrue(rset.next());
1599         rset.close();
1600         stmt.close();
1601 
1602         stmt = conn.prepareStatement("select * from dual");
1603         assertNotNull(stmt);
1604         rset = stmt.executeQuery();
1605         assertNotNull(rset);
1606         assertTrue(rset.next());
1607         rset.close();
1608         stmt.close();
1609 
1610         conn.close();
1611         conn = null;
1612     }
1613 
1614     @Test
1615     void testSimpleWithUsername() throws Exception {
1616         try (final Connection conn = ds.getConnection("u1", "p1")) {
1617             assertNotNull(conn);
1618             try (final PreparedStatement stmt = conn.prepareStatement("select * from dual")) {
1619                 assertNotNull(stmt);
1620                 try (final ResultSet rset = stmt.executeQuery()) {
1621                     assertNotNull(rset);
1622                     assertTrue(rset.next());
1623                 }
1624             }
1625         }
1626     }
1627 
1628     @Test
1629     void testTransactionIsolationBehavior() throws Exception {
1630         try (Connection conn = getConnection()) {
1631             assertNotNull(conn);
1632             assertEquals(Connection.TRANSACTION_READ_COMMITTED, conn.getTransactionIsolation());
1633             conn.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
1634         }
1635 
1636         final Connection conn2 = getConnection();
1637         assertEquals(Connection.TRANSACTION_READ_COMMITTED, conn2.getTransactionIsolation());
1638 
1639         final Connection conn3 = getConnection();
1640         assertEquals(Connection.TRANSACTION_READ_COMMITTED, conn3.getTransactionIsolation());
1641         conn2.close();
1642         conn3.close();
1643     }
1644 
1645     // see issue https://issues.apache.org/bugzilla/show_bug.cgi?id=23843
1646     // unregistered user is in the same pool as without user name
1647     @Test
1648     void testUnregisteredUser() throws Exception {
1649         final PerUserPoolDataSource tds = (PerUserPoolDataSource) ds;
1650 
1651         assertEquals(0, tds.getNumActive());
1652         assertEquals(0, tds.getNumIdle());
1653 
1654         try (Connection conn = tds.getConnection()) {
1655             assertNotNull(conn);
1656             assertEquals(1, tds.getNumActive());
1657             assertEquals(0, tds.getNumIdle());
1658         }
1659         assertEquals(0, tds.getNumActive());
1660         assertEquals(1, tds.getNumIdle());
1661 
1662         try (Connection conn = tds.getConnection("u1", "p1")) {
1663             assertNotNull(conn);
1664             assertEquals(0, tds.getNumActive());
1665             assertEquals(1, tds.getNumIdle());
1666             assertEquals(1, tds.getNumActive("u1"));
1667             assertEquals(0, tds.getNumIdle("u1"));
1668         }
1669         assertEquals(0, tds.getNumActive());
1670         assertEquals(1, tds.getNumIdle());
1671         assertEquals(0, tds.getNumActive("u1"));
1672         assertEquals(1, tds.getNumIdle("u1"));
1673     }
1674 
1675 }