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    *      http://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  import static org.junit.jupiter.api.Assertions.fail;
27  
28  import java.io.ByteArrayInputStream;
29  import java.io.ByteArrayOutputStream;
30  import java.io.ObjectInputStream;
31  import java.io.ObjectOutputStream;
32  import java.sql.Connection;
33  import java.sql.PreparedStatement;
34  import java.sql.ResultSet;
35  import java.sql.SQLException;
36  import java.sql.Statement;
37  import java.time.Duration;
38  import java.util.HashMap;
39  import java.util.Map;
40  
41  import javax.sql.DataSource;
42  
43  import org.apache.commons.dbcp2.TestConnectionPool;
44  import org.apache.commons.dbcp2.TesterDriver;
45  import org.apache.commons.dbcp2.cpdsadapter.DriverAdapterCPDS;
46  import org.junit.jupiter.api.AfterEach;
47  import org.junit.jupiter.api.BeforeEach;
48  import org.junit.jupiter.api.Test;
49  
50  /**
51   */
52  public class TestPerUserPoolDataSource extends TestConnectionPool {
53  
54      private static final Duration DURATION_1_MILLISECOND = Duration.ofMillis(1);
55  
56      private String user;
57  
58      private DataSource ds;
59  
60      @Override
61      protected Connection getConnection() throws SQLException {
62          return ds.getConnection(user,"bar");
63      }
64  
65      @BeforeEach
66      public void setUp() throws Exception {
67          user = "foo";
68          final DriverAdapterCPDS pcds = new DriverAdapterCPDS();
69          pcds.setDriver("org.apache.commons.dbcp2.TesterDriver");
70          pcds.setUrl("jdbc:apache:commons:testdriver");
71          pcds.setUser(user);
72          pcds.setPassword("bar");
73          pcds.setAccessToUnderlyingConnectionAllowed(true);
74  
75          final PerUserPoolDataSource tds = new PerUserPoolDataSource();
76          tds.setConnectionPoolDataSource(pcds);
77          tds.setDefaultMaxTotal(getMaxTotal());
78          tds.setDefaultMaxWait(getMaxWaitDuration());
79          tds.setPerUserMaxTotal(user, getMaxTotal());
80          tds.setPerUserMaxWait(user, getMaxWaitDuration());
81          tds.setDefaultTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
82          tds.setDefaultAutoCommit(Boolean.TRUE);
83          ds = tds;
84      }
85  
86      @Override
87      @AfterEach
88      public void tearDown() throws Exception {
89          super.tearDown();
90          ((PerUserPoolDataSource) ds).close();
91      }
92  
93      // See DBCP-8
94      @Test
95      public void testChangePassword() throws Exception {
96          assertThrows(SQLException.class, () -> ds.getConnection(user, "bay"));
97          final Connection con1 = ds.getConnection(user, "bar");
98          final Connection con2 = ds.getConnection(user, "bar");
99          final Connection con3 = ds.getConnection(user, "bar");
100         con1.close();
101         con2.close();
102         TesterDriver.addUser(user,"bay"); // change the user/password setting
103         try {
104             final Connection con4 = ds.getConnection(user, "bay"); // new password
105             // Idle instances with old password should have been cleared
106             assertEquals(0, ((PerUserPoolDataSource) ds).getNumIdle(user),
107                     "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),
111                     "Should be one idle connection in the pool");
112             try (Connection c = ds.getConnection(user, "bar")) { // old password
113                 fail("Should have generated SQLException");
114             } catch (final SQLException expected) {
115             }
116             final Connection con5 = ds.getConnection(user, "bay"); // take the idle one
117             con3.close(); // Return a connection with the old password
118             ds.getConnection(user, "bay").close();  // will try bad returned connection and destroy it
119             assertEquals(1, ((PerUserPoolDataSource) ds).getNumIdle(user),
120                     "Should be one idle connection in the pool");
121             con5.close();
122         } finally {
123             TesterDriver.addUser(user,"bar");
124         }
125     }
126 
127     @Override
128     @Test
129     public void testClosing()
130         throws Exception
131     {
132         final Connection[] c = new Connection[getMaxTotal()];
133         // open the maximum connections
134         for (int i=0; i<c.length; i++)
135         {
136             c[i] = ds.getConnection();
137         }
138 
139         // close one of the connections
140         c[0].close();
141         assertTrue(c[0].isClosed());
142 
143         // get a new connection
144         c[0] = ds.getConnection();
145 
146         for (final Connection element : c) {
147             element.close();
148         }
149     }
150 
151     @Test
152     public void testClosingWithUserName()
153         throws Exception
154     {
155         final Connection[] c = new Connection[getMaxTotal()];
156         // open the maximum connections
157         for (int i=0; i<c.length; i++)
158         {
159             c[i] = ds.getConnection("u1", "p1");
160         }
161 
162         // close one of the connections
163         c[0].close();
164         assertTrue(c[0].isClosed());
165         // get a new connection
166         c[0] = ds.getConnection("u1", "p1");
167 
168         for (final Connection element : c) {
169             element.close();
170         }
171 
172         // open the maximum connections
173         for (int i=0; i<c.length; i++)
174         {
175             c[i] = ds.getConnection("u1", "p1");
176         }
177         for (final Connection element : c) {
178             element.close();
179         }
180     }
181 
182     // see issue https://issues.apache.org/bugzilla/show_bug.cgi?id=23843
183     @Test
184     public void testDefaultUser1() throws Exception {
185         TesterDriver.addUser("mkh", "password");
186         TesterDriver.addUser("hanafey", "password");
187         TesterDriver.addUser("jsmith", "password");
188 
189         final PerUserPoolDataSource puds = (PerUserPoolDataSource) ds;
190         puds.setPerUserMaxTotal("jsmith", 2);
191         final String[] users = {"mkh", "hanafey", "jsmith"};
192         final String password = "password";
193         final Connection[] c = new Connection[users.length];
194         for (int i = 0; i < users.length; i++) {
195             c[i] = puds.getConnection(users[i], password);
196             assertEquals(users[i], getUsername(c[i]));
197         }
198         for (int i = 0; i < users.length; i++) {
199             c[i].close();
200         }
201     }
202 
203     // see issue https://issues.apache.org/bugzilla/show_bug.cgi?id=23843
204     @Test
205     public void testDefaultUser2() throws Exception {
206         TesterDriver.addUser("mkh", "password");
207         TesterDriver.addUser("hanafey", "password");
208         TesterDriver.addUser("jsmith", "password");
209 
210         final PerUserPoolDataSource puds = (PerUserPoolDataSource) ds;
211         puds.setPerUserMaxTotal("jsmith", 2);
212         final String[] users = {"jsmith", "hanafey", "mkh"};
213         final String password = "password";
214         final Connection[] c = new Connection[users.length];
215         for (int i = 0; i < users.length; i++) {
216             c[i] = puds.getConnection(users[i], password);
217             assertEquals(users[i], getUsername(c[i]));
218         }
219         for (int i = 0; i < users.length; i++) {
220             c[i].close();
221         }
222     }
223 
224     @SuppressWarnings("deprecation")
225     @Test
226     public void testDepreactedAccessors() {
227         try (final PerUserPoolDataSource ds = new PerUserPoolDataSource()) {
228             int i = 0;
229             //
230             i++;
231             ds.setDefaultMaxWaitMillis(i);
232             assertEquals(i, ds.getDefaultMaxWaitMillis());
233             assertEquals(Duration.ofMillis(i), ds.getDefaultMaxWait());
234             //
235             i++;
236             ds.setDefaultMinEvictableIdleTimeMillis(i);
237             assertEquals(i, ds.getDefaultMinEvictableIdleTimeMillis());
238             assertEquals(Duration.ofMillis(i), ds.getDefaultMinEvictableIdleDuration());
239             //
240             i++;
241             ds.setDefaultSoftMinEvictableIdleTimeMillis(i);
242             assertEquals(i, ds.getDefaultSoftMinEvictableIdleTimeMillis());
243             assertEquals(Duration.ofMillis(i), ds.getDefaultSoftMinEvictableIdleDuration());
244             //
245             i++;
246             ds.setDefaultTimeBetweenEvictionRunsMillis(i);
247             assertEquals(i, ds.getDefaultTimeBetweenEvictionRunsMillis());
248             assertEquals(Duration.ofMillis(i), ds.getDefaultDurationBetweenEvictionRuns());
249             //
250             i++;
251             ds.setPerUserMaxWaitMillis(user, Long.valueOf(i));
252             assertEquals(i, ds.getPerUserMaxWaitMillis(user));
253             assertEquals(Duration.ofMillis(i), ds.getPerUserMaxWaitDuration(user));
254             //
255             i++;
256             ds.setPerUserMinEvictableIdleTimeMillis(user, Long.valueOf(i));
257             assertEquals(i, ds.getPerUserMinEvictableIdleTimeMillis(user));
258             assertEquals(Duration.ofMillis(i), ds.getPerUserMinEvictableIdleDuration(user));
259             //
260             i++;
261             ds.setPerUserSoftMinEvictableIdleTimeMillis(user, Long.valueOf(i));
262             assertEquals(i, ds.getPerUserSoftMinEvictableIdleTimeMillis(user));
263             assertEquals(Duration.ofMillis(i), ds.getPerUserSoftMinEvictableIdleDuration(user));
264             //
265             i++;
266             ds.setPerUserTimeBetweenEvictionRunsMillis(user, Long.valueOf(i));
267             assertEquals(i, ds.getPerUserTimeBetweenEvictionRunsMillis(user));
268             assertEquals(Duration.ofMillis(i), ds.getPerUserDurationBetweenEvictionRuns(user));
269         }
270     }
271 
272     /**
273      * Switching 'u1 to 'u2' and 'p1' to 'p2' will
274      * exhibit the bug detailed in
275      * https://issues.apache.org/bugzilla/show_bug.cgi?id=18905
276      */
277     @Test
278     public void testIncorrectPassword() throws SQLException {
279         // Use bad password
280         assertThrows(SQLException.class, () -> ds.getConnection("u1", "zlsafjk"));
281 
282         // Use good password
283         ds.getConnection("u1", "p1").close();
284         try (Connection c = ds.getConnection("u1", "x")){
285             fail("Able to retrieve connection with incorrect password");
286         } catch (final SQLException e) {
287             if (!e.getMessage().startsWith("Given password did not match")) {
288                 throw e;
289             }
290             // else the exception was expected
291         }
292 
293         // Make sure we can still use our good password.
294         ds.getConnection("u1", "p1").close();
295 
296         // Try related users and passwords
297         ds.getConnection(user, "bar").close();
298         assertThrows(SQLException.class, () -> ds.getConnection("foob", "ar"));
299         assertThrows(SQLException.class, () -> ds.getConnection(user, "baz"));
300     }
301 
302     @Override
303     @Test
304     public void testMaxTotal() throws Exception {
305         final Connection[] c = new Connection[getMaxTotal()];
306         for (int i = 0; i < c.length; i++) {
307             c[i] = ds.getConnection();
308             assertNotNull(c[i]);
309         }
310 
311         try (Connection conn = ds.getConnection()) {
312             fail("Allowed to open more than DefaultMaxTotal connections.");
313         } catch (final java.sql.SQLException e) {
314             // should only be able to open 10 connections, so this test should
315             // throw an exception
316         }
317 
318         for (final Connection element : c) {
319             element.close();
320         }
321     }
322 
323     /**
324      * Verify that defaultMaxWaitMillis = 0 means immediate failure when
325      * pool is exhausted.
326      */
327     @Test
328     public void testMaxWaitMillisZero() throws Exception {
329         final PerUserPoolDataSource tds = (PerUserPoolDataSource) ds;
330         tds.setDefaultMaxWait(Duration.ZERO);
331         tds.setPerUserMaxTotal("u1", 1);
332         try (final Connection conn = tds.getConnection("u1", "p1")) {
333             assertThrows(SQLException.class, () -> tds.getConnection("u1", "p1"));
334         }
335     }
336 
337     @Test
338     public void testMultipleThreads1() throws Exception {
339         // Override wait time in order to allow for Thread.sleep(1) sometimes taking a lot longer on
340         // some JVMs, e.g. Windows.
341         final Duration defaultMaxWaitDuration = Duration.ofMillis(430);
342         ((PerUserPoolDataSource) ds).setDefaultMaxWait(defaultMaxWaitDuration);
343         ((PerUserPoolDataSource) ds).setPerUserMaxWait(user, defaultMaxWaitDuration);
344         multipleThreads(Duration.ofMillis(1), false, false, defaultMaxWaitDuration);
345     }
346 
347     @Test
348     public void testMultipleThreads2() throws Exception {
349         final Duration defaultMaxWaitDuration = Duration.ofMillis(500);
350         ((PerUserPoolDataSource) ds).setDefaultMaxWait(defaultMaxWaitDuration);
351         ((PerUserPoolDataSource) ds).setPerUserMaxWait(user, defaultMaxWaitDuration);
352         multipleThreads(defaultMaxWaitDuration.multipliedBy(2), true, true, defaultMaxWaitDuration);
353     }
354 
355     @Override
356     @Test
357     public void testOpening()
358         throws Exception
359     {
360         final Connection[] c = new Connection[getMaxTotal()];
361         // test that opening new connections is not closing previous
362         for (int i=0; i<c.length; i++)
363         {
364             c[i] = ds.getConnection();
365             assertNotNull(c[i]);
366             for (int j=0; j<=i; j++)
367             {
368                 assertFalse(c[j].isClosed());
369             }
370         }
371 
372         for (final Connection element : c) {
373             element.close();
374         }
375     }
376 
377     /**
378      * Test per user block when exhausted, with the backing map initialized before.
379      */
380     @Test
381     public void testPerUserBlockWhenExhaustedMapInitialized() {
382         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
383         Map<String, Boolean> userDefaultBlockWhenExhausted = new HashMap<>();
384         userDefaultBlockWhenExhausted.put("key", Boolean.FALSE);
385         ds.setPerUserBlockWhenExhausted(userDefaultBlockWhenExhausted);
386         assertEquals(Boolean.FALSE, ds.getPerUserBlockWhenExhausted("key"));
387         // when the code above is executed, the backing map was initalized
388         // now check if that still works. The backing map is clear'ed.
389         userDefaultBlockWhenExhausted = new HashMap<>();
390         userDefaultBlockWhenExhausted.put("anonymous", Boolean.FALSE);
391         ds.setPerUserBlockWhenExhausted(userDefaultBlockWhenExhausted);
392         // now the previously entered value was cleared, so it will be back to the
393         // default value of TRUE
394         assertEquals(Boolean.TRUE, ds.getPerUserBlockWhenExhausted("key"));
395         // and our new value exists too
396         assertEquals(Boolean.FALSE, ds.getPerUserBlockWhenExhausted("anonymous"));
397     }
398 
399     /**
400      * Test per user block when exhausted, with the backing map not initialized before.
401      * Instead we pass the map.
402      */
403     @Test
404     public void testPerUserBlockWhenExhaustedMapNotInitialized() {
405         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
406         final Map<String, Boolean> userDefaultBlockWhenExhausted = new HashMap<>();
407         userDefaultBlockWhenExhausted.put("key", Boolean.TRUE);
408         ds.setPerUserBlockWhenExhausted(userDefaultBlockWhenExhausted);
409         assertEquals(Boolean.TRUE, ds.getPerUserBlockWhenExhausted("key"));
410     }
411 
412     /**
413      * Test per user block when exhausted, with the backing map not initialized before.
414      * Instead, we pass the map. And furthermore, we are now searching for an inexistent
415      * key, which should return the default value.
416      */
417     @Test
418     public void testPerUserBlockWhenExhaustedMapNotInitializedMissingKey() {
419         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
420         final Map<String, Boolean> userDefaultBlockWhenExhausted = new HashMap<>();
421         userDefaultBlockWhenExhausted.put("key", Boolean.FALSE);
422         ds.setPerUserBlockWhenExhausted(userDefaultBlockWhenExhausted);
423         assertEquals(ds.getDefaultBlockWhenExhausted(), ds.getPerUserBlockWhenExhausted("missingkey"));
424     }
425 
426     /**
427      * Test per user block when exhausted, with the backing map not initialized before.
428      * Instead we pass the user and value, and hence the map is initialized beforehand.
429      * After that, we pass another user, so both values should still be present. The
430      * PerUserPoolDataSource does not clear the perUserPoolDataSource map, unless you
431      * pass a new map, using another internal/package method.
432      */
433     @Test
434     public void testPerUserBlockWhenExhaustedWithUserMapInitialized() {
435         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
436         ds.setPerUserBlockWhenExhausted(user, Boolean.FALSE);
437         assertEquals(Boolean.FALSE, ds.getPerUserBlockWhenExhausted(user));
438         // when the code above is executed, the backing map was initalized
439         // now check if that still works. The backing map is NOT clear'ed.
440         ds.setPerUserBlockWhenExhausted("anotheruser", Boolean.FALSE);
441         assertEquals(Boolean.FALSE, ds.getPerUserBlockWhenExhausted(user));
442         assertEquals(Boolean.FALSE, ds.getPerUserBlockWhenExhausted("anotheruser"));
443     }
444 
445     /**
446      * Test per user block when exhausted, with the backing map not initialized before.
447      * Instead we pass the user and value, and hence the map is initialized beforehand.
448      */
449     @Test
450     public void testPerUserBlockWhenExhaustedWithUserMapNotInitialized() {
451         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
452         ds.setPerUserBlockWhenExhausted(user, Boolean.FALSE);
453         assertEquals(Boolean.FALSE, ds.getPerUserBlockWhenExhausted(user));
454     }
455 
456     /**
457      * Test per user block when exhausted, with the backing map not initialized before.
458      * Instead we pass the user and value, and hence the map is initialized beforehand.
459      * Furthermore, we are now searching for an inexistent key, which should return the
460      * default value.
461      */
462     @Test
463     public 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     @Test
470     public void testPerUserDefaultAutoCommitMapInitialized() {
471         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
472         Map<String, Boolean> values = new HashMap<>();
473         values.put("key", Boolean.FALSE);
474         ds.setPerUserDefaultAutoCommit(values);
475         assertEquals(Boolean.FALSE, ds.getPerUserDefaultAutoCommit("key"));
476         values = new HashMap<>();
477         values.put("anonymous", Boolean.FALSE);
478         ds.setPerUserDefaultAutoCommit(values);
479         assertNull(ds.getPerUserDefaultAutoCommit("key"));
480         assertEquals(Boolean.FALSE, ds.getPerUserDefaultAutoCommit("anonymous"));
481     }
482 
483     // getters and setters. Most follow the same pattern. The initial tests contain a more
484     // complete documentation, which can be helpful when write/understanding the other methods.
485 
486     // -- per user block when exhausted
487 
488     @Test
489     public 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     public 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     public 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     public 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     public 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     @Test
533     public void testPerUserDefaultReadOnlyMapInitialized() {
534         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
535         Map<String, Boolean> values = new HashMap<>();
536         values.put("key", Boolean.FALSE);
537         ds.setPerUserDefaultReadOnly(values);
538         assertEquals(Boolean.FALSE, ds.getPerUserDefaultReadOnly("key"));
539         values = new HashMap<>();
540         values.put("anonymous", Boolean.FALSE);
541         ds.setPerUserDefaultReadOnly(values);
542         assertNull(ds.getPerUserDefaultReadOnly("key"));
543         assertEquals(Boolean.FALSE, ds.getPerUserDefaultReadOnly("anonymous"));
544     }
545 
546     // -- per user default auto commit
547 
548     @Test
549     public 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     public 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     public 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     public 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     public 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     @Test
593     public void testPerUserDefaultTransactionIsolationMapInitialized() {
594         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
595         Map<String, Integer> values = new HashMap<>();
596         values.put("key", 0);
597         ds.setPerUserDefaultTransactionIsolation(values);
598         assertEquals((Integer) 0, ds.getPerUserDefaultTransactionIsolation("key"));
599         values = new HashMap<>();
600         values.put("anonymous", 0);
601         ds.setPerUserDefaultTransactionIsolation(values);
602         // TODO this is not consistent with the other methods
603         assertNull(ds.getPerUserDefaultTransactionIsolation("key"));
604         assertEquals((Integer) 0, ds.getPerUserDefaultTransactionIsolation("anonymous"));
605     }
606 
607     // -- per user default read only
608 
609     @Test
610     public 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     public 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     public 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     public 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     public 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     @Test
654     public void testPerUserDurationBetweenEvictionRunsMapInitialized() {
655         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
656         Map<String, Duration> values = new HashMap<>();
657         values.put("key", Duration.ZERO);
658         ds.setPerUserDurationBetweenEvictionRuns(values);
659         assertEquals(0L, ds.getPerUserTimeBetweenEvictionRunsMillis("key"));
660         assertEquals(Duration.ZERO, ds.getPerUserDurationBetweenEvictionRuns("key"));
661         values = new HashMap<>();
662         values.put("anonymous", Duration.ZERO);
663         ds.setPerUserDurationBetweenEvictionRuns(values);
664         assertEquals(ds.getDefaultTimeBetweenEvictionRunsMillis(), ds.getPerUserTimeBetweenEvictionRunsMillis("key"));
665         assertEquals(ds.getDefaultDurationBetweenEvictionRuns(), ds.getPerUserDurationBetweenEvictionRuns("key"));
666         assertEquals(0L, ds.getPerUserTimeBetweenEvictionRunsMillis("anonymous"));
667         assertEquals(Duration.ZERO, ds.getPerUserDurationBetweenEvictionRuns("anonymous"));
668     }
669 
670     // -- per user default transaction isolation
671 
672     @Test
673     public 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     public 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     public 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     public 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     public 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     @Test
725     public void testPerUserEvictionPolicyClassNameWithUserMapInitialized() {
726         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
727         ds.setPerUserEvictionPolicyClassName(user, "bar");
728         assertEquals("bar", ds.getPerUserEvictionPolicyClassName(user));
729         ds.setPerUserEvictionPolicyClassName("anotheruser", "bar");
730         assertEquals("bar", ds.getPerUserEvictionPolicyClassName(user));
731         assertEquals("bar", ds.getPerUserEvictionPolicyClassName("anotheruser"));
732     }
733 
734     // -- per user eviction policy class name
735 
736     @Test
737     public 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     public 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     public 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     public 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     public 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     @Test
783     public void testPerUserLifoWithUserMapInitialized() {
784         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
785         ds.setPerUserLifo(user, Boolean.FALSE);
786         assertEquals(Boolean.FALSE, ds.getPerUserLifo(user));
787         ds.setPerUserLifo("anotheruser", Boolean.FALSE);
788         assertEquals(Boolean.FALSE, ds.getPerUserLifo(user));
789         assertEquals(Boolean.FALSE, ds.getPerUserLifo("anotheruser"));
790     }
791 
792     // -- per user lifo
793 
794     @Test
795     public 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     public 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     public 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     public 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     public 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     @Test
841     public void testPerUserMaxIdleWithUserMapInitialized() {
842         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
843         ds.setPerUserMaxIdle(user, 0);
844         assertEquals((Integer) 0, (Integer) ds.getPerUserMaxIdle(user));
845         ds.setPerUserMaxIdle("anotheruser", 0);
846         assertEquals((Integer) 0, (Integer) ds.getPerUserMaxIdle(user));
847         assertEquals((Integer) 0, (Integer) ds.getPerUserMaxIdle("anotheruser"));
848     }
849 
850     // -- per user max idle
851 
852     @Test
853     public 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     public 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     public 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     public 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     public 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     public 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     public 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     public 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     public 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     public 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     public 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     @Test
955     @SuppressWarnings("deprecation")
956     public void testPerUserMaxWaitMillisWithUserMapInitialized_Deprecated() {
957         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
958         ds.setPerUserMaxWaitMillis(user, 0L);
959         assertEquals(0L, ds.getPerUserMaxWaitMillis(user));
960         ds.setPerUserMaxWaitMillis("anotheruser", 0L);
961         assertEquals(0L, ds.getPerUserMaxWaitMillis(user));
962         assertEquals(0L, ds.getPerUserMaxWaitMillis("anotheruser"));
963     }
964 
965     // -- per user max wait millis
966 
967     @Test
968     @SuppressWarnings("deprecation")
969     public void testPerUserMaxWaitMillisWithUserMapNotInitialized_Deprecated() {
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     public void testPerUserMaxWaitMillisWithUserMapNotInitializedMissingKey_Deprecated() {
978         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
979         ds.setPerUserMaxWaitMillis("whatismyuseragain?", 0L);
980         assertEquals(ds.getDefaultMaxWaitMillis(), ds.getPerUserMaxWaitMillis("missingkey"));
981     }
982 
983     @Test
984     public 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     public 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     public 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     @Test
1060     public void testPerUserMinEvictableIdleDurationMapNotInitializedMissingKey() {
1061         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1062         final Map<String, Duration> values = new HashMap<>();
1063         values.put("key", Duration.ZERO);
1064         ds.setPerUserMinEvictableIdle(values);
1065         assertEquals(ds.getDefaultMinEvictableIdleTimeMillis(), ds.getPerUserMinEvictableIdleTimeMillis("missingkey"));
1066         assertEquals(ds.getDefaultMinEvictableIdleDuration(), ds.getPerUserMinEvictableIdleDuration("missingkey"));
1067     }
1068 
1069     // -- per user min evictable idle time millis
1070 
1071     @Test
1072     public 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     public 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     public 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     public 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     public 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     @Test
1119     public void testPerUserMinIdleMapNotInitializedMissingKey() {
1120         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1121         final Map<String, Integer> values = new HashMap<>();
1122         values.put("key", 0);
1123         ds.setPerUserMinIdle(values);
1124         assertEquals((Integer) ds.getDefaultMinIdle(), (Integer) ds.getPerUserMinIdle("missingkey"));
1125     }
1126 
1127     // -- per user min idle
1128 
1129     @Test
1130     public 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     public 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     public 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     public 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     public 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     @Test
1177     public void testPerUserNumTestsPerEvictionRunMapNotInitializedMissingKey() {
1178         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1179         final Map<String, Integer> values = new HashMap<>();
1180         values.put("key", 0);
1181         ds.setPerUserNumTestsPerEvictionRun(values);
1182         assertEquals((Integer) ds.getDefaultNumTestsPerEvictionRun(), (Integer) ds.getPerUserNumTestsPerEvictionRun("missingkey"));
1183     }
1184 
1185     // -- per user num tests per eviction run
1186 
1187     @Test
1188     public 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     public 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     public 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     public 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     public 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     @Test
1239     public void testPerUserSoftMinEvictableIdleDurationMapNotInitializedMissingKey() {
1240         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1241         final Map<String, Duration> values = new HashMap<>();
1242         values.put("key", Duration.ZERO);
1243         ds.setPerUserSoftMinEvictableIdle(values);
1244         assertEquals(ds.getDefaultSoftMinEvictableIdleTimeMillis(), ds.getPerUserSoftMinEvictableIdleTimeMillis("missingkey"));
1245         assertEquals(ds.getDefaultSoftMinEvictableIdleDuration(), ds.getPerUserSoftMinEvictableIdleDuration("missingkey"));
1246     }
1247 
1248     // -- per user soft min evictable idle time millis
1249 
1250     @Test
1251     public 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     public 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     public 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     public 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     public 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     @Test
1298     public void testPerUserTestOnBorrowMapNotInitializedMissingKey() {
1299         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1300         final Map<String, Boolean> values = new HashMap<>();
1301         values.put("key", Boolean.FALSE);
1302         ds.setPerUserTestOnBorrow(values);
1303         assertEquals(ds.getDefaultTestOnBorrow(), ds.getPerUserTestOnBorrow("missingkey"));
1304     }
1305 
1306     // -- per user test on borrow
1307 
1308     @Test
1309     public 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     public 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     public 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     public 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     public 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     @Test
1356     public void testPerUserTestOnCreateMapNotInitializedMissingKey() {
1357         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
1358         final Map<String, Boolean> values = new HashMap<>();
1359         values.put("key", Boolean.FALSE);
1360         ds.setPerUserTestOnCreate(values);
1361         assertEquals(ds.getDefaultTestOnCreate(), ds.getPerUserTestOnCreate("missingkey"));
1362     }
1363 
1364     // -- per user test on create
1365 
1366     @Test
1367     public 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     public 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     public 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     public 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     public 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     public 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     public 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     public 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     public 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     public 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     public 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     public 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     public 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     public 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     public 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     public 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     public 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     public 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     public 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         try (Statement s = conn.createStatement()) {
1590             fail("Can't use closed connections");
1591         } catch (final SQLException e) {
1592             // expected
1593         }
1594 
1595         conn = ds.getConnection();
1596         assertNotNull(conn);
1597 
1598         stmt = conn.prepareStatement("select * from dual");
1599         assertNotNull(stmt);
1600         rset = stmt.executeQuery();
1601         assertNotNull(rset);
1602         assertTrue(rset.next());
1603         rset.close();
1604         stmt.close();
1605 
1606         stmt = conn.prepareStatement("select * from dual");
1607         assertNotNull(stmt);
1608         rset = stmt.executeQuery();
1609         assertNotNull(rset);
1610         assertTrue(rset.next());
1611         rset.close();
1612         stmt.close();
1613 
1614         conn.close();
1615         conn = null;
1616     }
1617 
1618     @Test
1619     public void testSimpleWithUsername() throws Exception {
1620         try (final Connection conn = ds.getConnection("u1", "p1")) {
1621             assertNotNull(conn);
1622             try (final PreparedStatement stmt = conn.prepareStatement("select * from dual")) {
1623                 assertNotNull(stmt);
1624                 try (final ResultSet rset = stmt.executeQuery()) {
1625                     assertNotNull(rset);
1626                     assertTrue(rset.next());
1627                 }
1628             }
1629         }
1630     }
1631 
1632     @Test
1633     public void testTransactionIsolationBehavior() throws Exception {
1634         try (Connection conn = getConnection()) {
1635             assertNotNull(conn);
1636             assertEquals(Connection.TRANSACTION_READ_COMMITTED, conn.getTransactionIsolation());
1637             conn.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
1638         }
1639 
1640         final Connection conn2 = getConnection();
1641         assertEquals(Connection.TRANSACTION_READ_COMMITTED, conn2.getTransactionIsolation());
1642 
1643         final Connection conn3 = getConnection();
1644         assertEquals(Connection.TRANSACTION_READ_COMMITTED, conn3.getTransactionIsolation());
1645         conn2.close();
1646         conn3.close();
1647     }
1648 
1649     // see issue https://issues.apache.org/bugzilla/show_bug.cgi?id=23843
1650     // unregistered user is in the same pool as without user name
1651     @Test
1652     public void testUnregisteredUser() throws Exception {
1653         final PerUserPoolDataSource tds = (PerUserPoolDataSource) ds;
1654 
1655         assertEquals(0, tds.getNumActive());
1656         assertEquals(0, tds.getNumIdle());
1657 
1658         try (Connection conn = tds.getConnection()) {
1659             assertNotNull(conn);
1660             assertEquals(1, tds.getNumActive());
1661             assertEquals(0, tds.getNumIdle());
1662         }
1663         assertEquals(0, tds.getNumActive());
1664         assertEquals(1, tds.getNumIdle());
1665 
1666         try (Connection conn = tds.getConnection("u1", "p1")) {
1667             assertNotNull(conn);
1668             assertEquals(0, tds.getNumActive());
1669             assertEquals(1, tds.getNumIdle());
1670             assertEquals(1, tds.getNumActive("u1"));
1671             assertEquals(0, tds.getNumIdle("u1"));
1672         }
1673         assertEquals(0, tds.getNumActive());
1674         assertEquals(1, tds.getNumIdle());
1675         assertEquals(0, tds.getNumActive("u1"));
1676         assertEquals(1, tds.getNumIdle("u1"));
1677     }
1678 
1679 }