You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2021/06/06 23:22:01 UTC

[commons-dbcp] branch master updated (982e9ca -> c512dca)

This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/commons-dbcp.git.


    from 982e9ca  Use UserPassKey internally.
     new 6272dd6  Sort members.
     new c512dca  Add and reuse InstanceKeyDataSource.{get|set}DefaultMaxWait(Duration), deprecate .{get|set}DefaultMaxWaitMillis(long).

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 src/changes/changes.xml                            |   18 +-
 .../dbcp2/datasources/InstanceKeyDataSource.java   |   45 +-
 .../dbcp2/datasources/PerUserPoolDataSource.java   |   12 +-
 .../dbcp2/datasources/SharedPoolDataSource.java    |    2 +-
 .../datasources/TestPerUserPoolDataSource.java     | 1258 ++++++++++----------
 5 files changed, 683 insertions(+), 652 deletions(-)

[commons-dbcp] 02/02: Add and reuse InstanceKeyDataSource.{get|set}DefaultMaxWait(Duration), deprecate .{get|set}DefaultMaxWaitMillis(long).

Posted by gg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-dbcp.git

commit c512dca8cebf05643a6905868f884cd909cc34ee
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Sun Jun 6 19:21:57 2021 -0400

    Add and reuse InstanceKeyDataSource.{get|set}DefaultMaxWait(Duration),
    deprecate .{get|set}DefaultMaxWaitMillis(long).
    
    Javadoc.
---
 src/changes/changes.xml                            | 18 ++++++---
 .../dbcp2/datasources/InstanceKeyDataSource.java   | 45 +++++++++++++++++-----
 .../dbcp2/datasources/PerUserPoolDataSource.java   | 12 +++---
 .../dbcp2/datasources/SharedPoolDataSource.java    |  2 +-
 4 files changed, 54 insertions(+), 23 deletions(-)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 5721121..6bb24e1 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -63,22 +63,28 @@ The <action> type attribute can be add,update,fix,remove.
     <release version="2.9.0" date="202Y-MM-DD" description="This is a minor release, including bug fixes and enhancements.">
       <!-- ADDS -->
       <action dev="ggregory" type="add" due-to="Gary Gregory">
-         Add and reuse Constants.KEY_USER and Constants.KEY_PASSWORD.
+        Add and reuse Constants.KEY_USER and Constants.KEY_PASSWORD.
       </action>
       <action dev="ggregory" type="add" due-to="Frank Gasdorf, Gary Gregory">
-         Add and reuse DataSourceMXBean.
+        Add and reuse DataSourceMXBean.
       </action>
       <action dev="ggregory" type="add" due-to="Gary Gregory">
-         Add and reuse DriverAdapterCPDS.{get|set}DurationBetweenEvictionRuns(), deprecate {get|set}TimeBetweenEvictionRunsMillis(long).
+        Add and reuse DriverAdapterCPDS.{get|set}DurationBetweenEvictionRuns(), deprecate {get|set}TimeBetweenEvictionRunsMillis(long).
       </action>
       <action dev="ggregory" type="add" due-to="Gary Gregory">
-         Add and reuse DriverAdapterCPDS.{get|set}MinEvictableIdleDuration(), deprecate {get|set}MinEvictableIdleTimeMillis(int).
+        Add and reuse DriverAdapterCPDS.{get|set}MinEvictableIdleDuration(), deprecate {get|set}MinEvictableIdleTimeMillis(int).
       </action>
       <action dev="ggregory" type="add" due-to="Gary Gregory">
-         Add and reuse CPDSConnectionFactory.setMaxConnLifetime(Duration), deprecate setMaxConnLifetimeMillis(long).
+        Add and reuse CPDSConnectionFactory.setMaxConnLifetime(Duration), deprecate setMaxConnLifetimeMillis(long).
       </action>
       <action dev="ggregory" type="add" due-to="Gary Gregory">
-         Add and reuse KeyedCPDSConnectionFactory.setMaxConnLifetime(Duration), deprecate setMaxConnLifetimeMillis(long).
+        Add and reuse KeyedCPDSConnectionFactory.setMaxConnLifetime(Duration), deprecate setMaxConnLifetimeMillis(long).
+      </action>
+      <action dev="ggregory" type="add" due-to="Gary Gregory">
+        Add and reuse KeyedCPDSConnectionFactory.setMaxConnLifetime(Duration), deprecate setMaxConnLifetimeMillis(long).
+      </action>
+      <action dev="ggregory" type="add" due-to="Gary Gregory">
+        Add and reuse InstanceKeyDataSource.{get|set}DefaultMaxWait(Duration), deprecate {get|set}DefaultMaxWaitMillis(long).
       </action>
       <!--  FIXES -->
       <action dev="ggregory" type="fix" issue="DBCP-569" due-to="Florent Guillaume">
diff --git a/src/main/java/org/apache/commons/dbcp2/datasources/InstanceKeyDataSource.java b/src/main/java/org/apache/commons/dbcp2/datasources/InstanceKeyDataSource.java
index e6d3893..9d2aa60 100644
--- a/src/main/java/org/apache/commons/dbcp2/datasources/InstanceKeyDataSource.java
+++ b/src/main/java/org/apache/commons/dbcp2/datasources/InstanceKeyDataSource.java
@@ -116,7 +116,7 @@ public abstract class InstanceKeyDataSource implements DataSource, Referenceable
     private boolean defaultLifo = BaseObjectPoolConfig.DEFAULT_LIFO;
     private int defaultMaxIdle = GenericKeyedObjectPoolConfig.DEFAULT_MAX_IDLE_PER_KEY;
     private int defaultMaxTotal = GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL;
-    private long defaultMaxWaitMillis = BaseObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS;
+    private Duration defaultMaxWaitDuration = BaseObjectPoolConfig.DEFAULT_MAX_WAIT;
     private long defaultMinEvictableIdleTimeMillis = BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
     private int defaultMinIdle = GenericKeyedObjectPoolConfig.DEFAULT_MIN_IDLE_PER_KEY;
     private int defaultNumTestsPerEvictionRun = BaseObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
@@ -293,9 +293,21 @@ public abstract class InstanceKeyDataSource implements DataSource, Referenceable
      * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitMillis()} for each per user pool.
      *
      * @return The default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitMillis()} for each per user pool.
+     * @since 2.9.0
      */
+    public Duration getDefaultMaxWait() {
+        return this.defaultMaxWaitDuration;
+    }
+
+    /**
+     * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitMillis()} for each per user pool.
+     *
+     * @return The default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitMillis()} for each per user pool.
+     * @deprecated Use {@link #getDefaultMaxWait()}.
+     */
+    @Deprecated
     public long getDefaultMaxWaitMillis() {
-        return this.defaultMaxWaitMillis;
+        return getDefaultMaxWait().toMillis();
     }
 
     /**
@@ -303,17 +315,30 @@ public abstract class InstanceKeyDataSource implements DataSource, Referenceable
      *
      * @param maxWaitMillis
      *            The default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitMillis()} for each per user pool.
+     * @since 2.9.0
      */
-    public void setDefaultMaxWaitMillis(final long maxWaitMillis) {
+    public void setDefaultMaxWait(final Duration maxWaitMillis) {
         assertInitializationAllowed();
-        this.defaultMaxWaitMillis = maxWaitMillis;
+        this.defaultMaxWaitDuration = maxWaitMillis;
+    }
+
+    /**
+     * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitMillis()} for each per user pool.
+     *
+     * @param maxWaitMillis
+     *            The default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitMillis()} for each per user pool.
+     * @deprecated Use {@link #setDefaultMaxWait(Duration)}.
+     */
+    @Deprecated
+    public void setDefaultMaxWaitMillis(final long maxWaitMillis) {
+        setDefaultMaxWait(Duration.ofMillis(maxWaitMillis));
     }
 
     /**
-     * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleTimeMillis()} for each per user
+     * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleTime()} for each per user
      * pool.
      *
-     * @return The default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleTimeMillis()} for each per
+     * @return The default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleTime()} for each per
      *         user pool.
      */
     public long getDefaultMinEvictableIdleTimeMillis() {
@@ -321,11 +346,11 @@ public abstract class InstanceKeyDataSource implements DataSource, Referenceable
     }
 
     /**
-     * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleTimeMillis()} for each per user
+     * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleTime()} for each per user
      * pool.
      *
      * @param minEvictableIdleTimeMillis
-     *            The default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleTimeMillis()} for each
+     *            The default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleTime()} for each
      *            per user pool.
      */
     public void setDefaultMinEvictableIdleTimeMillis(final long minEvictableIdleTimeMillis) {
@@ -1113,8 +1138,8 @@ public abstract class InstanceKeyDataSource implements DataSource, Referenceable
         builder.append(defaultMaxIdle);
         builder.append(", defaultMaxTotal=");
         builder.append(defaultMaxTotal);
-        builder.append(", defaultMaxWaitMillis=");
-        builder.append(defaultMaxWaitMillis);
+        builder.append(", defaultMaxWait=");
+        builder.append(defaultMaxWaitDuration);
         builder.append(", defaultMinEvictableIdleTimeMillis=");
         builder.append(defaultMinEvictableIdleTimeMillis);
         builder.append(", defaultMinIdle=");
diff --git a/src/main/java/org/apache/commons/dbcp2/datasources/PerUserPoolDataSource.java b/src/main/java/org/apache/commons/dbcp2/datasources/PerUserPoolDataSource.java
index f2779fb..b469f86 100644
--- a/src/main/java/org/apache/commons/dbcp2/datasources/PerUserPoolDataSource.java
+++ b/src/main/java/org/apache/commons/dbcp2/datasources/PerUserPoolDataSource.java
@@ -346,7 +346,7 @@ public class PerUserPoolDataSource extends InstanceKeyDataSource {
     }
 
     /**
-     * Gets the user specific value for {@link GenericObjectPool#getMinEvictableIdleTimeMillis()} for the specified
+     * Gets the user specific value for {@link GenericObjectPool#getMinEvictableIdleTime()} for the specified
      * user's pool or the default if no user specific value is defined.
      *
      * @param userName
@@ -403,7 +403,7 @@ public class PerUserPoolDataSource extends InstanceKeyDataSource {
     }
 
     /**
-     * Gets the user specific value for {@link GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for the specified
+     * Gets the user specific value for {@link GenericObjectPool#getSoftMinEvictableIdleTime()} for the specified
      * user's pool or the default if no user specific value is defined.
      *
      * @param userName
@@ -498,7 +498,7 @@ public class PerUserPoolDataSource extends InstanceKeyDataSource {
     }
 
     /**
-     * Gets the user specific value for {@link GenericObjectPool#getTimeBetweenEvictionRunsMillis()} for the specified
+     * Gets the user specific value for {@link GenericObjectPool#getTimeBetweenEvictionRuns()} for the specified
      * user's pool or the default if no user specific value is defined.
      *
      * @param userName
@@ -908,7 +908,7 @@ public class PerUserPoolDataSource extends InstanceKeyDataSource {
     }
 
     /**
-     * Sets a user specific value for {@link GenericObjectPool#getMinEvictableIdleTimeMillis()} for the specified user's
+     * Sets a user specific value for {@link GenericObjectPool#getMinEvictableIdleTime()} for the specified user's
      * pool.
      *
      * @param userName
@@ -988,7 +988,7 @@ public class PerUserPoolDataSource extends InstanceKeyDataSource {
     }
 
     /**
-     * Sets a user specific value for {@link GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for the specified
+     * Sets a user specific value for {@link GenericObjectPool#getSoftMinEvictableIdleTime()} for the specified
      * user's pool.
      *
      * @param userName
@@ -1119,7 +1119,7 @@ public class PerUserPoolDataSource extends InstanceKeyDataSource {
     }
 
     /**
-     * Sets a user specific value for {@link GenericObjectPool#getTimeBetweenEvictionRunsMillis ()} for the specified
+     * Sets a user specific value for {@link GenericObjectPool#getTimeBetweenEvictionRuns()} for the specified
      * user's pool.
      *
      * @param userName
diff --git a/src/main/java/org/apache/commons/dbcp2/datasources/SharedPoolDataSource.java b/src/main/java/org/apache/commons/dbcp2/datasources/SharedPoolDataSource.java
index e735c98..de3f1b0 100644
--- a/src/main/java/org/apache/commons/dbcp2/datasources/SharedPoolDataSource.java
+++ b/src/main/java/org/apache/commons/dbcp2/datasources/SharedPoolDataSource.java
@@ -169,7 +169,7 @@ public class SharedPoolDataSource extends InstanceKeyDataSource {
         config.setMaxIdlePerKey(getDefaultMaxIdle());
         config.setMaxTotal(getMaxTotal());
         config.setMaxTotalPerKey(getDefaultMaxTotal());
-        config.setMaxWaitMillis(getDefaultMaxWaitMillis());
+        config.setMaxWaitMillis(getDefaultMaxWait().toMillis());
         config.setMinEvictableIdleTimeMillis(getDefaultMinEvictableIdleTimeMillis());
         config.setMinIdlePerKey(getDefaultMinIdle());
         config.setNumTestsPerEvictionRun(getDefaultNumTestsPerEvictionRun());

[commons-dbcp] 01/02: Sort members.

Posted by gg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-dbcp.git

commit 6272dd6204a8b5cb6be07c92cece94bf540d6172
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Sun Jun 6 13:48:15 2021 -0400

    Sort members.
---
 .../datasources/TestPerUserPoolDataSource.java     | 1258 ++++++++++----------
 1 file changed, 629 insertions(+), 629 deletions(-)

diff --git a/src/test/java/org/apache/commons/dbcp2/datasources/TestPerUserPoolDataSource.java b/src/test/java/org/apache/commons/dbcp2/datasources/TestPerUserPoolDataSource.java
index a261ce9..8acb85f 100644
--- a/src/test/java/org/apache/commons/dbcp2/datasources/TestPerUserPoolDataSource.java
+++ b/src/test/java/org/apache/commons/dbcp2/datasources/TestPerUserPoolDataSource.java
@@ -51,13 +51,13 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
 
     private String user;
 
+    private DataSource ds;
+
     @Override
     protected Connection getConnection() throws SQLException {
         return ds.getConnection(user,"bar");
     }
 
-    private DataSource ds;
-
     @BeforeEach
     public void setUp() throws Exception {
         user = "foo";
@@ -87,76 +87,65 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
         ((PerUserPoolDataSource) ds).close();
     }
 
-    /**
-     * Switching 'u1 to 'u2' and 'p1' to 'p2' will
-     * exhibit the bug detailed in
-     * https://issues.apache.org/bugzilla/show_bug.cgi?id=18905
-     */
+    // See DBCP-8
     @Test
-    public void testIncorrectPassword() throws Exception {
-        // Use bad password
-        try (Connection c = ds.getConnection("u1", "zlsafjk")){
-            fail("Able to retrieve connection with incorrect password");
-        } catch (final SQLException e1) {
-            // should fail
-
-        }
-
-        // Use good password
-        ds.getConnection("u1", "p1").close();
-        try (Connection c = ds.getConnection("u1", "x")){
-            fail("Able to retrieve connection with incorrect password");
-        } catch (final SQLException e) {
-            if (!e.getMessage().startsWith("Given password did not match")) {
-                throw e;
-            }
-            // else the exception was expected
-        }
-
-        // Make sure we can still use our good password.
-        ds.getConnection("u1", "p1").close();
-
-        // Try related users and passwords
-        ds.getConnection(user, "bar").close();
-        try (Connection c = ds.getConnection("foob", "ar")) {
-            fail("Should have caused an SQLException");
-        } catch (final SQLException expected) {
-        }
-        try (Connection c = ds.getConnection(user, "baz")){
+    public void testChangePassword() throws Exception {
+        try (Connection c = ds.getConnection(user, "bay")){
             fail("Should have generated SQLException");
         } catch (final SQLException expected) {
         }
+        final Connection con1 = ds.getConnection(user, "bar");
+        final Connection con2 = ds.getConnection(user, "bar");
+        final Connection con3 = ds.getConnection(user, "bar");
+        con1.close();
+        con2.close();
+        TesterDriver.addUser(user,"bay"); // change the user/password setting
+        try {
+            final Connection con4 = ds.getConnection(user, "bay"); // new password
+            // Idle instances with old password should have been cleared
+            assertEquals(0, ((PerUserPoolDataSource) ds).getNumIdle(user),
+                    "Should be no idle connections in the pool");
+            con4.close();
+            // Should be one idle instance with new pwd
+            assertEquals(1, ((PerUserPoolDataSource) ds).getNumIdle(user),
+                    "Should be one idle connection in the pool");
+            try (Connection c = ds.getConnection(user, "bar")) { // old password
+                fail("Should have generated SQLException");
+            } catch (final SQLException expected) {
+            }
+            final Connection con5 = ds.getConnection(user, "bay"); // take the idle one
+            con3.close(); // Return a connection with the old password
+            ds.getConnection(user, "bay").close();  // will try bad returned connection and destroy it
+            assertEquals(1, ((PerUserPoolDataSource) ds).getNumIdle(user),
+                    "Should be one idle connection in the pool");
+            con5.close();
+        } finally {
+            TesterDriver.addUser(user,"bar");
+        }
     }
 
     @Override
     @Test
-    public void testSimple() throws Exception
+    public void testClosing()
+        throws Exception
     {
-        final Connection conn = ds.getConnection();
-        assertNotNull(conn);
-        final PreparedStatement stmt = conn.prepareStatement("select * from dual");
-        assertNotNull(stmt);
-        final ResultSet rset = stmt.executeQuery();
-        assertNotNull(rset);
-        assertTrue(rset.next());
-        rset.close();
-        stmt.close();
-        conn.close();
-    }
+        final Connection[] c = new Connection[getMaxTotal()];
+        // open the maximum connections
+        for (int i=0; i<c.length; i++)
+        {
+            c[i] = ds.getConnection();
+        }
 
-    @Test
-    public void testSimpleWithUsername() throws Exception
-    {
-        final Connection conn = ds.getConnection("u1", "p1");
-        assertNotNull(conn);
-        final PreparedStatement stmt = conn.prepareStatement("select * from dual");
-        assertNotNull(stmt);
-        final ResultSet rset = stmt.executeQuery();
-        assertNotNull(rset);
-        assertTrue(rset.next());
-        rset.close();
-        stmt.close();
-        conn.close();
+        // close one of the connections
+        c[0].close();
+        assertTrue(c[0].isClosed());
+
+        // get a new connection
+        c[0] = ds.getConnection();
+
+        for (final Connection element : c) {
+            element.close();
+        }
     }
 
     @Test
@@ -190,104 +179,86 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
         }
     }
 
-    @Override
+    // see issue https://issues.apache.org/bugzilla/show_bug.cgi?id=23843
     @Test
-    public void testSimple2()
-        throws Exception
-    {
-        Connection conn = ds.getConnection();
-        assertNotNull(conn);
-
-        PreparedStatement stmt =
-            conn.prepareStatement("select * from dual");
-        assertNotNull(stmt);
-        ResultSet rset = stmt.executeQuery();
-        assertNotNull(rset);
-        assertTrue(rset.next());
-        rset.close();
-        stmt.close();
-
-        stmt = conn.prepareStatement("select * from dual");
-        assertNotNull(stmt);
-        rset = stmt.executeQuery();
-        assertNotNull(rset);
-        assertTrue(rset.next());
-        rset.close();
-        stmt.close();
+    public void testDefaultUser1() throws Exception {
+        TesterDriver.addUser("mkh", "password");
+        TesterDriver.addUser("hanafey", "password");
+        TesterDriver.addUser("jsmith", "password");
 
-        conn.close();
-        try (Statement s = conn.createStatement()){
-            fail("Can't use closed connections");
-        } catch(final SQLException e) {
-            // expected
+        final PerUserPoolDataSource puds = (PerUserPoolDataSource) ds;
+        puds.setPerUserMaxTotal("jsmith", 2);
+        final String[] users = {"mkh", "hanafey", "jsmith"};
+        final String password = "password";
+        final Connection[] c = new Connection[users.length];
+        for (int i = 0; i < users.length; i++) {
+            c[i] = puds.getConnection(users[i], password);
+            assertEquals(users[i], getUsername(c[i]));
+        }
+        for (int i = 0; i < users.length; i++) {
+            c[i].close();
         }
-
-        conn = ds.getConnection();
-        assertNotNull(conn);
-
-        stmt = conn.prepareStatement("select * from dual");
-        assertNotNull(stmt);
-        rset = stmt.executeQuery();
-        assertNotNull(rset);
-        assertTrue(rset.next());
-        rset.close();
-        stmt.close();
-
-        stmt = conn.prepareStatement("select * from dual");
-        assertNotNull(stmt);
-        rset = stmt.executeQuery();
-        assertNotNull(rset);
-        assertTrue(rset.next());
-        rset.close();
-        stmt.close();
-
-        conn.close();
-        conn = null;
     }
 
-    @Override
+    // see issue https://issues.apache.org/bugzilla/show_bug.cgi?id=23843
     @Test
-    public void testOpening()
-        throws Exception
-    {
-        final Connection[] c = new Connection[getMaxTotal()];
-        // test that opening new connections is not closing previous
-        for (int i=0; i<c.length; i++)
-        {
-            c[i] = ds.getConnection();
-            assertNotNull(c[i]);
-            for (int j=0; j<=i; j++)
-            {
-                assertFalse(c[j].isClosed());
-            }
-        }
+    public void testDefaultUser2() throws Exception {
+        TesterDriver.addUser("mkh", "password");
+        TesterDriver.addUser("hanafey", "password");
+        TesterDriver.addUser("jsmith", "password");
 
-        for (final Connection element : c) {
-            element.close();
+        final PerUserPoolDataSource puds = (PerUserPoolDataSource) ds;
+        puds.setPerUserMaxTotal("jsmith", 2);
+        final String[] users = {"jsmith", "hanafey", "mkh"};
+        final String password = "password";
+        final Connection[] c = new Connection[users.length];
+        for (int i = 0; i < users.length; i++) {
+            c[i] = puds.getConnection(users[i], password);
+            assertEquals(users[i], getUsername(c[i]));
+        }
+        for (int i = 0; i < users.length; i++) {
+            c[i].close();
         }
     }
 
-    @Override
+    /**
+     * Switching 'u1 to 'u2' and 'p1' to 'p2' will
+     * exhibit the bug detailed in
+     * https://issues.apache.org/bugzilla/show_bug.cgi?id=18905
+     */
     @Test
-    public void testClosing()
-        throws Exception
-    {
-        final Connection[] c = new Connection[getMaxTotal()];
-        // open the maximum connections
-        for (int i=0; i<c.length; i++)
-        {
-            c[i] = ds.getConnection();
+    public void testIncorrectPassword() throws Exception {
+        // Use bad password
+        try (Connection c = ds.getConnection("u1", "zlsafjk")){
+            fail("Able to retrieve connection with incorrect password");
+        } catch (final SQLException e1) {
+            // should fail
+
         }
 
-        // close one of the connections
-        c[0].close();
-        assertTrue(c[0].isClosed());
+        // Use good password
+        ds.getConnection("u1", "p1").close();
+        try (Connection c = ds.getConnection("u1", "x")){
+            fail("Able to retrieve connection with incorrect password");
+        } catch (final SQLException e) {
+            if (!e.getMessage().startsWith("Given password did not match")) {
+                throw e;
+            }
+            // else the exception was expected
+        }
 
-        // get a new connection
-        c[0] = ds.getConnection();
+        // Make sure we can still use our good password.
+        ds.getConnection("u1", "p1").close();
 
-        for (final Connection element : c) {
-            element.close();
+        // Try related users and passwords
+        ds.getConnection(user, "bar").close();
+        try (Connection c = ds.getConnection("foob", "ar")) {
+            fail("Should have caused an SQLException");
+        } catch (final SQLException expected) {
+        }
+        try (Connection c = ds.getConnection(user, "baz")){
+            fail("Should have generated SQLException");
+        } catch (final SQLException expected) {
         }
     }
 
@@ -331,56 +302,6 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
     }
 
     @Test
-    public void testPerUserMethods() throws Exception {
-        final PerUserPoolDataSource tds = (PerUserPoolDataSource) ds;
-
-        // you need to set per user maxTotal otherwise there is no accounting
-        tds.setPerUserMaxTotal("u1", 5);
-        tds.setPerUserMaxTotal("u2", 5);
-
-        assertEquals(0, tds.getNumActive());
-        assertEquals(0, tds.getNumActive("u1"));
-        assertEquals(0, tds.getNumActive("u2"));
-        assertEquals(0, tds.getNumIdle());
-        assertEquals(0, tds.getNumIdle("u1"));
-        assertEquals(0, tds.getNumIdle("u2"));
-
-        Connection conn = tds.getConnection();
-        assertNotNull(conn);
-        assertEquals(1, tds.getNumActive());
-        assertEquals(0, tds.getNumActive("u1"));
-        assertEquals(0, tds.getNumActive("u2"));
-        assertEquals(0, tds.getNumIdle());
-        assertEquals(0, tds.getNumIdle("u1"));
-        assertEquals(0, tds.getNumIdle("u2"));
-
-        conn.close();
-        assertEquals(0, tds.getNumActive());
-        assertEquals(0, tds.getNumActive("u1"));
-        assertEquals(0, tds.getNumActive("u2"));
-        assertEquals(1, tds.getNumIdle());
-        assertEquals(0, tds.getNumIdle("u1"));
-        assertEquals(0, tds.getNumIdle("u2"));
-
-        conn = tds.getConnection("u1", "p1");
-        assertNotNull(conn);
-        assertEquals(0, tds.getNumActive());
-        assertEquals(1, tds.getNumActive("u1"));
-        assertEquals(0, tds.getNumActive("u2"));
-        assertEquals(1, tds.getNumIdle());
-        assertEquals(0, tds.getNumIdle("u1"));
-        assertEquals(0, tds.getNumIdle("u2"));
-
-        conn.close();
-        assertEquals(0, tds.getNumActive());
-        assertEquals(0, tds.getNumActive("u1"));
-        assertEquals(0, tds.getNumActive("u2"));
-        assertEquals(1, tds.getNumIdle());
-        assertEquals(1, tds.getNumIdle("u1"));
-        assertEquals(0, tds.getNumIdle("u2"));
-    }
-
-    @Test
     public void testMultipleThreads1() throws Exception {
         // Override wait time in order to allow for Thread.sleep(1) sometimes taking a lot longer on
         // some JVMs, e.g. Windows.
@@ -398,174 +319,26 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
         multipleThreads(2 * defaultMaxWaitMillis, true, true, defaultMaxWaitMillis);
     }
 
+    @Override
     @Test
-    public void testTransactionIsolationBehavior() throws Exception {
-        final Connection conn = getConnection();
-        assertNotNull(conn);
-        assertEquals(Connection.TRANSACTION_READ_COMMITTED,
-                     conn.getTransactionIsolation());
-        conn.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
-        conn.close();
-
-        final Connection conn2 = getConnection();
-        assertEquals(Connection.TRANSACTION_READ_COMMITTED,
-                     conn2.getTransactionIsolation());
-
-        final Connection conn3 = getConnection();
-        assertEquals(Connection.TRANSACTION_READ_COMMITTED,
-                     conn3.getTransactionIsolation());
-        conn2.close();
-        conn3.close();
-    }
-
-    @Test
-    public void testSerialization() throws Exception {
-        // make sure the pool has initialized
-        final Connection conn = ds.getConnection();
-        conn.close();
-
-        // serialize
-        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        final ObjectOutputStream out = new ObjectOutputStream(baos);
-        out.writeObject(ds);
-        out.close();
-        final byte[] b = baos.toByteArray();
-
-        final ByteArrayInputStream bais = new ByteArrayInputStream(b);
-        final ObjectInputStream in = new ObjectInputStream(bais);
-        final Object obj = in.readObject();
-        in.close();
-
-        assertEquals( 1, ((PerUserPoolDataSource)obj).getNumIdle() );
-    }
-
-    // see issue https://issues.apache.org/bugzilla/show_bug.cgi?id=23843
-    // unregistered user is in the same pool as without user name
-    @Test
-    public void testUnregisteredUser() throws Exception {
-        final PerUserPoolDataSource tds = (PerUserPoolDataSource) ds;
-
-        assertEquals(0, tds.getNumActive());
-        assertEquals(0, tds.getNumIdle());
-
-        Connection conn = tds.getConnection();
-        assertNotNull(conn);
-        assertEquals(1, tds.getNumActive());
-        assertEquals(0, tds.getNumIdle());
-
-        conn.close();
-        assertEquals(0, tds.getNumActive());
-        assertEquals(1, tds.getNumIdle());
-
-        conn = tds.getConnection("u1", "p1");
-        assertNotNull(conn);
-        assertEquals(0, tds.getNumActive());
-        assertEquals(1, tds.getNumIdle());
-        assertEquals(1, tds.getNumActive("u1"));
-        assertEquals(0, tds.getNumIdle("u1"));
-
-        conn.close();
-        assertEquals(0, tds.getNumActive());
-        assertEquals(1, tds.getNumIdle());
-        assertEquals(0, tds.getNumActive("u1"));
-        assertEquals(1, tds.getNumIdle("u1"));
-    }
-
-    // see issue https://issues.apache.org/bugzilla/show_bug.cgi?id=23843
-    @Test
-    public void testDefaultUser1() throws Exception {
-        TesterDriver.addUser("mkh", "password");
-        TesterDriver.addUser("hanafey", "password");
-        TesterDriver.addUser("jsmith", "password");
-
-        final PerUserPoolDataSource puds = (PerUserPoolDataSource) ds;
-        puds.setPerUserMaxTotal("jsmith", 2);
-        final String[] users = {"mkh", "hanafey", "jsmith"};
-        final String password = "password";
-        final Connection[] c = new Connection[users.length];
-        for (int i = 0; i < users.length; i++) {
-            c[i] = puds.getConnection(users[i], password);
-            assertEquals(users[i], getUsername(c[i]));
-        }
-        for (int i = 0; i < users.length; i++) {
-            c[i].close();
-        }
-    }
-
-    // see issue https://issues.apache.org/bugzilla/show_bug.cgi?id=23843
-    @Test
-    public void testDefaultUser2() throws Exception {
-        TesterDriver.addUser("mkh", "password");
-        TesterDriver.addUser("hanafey", "password");
-        TesterDriver.addUser("jsmith", "password");
-
-        final PerUserPoolDataSource puds = (PerUserPoolDataSource) ds;
-        puds.setPerUserMaxTotal("jsmith", 2);
-        final String[] users = {"jsmith", "hanafey", "mkh"};
-        final String password = "password";
-        final Connection[] c = new Connection[users.length];
-        for (int i = 0; i < users.length; i++) {
-            c[i] = puds.getConnection(users[i], password);
-            assertEquals(users[i], getUsername(c[i]));
-        }
-        for (int i = 0; i < users.length; i++) {
-            c[i].close();
-        }
-    }
-
-    // See DBCP-8
-    @Test
-    public void testChangePassword() throws Exception {
-        try (Connection c = ds.getConnection(user, "bay")){
-            fail("Should have generated SQLException");
-        } catch (final SQLException expected) {
-        }
-        final Connection con1 = ds.getConnection(user, "bar");
-        final Connection con2 = ds.getConnection(user, "bar");
-        final Connection con3 = ds.getConnection(user, "bar");
-        con1.close();
-        con2.close();
-        TesterDriver.addUser(user,"bay"); // change the user/password setting
-        try {
-            final Connection con4 = ds.getConnection(user, "bay"); // new password
-            // Idle instances with old password should have been cleared
-            assertEquals(0, ((PerUserPoolDataSource) ds).getNumIdle(user),
-                    "Should be no idle connections in the pool");
-            con4.close();
-            // Should be one idle instance with new pwd
-            assertEquals(1, ((PerUserPoolDataSource) ds).getNumIdle(user),
-                    "Should be one idle connection in the pool");
-            try (Connection c = ds.getConnection(user, "bar")) { // old password
-                fail("Should have generated SQLException");
-            } catch (final SQLException expected) {
+    public void testOpening()
+        throws Exception
+    {
+        final Connection[] c = new Connection[getMaxTotal()];
+        // test that opening new connections is not closing previous
+        for (int i=0; i<c.length; i++)
+        {
+            c[i] = ds.getConnection();
+            assertNotNull(c[i]);
+            for (int j=0; j<=i; j++)
+            {
+                assertFalse(c[j].isClosed());
             }
-            final Connection con5 = ds.getConnection(user, "bay"); // take the idle one
-            con3.close(); // Return a connection with the old password
-            ds.getConnection(user, "bay").close();  // will try bad returned connection and destroy it
-            assertEquals(1, ((PerUserPoolDataSource) ds).getNumIdle(user),
-                    "Should be one idle connection in the pool");
-            con5.close();
-        } finally {
-            TesterDriver.addUser(user,"bar");
         }
-    }
-
-    // getters and setters. Most follow the same pattern. The initial tests contain a more
-    // complete documentation, which can be helpful when write/understanding the other methods.
 
-    // -- per user block when exhausted
-
-    /**
-     * Test per user block when exhausted, with the backing map not initialized before.
-     * Instead we pass the map.
-     */
-    @Test
-    public void testPerUserBlockWhenExhaustedMapNotInitialized() {
-        final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
-        final Map<String, Boolean> userDefaultBlockWhenExhausted = new HashMap<>();
-        userDefaultBlockWhenExhausted.put("key", Boolean.TRUE);
-        ds.setPerUserBlockWhenExhausted(userDefaultBlockWhenExhausted);
-        assertEquals(Boolean.TRUE, ds.getPerUserBlockWhenExhausted("key"));
+        for (final Connection element : c) {
+            element.close();
+        }
     }
 
     /**
@@ -592,27 +365,29 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
 
     /**
      * 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 inexistent
-     * key, which should return the default value.
+     * Instead we pass the map.
      */
     @Test
-    public void testPerUserBlockWhenExhaustedMapNotInitializedMissingKey() {
+    public void testPerUserBlockWhenExhaustedMapNotInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         final Map<String, Boolean> userDefaultBlockWhenExhausted = new HashMap<>();
-        userDefaultBlockWhenExhausted.put("key", Boolean.FALSE);
+        userDefaultBlockWhenExhausted.put("key", Boolean.TRUE);
         ds.setPerUserBlockWhenExhausted(userDefaultBlockWhenExhausted);
-        assertEquals(ds.getDefaultBlockWhenExhausted(), ds.getPerUserBlockWhenExhausted("missingkey"));
+        assertEquals(Boolean.TRUE, ds.getPerUserBlockWhenExhausted("key"));
     }
 
     /**
      * 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 beforehand.
+     * Instead, we pass the map. And furthermore, we are now searching for an inexistent
+     * key, which should return the default value.
      */
     @Test
-    public void testPerUserBlockWhenExhaustedWithUserMapNotInitialized() {
+    public void testPerUserBlockWhenExhaustedMapNotInitializedMissingKey() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
-        ds.setPerUserBlockWhenExhausted(user, Boolean.FALSE);
-        assertEquals(Boolean.FALSE, ds.getPerUserBlockWhenExhausted(user));
+        final Map<String, Boolean> userDefaultBlockWhenExhausted = new HashMap<>();
+        userDefaultBlockWhenExhausted.put("key", Boolean.FALSE);
+        ds.setPerUserBlockWhenExhausted(userDefaultBlockWhenExhausted);
+        assertEquals(ds.getDefaultBlockWhenExhausted(), ds.getPerUserBlockWhenExhausted("missingkey"));
     }
 
     /**
@@ -637,6 +412,17 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
     /**
      * 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 beforehand.
+     */
+    @Test
+    public void testPerUserBlockWhenExhaustedWithUserMapNotInitialized() {
+        final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
+        ds.setPerUserBlockWhenExhausted(user, Boolean.FALSE);
+        assertEquals(Boolean.FALSE, ds.getPerUserBlockWhenExhausted(user));
+    }
+
+    /**
+     * 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 beforehand.
      * Furthermore, we are now searching for an inexistent key, which should return the
      * default value.
      */
@@ -647,17 +433,6 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
         assertEquals(Boolean.TRUE, ds.getPerUserBlockWhenExhausted("missingkey"));
     }
 
-    // -- per user default auto commit
-
-    @Test
-    public void testPerUserDefaultAutoCommitMapNotInitialized() {
-        final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
-        final Map<String, Boolean> values = new HashMap<>();
-        values.put("key", Boolean.TRUE);
-        ds.setPerUserDefaultAutoCommit(values);
-        assertEquals(Boolean.TRUE, ds.getPerUserDefaultAutoCommit("key"));
-    }
-
     @Test
     public void testPerUserDefaultAutoCommitMapInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
@@ -672,6 +447,20 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
         assertEquals(Boolean.FALSE, ds.getPerUserDefaultAutoCommit("anonymous"));
     }
 
+    // getters and setters. Most follow the same pattern. The initial tests contain a more
+    // complete documentation, which can be helpful when write/understanding the other methods.
+
+    // -- per user block when exhausted
+
+    @Test
+    public void testPerUserDefaultAutoCommitMapNotInitialized() {
+        final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
+        final Map<String, Boolean> values = new HashMap<>();
+        values.put("key", Boolean.TRUE);
+        ds.setPerUserDefaultAutoCommit(values);
+        assertEquals(Boolean.TRUE, ds.getPerUserDefaultAutoCommit("key"));
+    }
+
     @Test
     public void testPerUserDefaultAutoCommitMapNotInitializedMissingKey() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
@@ -683,20 +472,20 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
     }
 
     @Test
-    public void testPerUserDefaultAutoCommitWithUserMapNotInitialized() {
+    public void testPerUserDefaultAutoCommitWithUserMapInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         ds.setPerUserDefaultAutoCommit(user, Boolean.FALSE);
         assertEquals(Boolean.FALSE, ds.getPerUserDefaultAutoCommit(user));
+        ds.setPerUserDefaultAutoCommit("anotheruser", Boolean.FALSE);
+        assertEquals(Boolean.FALSE, ds.getPerUserDefaultAutoCommit(user));
+        assertEquals(Boolean.FALSE, ds.getPerUserDefaultAutoCommit("anotheruser"));
     }
 
     @Test
-    public void testPerUserDefaultAutoCommitWithUserMapInitialized() {
+    public void testPerUserDefaultAutoCommitWithUserMapNotInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         ds.setPerUserDefaultAutoCommit(user, Boolean.FALSE);
         assertEquals(Boolean.FALSE, ds.getPerUserDefaultAutoCommit(user));
-        ds.setPerUserDefaultAutoCommit("anotheruser", Boolean.FALSE);
-        assertEquals(Boolean.FALSE, ds.getPerUserDefaultAutoCommit(user));
-        assertEquals(Boolean.FALSE, ds.getPerUserDefaultAutoCommit("anotheruser"));
     }
 
     @Test
@@ -707,17 +496,6 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
         assertNull(ds.getPerUserDefaultAutoCommit("missingkey"));
     }
 
-    // -- per user default read only
-
-    @Test
-    public void testPerUserDefaultReadOnlyMapNotInitialized() {
-        final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
-        final Map<String, Boolean> values = new HashMap<>();
-        values.put("key", Boolean.TRUE);
-        ds.setPerUserDefaultReadOnly(values);
-        assertEquals(Boolean.TRUE, ds.getPerUserDefaultReadOnly("key"));
-    }
-
     @Test
     public void testPerUserDefaultReadOnlyMapInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
@@ -732,6 +510,17 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
         assertEquals(Boolean.FALSE, ds.getPerUserDefaultReadOnly("anonymous"));
     }
 
+    // -- per user default auto commit
+
+    @Test
+    public void testPerUserDefaultReadOnlyMapNotInitialized() {
+        final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
+        final Map<String, Boolean> values = new HashMap<>();
+        values.put("key", Boolean.TRUE);
+        ds.setPerUserDefaultReadOnly(values);
+        assertEquals(Boolean.TRUE, ds.getPerUserDefaultReadOnly("key"));
+    }
+
     @Test
     public void testPerUserDefaultReadOnlyMapNotInitializedMissingKey() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
@@ -743,20 +532,20 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
     }
 
     @Test
-    public void testPerUserDefaultReadOnlyWithUserMapNotInitialized() {
+    public void testPerUserDefaultReadOnlyWithUserMapInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         ds.setPerUserDefaultReadOnly(user, Boolean.FALSE);
         assertEquals(Boolean.FALSE, ds.getPerUserDefaultReadOnly(user));
+        ds.setPerUserDefaultReadOnly("anotheruser", Boolean.FALSE);
+        assertEquals(Boolean.FALSE, ds.getPerUserDefaultReadOnly(user));
+        assertEquals(Boolean.FALSE, ds.getPerUserDefaultReadOnly("anotheruser"));
     }
 
     @Test
-    public void testPerUserDefaultReadOnlyWithUserMapInitialized() {
+    public void testPerUserDefaultReadOnlyWithUserMapNotInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         ds.setPerUserDefaultReadOnly(user, Boolean.FALSE);
         assertEquals(Boolean.FALSE, ds.getPerUserDefaultReadOnly(user));
-        ds.setPerUserDefaultReadOnly("anotheruser", Boolean.FALSE);
-        assertEquals(Boolean.FALSE, ds.getPerUserDefaultReadOnly(user));
-        assertEquals(Boolean.FALSE, ds.getPerUserDefaultReadOnly("anotheruser"));
     }
 
     @Test
@@ -767,17 +556,6 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
         assertNull(ds.getPerUserDefaultReadOnly("missingkey"));
     }
 
-    // -- per user default transaction isolation
-
-    @Test
-    public void testPerUserDefaultTransactionIsolationMapNotInitialized() {
-        final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
-        final Map<String, Integer> values = new HashMap<>();
-        values.put("key", 1);
-        ds.setPerUserDefaultTransactionIsolation(values);
-        assertEquals((Integer) 1, ds.getPerUserDefaultTransactionIsolation("key"));
-    }
-
     @Test
     public void testPerUserDefaultTransactionIsolationMapInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
@@ -793,6 +571,17 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
         assertEquals((Integer) 0, ds.getPerUserDefaultTransactionIsolation("anonymous"));
     }
 
+    // -- per user default read only
+
+    @Test
+    public void testPerUserDefaultTransactionIsolationMapNotInitialized() {
+        final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
+        final Map<String, Integer> values = new HashMap<>();
+        values.put("key", 1);
+        ds.setPerUserDefaultTransactionIsolation(values);
+        assertEquals((Integer) 1, ds.getPerUserDefaultTransactionIsolation("key"));
+    }
+
     @Test
     public void testPerUserDefaultTransactionIsolationMapNotInitializedMissingKey() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
@@ -804,20 +593,20 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
     }
 
     @Test
-    public void testPerUserDefaultTransactionIsolationWithUserMapNotInitialized() {
+    public void testPerUserDefaultTransactionIsolationWithUserMapInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         ds.setPerUserDefaultTransactionIsolation(user, 0);
         assertEquals((Integer) 0, ds.getPerUserDefaultTransactionIsolation(user));
+        ds.setPerUserDefaultTransactionIsolation("anotheruser", 0);
+        assertEquals((Integer) 0, ds.getPerUserDefaultTransactionIsolation(user));
+        assertEquals((Integer) 0, ds.getPerUserDefaultTransactionIsolation("anotheruser"));
     }
 
     @Test
-    public void testPerUserDefaultTransactionIsolationWithUserMapInitialized() {
+    public void testPerUserDefaultTransactionIsolationWithUserMapNotInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         ds.setPerUserDefaultTransactionIsolation(user, 0);
         assertEquals((Integer) 0, ds.getPerUserDefaultTransactionIsolation(user));
-        ds.setPerUserDefaultTransactionIsolation("anotheruser", 0);
-        assertEquals((Integer) 0, ds.getPerUserDefaultTransactionIsolation(user));
-        assertEquals((Integer) 0, ds.getPerUserDefaultTransactionIsolation("anotheruser"));
     }
 
     @Test
@@ -828,17 +617,6 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
         assertNull(ds.getPerUserDefaultTransactionIsolation("missingkey"));
     }
 
-    // -- per user eviction policy class name
-
-    @Test
-    public void testPerUserEvictionPolicyClassNameMapNotInitialized() {
-        final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
-        final Map<String, String> values = new HashMap<>();
-        values.put("key", "test");
-        ds.setPerUserEvictionPolicyClassName(values);
-        assertEquals("test", ds.getPerUserEvictionPolicyClassName("key"));
-    }
-
     @Test
     public void testPerUserEvictionPolicyClassNameMapInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
@@ -853,20 +631,24 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
         assertEquals("bar", ds.getPerUserEvictionPolicyClassName("anonymous"));
     }
 
+    // -- per user default transaction isolation
+
     @Test
-    public void testPerUserEvictionPolicyClassNameMapNotInitializedMissingKey() {
+    public void testPerUserEvictionPolicyClassNameMapNotInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         final Map<String, String> values = new HashMap<>();
-        values.put("key", "bar");
+        values.put("key", "test");
         ds.setPerUserEvictionPolicyClassName(values);
-        assertEquals(ds.getDefaultEvictionPolicyClassName(), ds.getPerUserEvictionPolicyClassName("missingkey"));
+        assertEquals("test", ds.getPerUserEvictionPolicyClassName("key"));
     }
 
     @Test
-    public void testPerUserEvictionPolicyClassNameWithUserMapNotInitialized() {
+    public void testPerUserEvictionPolicyClassNameMapNotInitializedMissingKey() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
-        ds.setPerUserEvictionPolicyClassName(user, "bar");
-        assertEquals("bar", ds.getPerUserEvictionPolicyClassName(user));
+        final Map<String, String> values = new HashMap<>();
+        values.put("key", "bar");
+        ds.setPerUserEvictionPolicyClassName(values);
+        assertEquals(ds.getDefaultEvictionPolicyClassName(), ds.getPerUserEvictionPolicyClassName("missingkey"));
     }
 
     @Test
@@ -880,21 +662,17 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
     }
 
     @Test
-    public void testPerUserEvictionPolicyClassNameWithUserMapNotInitializedMissingKey() {
+    public void testPerUserEvictionPolicyClassNameWithUserMapNotInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
-        ds.setPerUserEvictionPolicyClassName("whatismyuseragain?", "bar");
-        assertEquals(ds.getDefaultEvictionPolicyClassName(), ds.getPerUserEvictionPolicyClassName("missingkey"));
+        ds.setPerUserEvictionPolicyClassName(user, "bar");
+        assertEquals("bar", ds.getPerUserEvictionPolicyClassName(user));
     }
 
-    // -- per user lifo
-
     @Test
-    public void testPerUserLifoMapNotInitialized() {
+    public void testPerUserEvictionPolicyClassNameWithUserMapNotInitializedMissingKey() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
-        final Map<String, Boolean> values = new HashMap<>();
-        values.put("key", Boolean.TRUE);
-        ds.setPerUserLifo(values);
-        assertEquals(Boolean.TRUE, ds.getPerUserLifo("key"));
+        ds.setPerUserEvictionPolicyClassName("whatismyuseragain?", "bar");
+        assertEquals(ds.getDefaultEvictionPolicyClassName(), ds.getPerUserEvictionPolicyClassName("missingkey"));
     }
 
     @Test
@@ -911,20 +689,24 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
         assertEquals(Boolean.FALSE, ds.getPerUserLifo("anonymous"));
     }
 
+    // -- per user eviction policy class name
+
     @Test
-    public void testPerUserLifoMapNotInitializedMissingKey() {
+    public void testPerUserLifoMapNotInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         final Map<String, Boolean> values = new HashMap<>();
-        values.put("key", Boolean.FALSE);
+        values.put("key", Boolean.TRUE);
         ds.setPerUserLifo(values);
-        assertEquals(ds.getDefaultLifo(), ds.getPerUserLifo("missingkey"));
+        assertEquals(Boolean.TRUE, ds.getPerUserLifo("key"));
     }
 
     @Test
-    public void testPerUserLifoWithUserMapNotInitialized() {
+    public void testPerUserLifoMapNotInitializedMissingKey() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
-        ds.setPerUserLifo(user, Boolean.FALSE);
-        assertEquals(Boolean.FALSE, ds.getPerUserLifo(user));
+        final Map<String, Boolean> values = new HashMap<>();
+        values.put("key", Boolean.FALSE);
+        ds.setPerUserLifo(values);
+        assertEquals(ds.getDefaultLifo(), ds.getPerUserLifo("missingkey"));
     }
 
     @Test
@@ -938,21 +720,17 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
     }
 
     @Test
-    public void testPerUserLifoWithUserMapNotInitializedMissingKey() {
+    public void testPerUserLifoWithUserMapNotInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
-        ds.setPerUserLifo("whatismyuseragain?", Boolean.FALSE);
-        assertEquals(ds.getDefaultLifo(), ds.getPerUserLifo("missingkey"));
+        ds.setPerUserLifo(user, Boolean.FALSE);
+        assertEquals(Boolean.FALSE, ds.getPerUserLifo(user));
     }
 
-    // -- per user max idle
-
     @Test
-    public void testPerUserMaxIdleMapNotInitialized() {
+    public void testPerUserLifoWithUserMapNotInitializedMissingKey() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
-        final Map<String, Integer> values = new HashMap<>();
-        values.put("key", 1);
-        ds.setPerUserMaxIdle(values);
-        assertEquals((Integer) 1, (Integer) ds.getPerUserMaxIdle("key"));
+        ds.setPerUserLifo("whatismyuseragain?", Boolean.FALSE);
+        assertEquals(ds.getDefaultLifo(), ds.getPerUserLifo("missingkey"));
     }
 
     @Test
@@ -969,20 +747,24 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
         assertEquals((Integer) 0, (Integer) ds.getPerUserMaxIdle("anonymous"));
     }
 
+    // -- per user lifo
+
     @Test
-    public void testPerUserMaxIdleMapNotInitializedMissingKey() {
+    public void testPerUserMaxIdleMapNotInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         final Map<String, Integer> values = new HashMap<>();
-        values.put("key", 0);
+        values.put("key", 1);
         ds.setPerUserMaxIdle(values);
-        assertEquals((Integer) ds.getDefaultMaxIdle(), (Integer) ds.getPerUserMaxIdle("missingkey"));
+        assertEquals((Integer) 1, (Integer) ds.getPerUserMaxIdle("key"));
     }
 
     @Test
-    public void testPerUserMaxIdleWithUserMapNotInitialized() {
+    public void testPerUserMaxIdleMapNotInitializedMissingKey() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
-        ds.setPerUserMaxIdle(user, 0);
-        assertEquals((Integer) 0, (Integer) ds.getPerUserMaxIdle(user));
+        final Map<String, Integer> values = new HashMap<>();
+        values.put("key", 0);
+        ds.setPerUserMaxIdle(values);
+        assertEquals((Integer) ds.getDefaultMaxIdle(), (Integer) ds.getPerUserMaxIdle("missingkey"));
     }
 
     @Test
@@ -996,21 +778,17 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
     }
 
     @Test
-    public void testPerUserMaxIdleWithUserMapNotInitializedMissingKey() {
+    public void testPerUserMaxIdleWithUserMapNotInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
-        ds.setPerUserMaxIdle("whatismyuseragain?", 0);
-        assertEquals((Integer) ds.getDefaultMaxIdle(), (Integer) ds.getPerUserMaxIdle("missingkey"));
+        ds.setPerUserMaxIdle(user, 0);
+        assertEquals((Integer) 0, (Integer) ds.getPerUserMaxIdle(user));
     }
 
-    // -- per user max total
-
     @Test
-    public void testPerUserMaxTotalMapNotInitialized() {
+    public void testPerUserMaxIdleWithUserMapNotInitializedMissingKey() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
-        final Map<String, Integer> values = new HashMap<>();
-        values.put("key", 1);
-        ds.setPerUserMaxTotal(values);
-        assertEquals((Integer) 1, (Integer) ds.getPerUserMaxTotal("key"));
+        ds.setPerUserMaxIdle("whatismyuseragain?", 0);
+        assertEquals((Integer) ds.getDefaultMaxIdle(), (Integer) ds.getPerUserMaxIdle("missingkey"));
     }
 
     @Test
@@ -1027,6 +805,17 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
         assertEquals((Integer) 0, (Integer) ds.getPerUserMaxTotal("anonymous"));
     }
 
+    // -- per user max idle
+
+    @Test
+    public void testPerUserMaxTotalMapNotInitialized() {
+        final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
+        final Map<String, Integer> values = new HashMap<>();
+        values.put("key", 1);
+        ds.setPerUserMaxTotal(values);
+        assertEquals((Integer) 1, (Integer) ds.getPerUserMaxTotal("key"));
+    }
+
     @Test
     public void testPerUserMaxTotalMapNotInitializedMissingKey() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
@@ -1037,20 +826,20 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
     }
 
     @Test
-    public void testPerUserMaxTotalWithUserMapNotInitialized() {
+    public void testPerUserMaxTotalWithUserMapInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         ds.setPerUserMaxTotal(user, 0);
         assertEquals((Integer) 0, (Integer) ds.getPerUserMaxTotal(user));
+        ds.setPerUserMaxTotal("anotheruser", 0);
+        assertEquals((Integer) 0, (Integer) ds.getPerUserMaxTotal(user));
+        assertEquals((Integer) 0, (Integer) ds.getPerUserMaxTotal("anotheruser"));
     }
 
     @Test
-    public void testPerUserMaxTotalWithUserMapInitialized() {
+    public void testPerUserMaxTotalWithUserMapNotInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         ds.setPerUserMaxTotal(user, 0);
         assertEquals((Integer) 0, (Integer) ds.getPerUserMaxTotal(user));
-        ds.setPerUserMaxTotal("anotheruser", 0);
-        assertEquals((Integer) 0, (Integer) ds.getPerUserMaxTotal(user));
-        assertEquals((Integer) 0, (Integer) ds.getPerUserMaxTotal("anotheruser"));
     }
 
     @Test
@@ -1060,17 +849,6 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
         assertEquals((Integer) ds.getDefaultMaxTotal(), (Integer) ds.getPerUserMaxTotal("missingkey"));
     }
 
-    // -- per user max wait millis
-
-    @Test
-    public void testPerUserMaxWaitMillisMapNotInitialized() {
-        final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
-        final Map<String, Long> values = new HashMap<>();
-        values.put("key", 1L);
-        ds.setPerUserMaxWaitMillis(values);
-        assertEquals(1L, ds.getPerUserMaxWaitMillis("key"));
-    }
-
     @Test
     public void testPerUserMaxWaitMillisMapInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
@@ -1085,6 +863,17 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
         assertEquals(0L, ds.getPerUserMaxWaitMillis("anonymous"));
     }
 
+    // -- per user max total
+
+    @Test
+    public void testPerUserMaxWaitMillisMapNotInitialized() {
+        final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
+        final Map<String, Long> values = new HashMap<>();
+        values.put("key", 1L);
+        ds.setPerUserMaxWaitMillis(values);
+        assertEquals(1L, ds.getPerUserMaxWaitMillis("key"));
+    }
+
     @Test
     public void testPerUserMaxWaitMillisMapNotInitializedMissingKey() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
@@ -1095,20 +884,20 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
     }
 
     @Test
-    public void testPerUserMaxWaitMillisWithUserMapNotInitialized() {
+    public void testPerUserMaxWaitMillisWithUserMapInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         ds.setPerUserMaxWaitMillis(user, 0L);
         assertEquals(0L, ds.getPerUserMaxWaitMillis(user));
+        ds.setPerUserMaxWaitMillis("anotheruser", 0L);
+        assertEquals(0L, ds.getPerUserMaxWaitMillis(user));
+        assertEquals(0L, ds.getPerUserMaxWaitMillis("anotheruser"));
     }
 
     @Test
-    public void testPerUserMaxWaitMillisWithUserMapInitialized() {
+    public void testPerUserMaxWaitMillisWithUserMapNotInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         ds.setPerUserMaxWaitMillis(user, 0L);
         assertEquals(0L, ds.getPerUserMaxWaitMillis(user));
-        ds.setPerUserMaxWaitMillis("anotheruser", 0L);
-        assertEquals(0L, ds.getPerUserMaxWaitMillis(user));
-        assertEquals(0L, ds.getPerUserMaxWaitMillis("anotheruser"));
     }
 
     @Test
@@ -1118,17 +907,58 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
         assertEquals(ds.getDefaultMaxWaitMillis(), ds.getPerUserMaxWaitMillis("missingkey"));
     }
 
-    // -- per user min evictable idle time millis
-
     @Test
-    public void testPerUserMinEvictableIdleTimeMillisMapNotInitialized() {
-        final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
-        final Map<String, Long> values = new HashMap<>();
-        values.put("key", 1L);
-        ds.setPerUserMinEvictableIdleTimeMillis(values);
-        assertEquals(1L, ds.getPerUserMinEvictableIdleTimeMillis("key"));
+    public void testPerUserMethods() throws Exception {
+        final PerUserPoolDataSource tds = (PerUserPoolDataSource) ds;
+
+        // you need to set per user maxTotal otherwise there is no accounting
+        tds.setPerUserMaxTotal("u1", 5);
+        tds.setPerUserMaxTotal("u2", 5);
+
+        assertEquals(0, tds.getNumActive());
+        assertEquals(0, tds.getNumActive("u1"));
+        assertEquals(0, tds.getNumActive("u2"));
+        assertEquals(0, tds.getNumIdle());
+        assertEquals(0, tds.getNumIdle("u1"));
+        assertEquals(0, tds.getNumIdle("u2"));
+
+        Connection conn = tds.getConnection();
+        assertNotNull(conn);
+        assertEquals(1, tds.getNumActive());
+        assertEquals(0, tds.getNumActive("u1"));
+        assertEquals(0, tds.getNumActive("u2"));
+        assertEquals(0, tds.getNumIdle());
+        assertEquals(0, tds.getNumIdle("u1"));
+        assertEquals(0, tds.getNumIdle("u2"));
+
+        conn.close();
+        assertEquals(0, tds.getNumActive());
+        assertEquals(0, tds.getNumActive("u1"));
+        assertEquals(0, tds.getNumActive("u2"));
+        assertEquals(1, tds.getNumIdle());
+        assertEquals(0, tds.getNumIdle("u1"));
+        assertEquals(0, tds.getNumIdle("u2"));
+
+        conn = tds.getConnection("u1", "p1");
+        assertNotNull(conn);
+        assertEquals(0, tds.getNumActive());
+        assertEquals(1, tds.getNumActive("u1"));
+        assertEquals(0, tds.getNumActive("u2"));
+        assertEquals(1, tds.getNumIdle());
+        assertEquals(0, tds.getNumIdle("u1"));
+        assertEquals(0, tds.getNumIdle("u2"));
+
+        conn.close();
+        assertEquals(0, tds.getNumActive());
+        assertEquals(0, tds.getNumActive("u1"));
+        assertEquals(0, tds.getNumActive("u2"));
+        assertEquals(1, tds.getNumIdle());
+        assertEquals(1, tds.getNumIdle("u1"));
+        assertEquals(0, tds.getNumIdle("u2"));
     }
 
+    // -- per user max wait millis
+
     @Test
     public void testPerUserMinEvictableIdleTimeMillisMapInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
@@ -1144,6 +974,15 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
     }
 
     @Test
+    public void testPerUserMinEvictableIdleTimeMillisMapNotInitialized() {
+        final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
+        final Map<String, Long> values = new HashMap<>();
+        values.put("key", 1L);
+        ds.setPerUserMinEvictableIdleTimeMillis(values);
+        assertEquals(1L, ds.getPerUserMinEvictableIdleTimeMillis("key"));
+    }
+
+    @Test
     public void testPerUserMinEvictableIdleTimeMillisMapNotInitializedMissingKey() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         final Map<String, Long> values = new HashMap<>();
@@ -1153,20 +992,20 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
     }
 
     @Test
-    public void testPerUserMinEvictableIdleTimeMillisWithUserMapNotInitialized() {
+    public void testPerUserMinEvictableIdleTimeMillisWithUserMapInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         ds.setPerUserMinEvictableIdleTimeMillis(user, 0L);
         assertEquals(0L, ds.getPerUserMinEvictableIdleTimeMillis(user));
+        ds.setPerUserMinEvictableIdleTimeMillis("anotheruser", 0L);
+        assertEquals(0L, ds.getPerUserMinEvictableIdleTimeMillis(user));
+        assertEquals(0L, ds.getPerUserMinEvictableIdleTimeMillis("anotheruser"));
     }
 
     @Test
-    public void testPerUserMinEvictableIdleTimeMillisWithUserMapInitialized() {
+    public void testPerUserMinEvictableIdleTimeMillisWithUserMapNotInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         ds.setPerUserMinEvictableIdleTimeMillis(user, 0L);
         assertEquals(0L, ds.getPerUserMinEvictableIdleTimeMillis(user));
-        ds.setPerUserMinEvictableIdleTimeMillis("anotheruser", 0L);
-        assertEquals(0L, ds.getPerUserMinEvictableIdleTimeMillis(user));
-        assertEquals(0L, ds.getPerUserMinEvictableIdleTimeMillis("anotheruser"));
     }
 
     @Test
@@ -1176,16 +1015,7 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
         assertEquals(ds.getDefaultMinEvictableIdleTimeMillis(), ds.getPerUserMinEvictableIdleTimeMillis("missingkey"));
     }
 
-    // -- per user min idle
-
-    @Test
-    public void testPerUserMinIdleMapNotInitialized() {
-        final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
-        final Map<String, Integer> values = new HashMap<>();
-        values.put("key", 1);
-        ds.setPerUserMinIdle(values);
-        assertEquals((Integer) 1, (Integer) ds.getPerUserMinIdle("key"));
-    }
+    // -- per user min evictable idle time millis
 
     @Test
     public void testPerUserMinIdleMapInitialized() {
@@ -1202,6 +1032,15 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
     }
 
     @Test
+    public void testPerUserMinIdleMapNotInitialized() {
+        final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
+        final Map<String, Integer> values = new HashMap<>();
+        values.put("key", 1);
+        ds.setPerUserMinIdle(values);
+        assertEquals((Integer) 1, (Integer) ds.getPerUserMinIdle("key"));
+    }
+
+    @Test
     public void testPerUserMinIdleMapNotInitializedMissingKey() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         final Map<String, Integer> values = new HashMap<>();
@@ -1211,20 +1050,20 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
     }
 
     @Test
-    public void testPerUserMinIdleWithUserMapNotInitialized() {
+    public void testPerUserMinIdleWithUserMapInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         ds.setPerUserMinIdle(user, 0);
         assertEquals((Integer) 0, (Integer) ds.getPerUserMinIdle(user));
+        ds.setPerUserMinIdle("anotheruser", 0);
+        assertEquals((Integer) 0, (Integer) ds.getPerUserMinIdle(user));
+        assertEquals((Integer) 0, (Integer) ds.getPerUserMinIdle("anotheruser"));
     }
 
     @Test
-    public void testPerUserMinIdleWithUserMapInitialized() {
+    public void testPerUserMinIdleWithUserMapNotInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         ds.setPerUserMinIdle(user, 0);
         assertEquals((Integer) 0, (Integer) ds.getPerUserMinIdle(user));
-        ds.setPerUserMinIdle("anotheruser", 0);
-        assertEquals((Integer) 0, (Integer) ds.getPerUserMinIdle(user));
-        assertEquals((Integer) 0, (Integer) ds.getPerUserMinIdle("anotheruser"));
     }
 
     @Test
@@ -1234,16 +1073,7 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
         assertEquals((Integer) ds.getDefaultMinIdle(), (Integer) ds.getPerUserMinIdle("missingkey"));
     }
 
-    // -- per user num tests per eviction run
-
-    @Test
-    public void testPerUserNumTestsPerEvictionRunMapNotInitialized() {
-        final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
-        final Map<String, Integer> values = new HashMap<>();
-        values.put("key", 1);
-        ds.setPerUserNumTestsPerEvictionRun(values);
-        assertEquals((Integer) 1, (Integer) ds.getPerUserNumTestsPerEvictionRun("key"));
-    }
+    // -- per user min idle
 
     @Test
     public void testPerUserNumTestsPerEvictionRunMapInitialized() {
@@ -1260,6 +1090,15 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
     }
 
     @Test
+    public void testPerUserNumTestsPerEvictionRunMapNotInitialized() {
+        final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
+        final Map<String, Integer> values = new HashMap<>();
+        values.put("key", 1);
+        ds.setPerUserNumTestsPerEvictionRun(values);
+        assertEquals((Integer) 1, (Integer) ds.getPerUserNumTestsPerEvictionRun("key"));
+    }
+
+    @Test
     public void testPerUserNumTestsPerEvictionRunMapNotInitializedMissingKey() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         final Map<String, Integer> values = new HashMap<>();
@@ -1269,20 +1108,20 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
     }
 
     @Test
-    public void testPerUserNumTestsPerEvictionRunWithUserMapNotInitialized() {
+    public void testPerUserNumTestsPerEvictionRunWithUserMapInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         ds.setPerUserNumTestsPerEvictionRun(user, 0);
         assertEquals((Integer) 0, (Integer) ds.getPerUserNumTestsPerEvictionRun(user));
+        ds.setPerUserNumTestsPerEvictionRun("anotheruser", 0);
+        assertEquals((Integer) 0, (Integer) ds.getPerUserNumTestsPerEvictionRun(user));
+        assertEquals((Integer) 0, (Integer) ds.getPerUserNumTestsPerEvictionRun("anotheruser"));
     }
 
     @Test
-    public void testPerUserNumTestsPerEvictionRunWithUserMapInitialized() {
+    public void testPerUserNumTestsPerEvictionRunWithUserMapNotInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         ds.setPerUserNumTestsPerEvictionRun(user, 0);
         assertEquals((Integer) 0, (Integer) ds.getPerUserNumTestsPerEvictionRun(user));
-        ds.setPerUserNumTestsPerEvictionRun("anotheruser", 0);
-        assertEquals((Integer) 0, (Integer) ds.getPerUserNumTestsPerEvictionRun(user));
-        assertEquals((Integer) 0, (Integer) ds.getPerUserNumTestsPerEvictionRun("anotheruser"));
     }
 
     @Test
@@ -1292,16 +1131,7 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
         assertEquals((Integer) ds.getDefaultNumTestsPerEvictionRun(), (Integer) ds.getPerUserNumTestsPerEvictionRun("missingkey"));
     }
 
-    // -- per user soft min evictable idle time millis
-
-    @Test
-    public void testPerUserSoftMinEvictableIdleTimeMillisMapNotInitialized() {
-        final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
-        final Map<String, Long> values = new HashMap<>();
-        values.put("key", 1L);
-        ds.setPerUserSoftMinEvictableIdleTimeMillis(values);
-        assertEquals(1L, ds.getPerUserSoftMinEvictableIdleTimeMillis("key"));
-    }
+    // -- per user num tests per eviction run
 
     @Test
     public void testPerUserSoftMinEvictableIdleTimeMillisMapInitialized() {
@@ -1318,6 +1148,15 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
     }
 
     @Test
+    public void testPerUserSoftMinEvictableIdleTimeMillisMapNotInitialized() {
+        final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
+        final Map<String, Long> values = new HashMap<>();
+        values.put("key", 1L);
+        ds.setPerUserSoftMinEvictableIdleTimeMillis(values);
+        assertEquals(1L, ds.getPerUserSoftMinEvictableIdleTimeMillis("key"));
+    }
+
+    @Test
     public void testPerUserSoftMinEvictableIdleTimeMillisMapNotInitializedMissingKey() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         final Map<String, Long> values = new HashMap<>();
@@ -1327,20 +1166,20 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
     }
 
     @Test
-    public void testPerUserSoftMinEvictableIdleTimeMillisWithUserMapNotInitialized() {
+    public void testPerUserSoftMinEvictableIdleTimeMillisWithUserMapInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         ds.setPerUserSoftMinEvictableIdleTimeMillis(user, 0L);
         assertEquals(0L, ds.getPerUserSoftMinEvictableIdleTimeMillis(user));
+        ds.setPerUserSoftMinEvictableIdleTimeMillis("anotheruser", 0L);
+        assertEquals(0L, ds.getPerUserSoftMinEvictableIdleTimeMillis(user));
+        assertEquals(0L, ds.getPerUserSoftMinEvictableIdleTimeMillis("anotheruser"));
     }
 
     @Test
-    public void testPerUserSoftMinEvictableIdleTimeMillisWithUserMapInitialized() {
+    public void testPerUserSoftMinEvictableIdleTimeMillisWithUserMapNotInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         ds.setPerUserSoftMinEvictableIdleTimeMillis(user, 0L);
         assertEquals(0L, ds.getPerUserSoftMinEvictableIdleTimeMillis(user));
-        ds.setPerUserSoftMinEvictableIdleTimeMillis("anotheruser", 0L);
-        assertEquals(0L, ds.getPerUserSoftMinEvictableIdleTimeMillis(user));
-        assertEquals(0L, ds.getPerUserSoftMinEvictableIdleTimeMillis("anotheruser"));
     }
 
     @Test
@@ -1350,16 +1189,7 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
         assertEquals(ds.getDefaultSoftMinEvictableIdleTimeMillis(), ds.getPerUserSoftMinEvictableIdleTimeMillis("missingkey"));
     }
 
-    // -- per user test on borrow
-
-    @Test
-    public void testPerUserTestOnBorrowMapNotInitialized() {
-        final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
-        final Map<String, Boolean> values = new HashMap<>();
-        values.put("key", Boolean.TRUE);
-        ds.setPerUserTestOnBorrow(values);
-        assertEquals(Boolean.TRUE, ds.getPerUserTestOnBorrow("key"));
-    }
+    // -- per user soft min evictable idle time millis
 
     @Test
     public void testPerUserTestOnBorrowMapInitialized() {
@@ -1376,6 +1206,15 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
     }
 
     @Test
+    public void testPerUserTestOnBorrowMapNotInitialized() {
+        final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
+        final Map<String, Boolean> values = new HashMap<>();
+        values.put("key", Boolean.TRUE);
+        ds.setPerUserTestOnBorrow(values);
+        assertEquals(Boolean.TRUE, ds.getPerUserTestOnBorrow("key"));
+    }
+
+    @Test
     public void testPerUserTestOnBorrowMapNotInitializedMissingKey() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         final Map<String, Boolean> values = new HashMap<>();
@@ -1385,20 +1224,20 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
     }
 
     @Test
-    public void testPerUserTestOnBorrowWithUserMapNotInitialized() {
+    public void testPerUserTestOnBorrowWithUserMapInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         ds.setPerUserTestOnBorrow(user, Boolean.FALSE);
         assertEquals(Boolean.FALSE, ds.getPerUserTestOnBorrow(user));
+        ds.setPerUserTestOnBorrow("anotheruser", Boolean.FALSE);
+        assertEquals(Boolean.FALSE, ds.getPerUserTestOnBorrow(user));
+        assertEquals(Boolean.FALSE, ds.getPerUserTestOnBorrow("anotheruser"));
     }
 
     @Test
-    public void testPerUserTestOnBorrowWithUserMapInitialized() {
+    public void testPerUserTestOnBorrowWithUserMapNotInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         ds.setPerUserTestOnBorrow(user, Boolean.FALSE);
         assertEquals(Boolean.FALSE, ds.getPerUserTestOnBorrow(user));
-        ds.setPerUserTestOnBorrow("anotheruser", Boolean.FALSE);
-        assertEquals(Boolean.FALSE, ds.getPerUserTestOnBorrow(user));
-        assertEquals(Boolean.FALSE, ds.getPerUserTestOnBorrow("anotheruser"));
     }
 
     @Test
@@ -1408,16 +1247,7 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
         assertEquals(ds.getDefaultTestOnBorrow(), ds.getPerUserTestOnBorrow("missingkey"));
     }
 
-    // -- per user test on create
-
-    @Test
-    public void testPerUserTestOnCreateMapNotInitialized() {
-        final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
-        final Map<String, Boolean> values = new HashMap<>();
-        values.put("key", Boolean.TRUE);
-        ds.setPerUserTestOnCreate(values);
-        assertEquals(Boolean.TRUE, ds.getPerUserTestOnCreate("key"));
-    }
+    // -- per user test on borrow
 
     @Test
     public void testPerUserTestOnCreateMapInitialized() {
@@ -1434,6 +1264,15 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
     }
 
     @Test
+    public void testPerUserTestOnCreateMapNotInitialized() {
+        final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
+        final Map<String, Boolean> values = new HashMap<>();
+        values.put("key", Boolean.TRUE);
+        ds.setPerUserTestOnCreate(values);
+        assertEquals(Boolean.TRUE, ds.getPerUserTestOnCreate("key"));
+    }
+
+    @Test
     public void testPerUserTestOnCreateMapNotInitializedMissingKey() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         final Map<String, Boolean> values = new HashMap<>();
@@ -1443,20 +1282,20 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
     }
 
     @Test
-    public void testPerUserTestOnCreateWithUserMapNotInitialized() {
+    public void testPerUserTestOnCreateWithUserMapInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         ds.setPerUserTestOnCreate(user, Boolean.FALSE);
         assertEquals(Boolean.FALSE, ds.getPerUserTestOnCreate(user));
+        ds.setPerUserTestOnCreate("anotheruser", Boolean.FALSE);
+        assertEquals(Boolean.FALSE, ds.getPerUserTestOnCreate(user));
+        assertEquals(Boolean.FALSE, ds.getPerUserTestOnCreate("anotheruser"));
     }
 
     @Test
-    public void testPerUserTestOnCreateWithUserMapInitialized() {
+    public void testPerUserTestOnCreateWithUserMapNotInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         ds.setPerUserTestOnCreate(user, Boolean.FALSE);
         assertEquals(Boolean.FALSE, ds.getPerUserTestOnCreate(user));
-        ds.setPerUserTestOnCreate("anotheruser", Boolean.FALSE);
-        assertEquals(Boolean.FALSE, ds.getPerUserTestOnCreate(user));
-        assertEquals(Boolean.FALSE, ds.getPerUserTestOnCreate("anotheruser"));
     }
 
     @Test
@@ -1466,16 +1305,7 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
         assertEquals(ds.getDefaultTestOnCreate(), ds.getPerUserTestOnCreate("missingkey"));
     }
 
-    // -- per user test on return
-
-    @Test
-    public void testPerUserTestOnReturnMapNotInitialized() {
-        final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
-        final Map<String, Boolean> values = new HashMap<>();
-        values.put("key", Boolean.TRUE);
-        ds.setPerUserTestOnReturn(values);
-        assertEquals(Boolean.TRUE, ds.getPerUserTestOnReturn("key"));
-    }
+    // -- per user test on create
 
     @Test
     public void testPerUserTestOnReturnMapInitialized() {
@@ -1492,6 +1322,15 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
     }
 
     @Test
+    public void testPerUserTestOnReturnMapNotInitialized() {
+        final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
+        final Map<String, Boolean> values = new HashMap<>();
+        values.put("key", Boolean.TRUE);
+        ds.setPerUserTestOnReturn(values);
+        assertEquals(Boolean.TRUE, ds.getPerUserTestOnReturn("key"));
+    }
+
+    @Test
     public void testPerUserTestOnReturnMapNotInitializedMissingKey() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         final Map<String, Boolean> values = new HashMap<>();
@@ -1501,20 +1340,20 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
     }
 
     @Test
-    public void testPerUserTestOnReturnWithUserMapNotInitialized() {
+    public void testPerUserTestOnReturnWithUserMapInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         ds.setPerUserTestOnReturn(user, Boolean.FALSE);
         assertEquals(Boolean.FALSE, ds.getPerUserTestOnReturn(user));
+        ds.setPerUserTestOnReturn("anotheruser", Boolean.FALSE);
+        assertEquals(Boolean.FALSE, ds.getPerUserTestOnReturn(user));
+        assertEquals(Boolean.FALSE, ds.getPerUserTestOnReturn("anotheruser"));
     }
 
     @Test
-    public void testPerUserTestOnReturnWithUserMapInitialized() {
+    public void testPerUserTestOnReturnWithUserMapNotInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         ds.setPerUserTestOnReturn(user, Boolean.FALSE);
         assertEquals(Boolean.FALSE, ds.getPerUserTestOnReturn(user));
-        ds.setPerUserTestOnReturn("anotheruser", Boolean.FALSE);
-        assertEquals(Boolean.FALSE, ds.getPerUserTestOnReturn(user));
-        assertEquals(Boolean.FALSE, ds.getPerUserTestOnReturn("anotheruser"));
     }
 
     @Test
@@ -1524,16 +1363,7 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
         assertEquals(ds.getDefaultTestOnReturn(), ds.getPerUserTestOnReturn("missingkey"));
     }
 
-    // -- per user test while idle
-
-    @Test
-    public void testPerUserTestWhileIdleMapNotInitialized() {
-        final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
-        final Map<String, Boolean> values = new HashMap<>();
-        values.put("key", Boolean.TRUE);
-        ds.setPerUserTestWhileIdle(values);
-        assertEquals(Boolean.TRUE, ds.getPerUserTestWhileIdle("key"));
-    }
+    // -- per user test on return
 
     @Test
     public void testPerUserTestWhileIdleMapInitialized() {
@@ -1550,6 +1380,15 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
     }
 
     @Test
+    public void testPerUserTestWhileIdleMapNotInitialized() {
+        final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
+        final Map<String, Boolean> values = new HashMap<>();
+        values.put("key", Boolean.TRUE);
+        ds.setPerUserTestWhileIdle(values);
+        assertEquals(Boolean.TRUE, ds.getPerUserTestWhileIdle("key"));
+    }
+
+    @Test
     public void testPerUserTestWhileIdleMapNotInitializedMissingKey() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         final Map<String, Boolean> values = new HashMap<>();
@@ -1559,20 +1398,20 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
     }
 
     @Test
-    public void testPerUserTestWhileIdleWithUserMapNotInitialized() {
+    public void testPerUserTestWhileIdleWithUserMapInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         ds.setPerUserTestWhileIdle(user, Boolean.FALSE);
         assertEquals(Boolean.FALSE, ds.getPerUserTestWhileIdle(user));
+        ds.setPerUserTestWhileIdle("anotheruser", Boolean.FALSE);
+        assertEquals(Boolean.FALSE, ds.getPerUserTestWhileIdle(user));
+        assertEquals(Boolean.FALSE, ds.getPerUserTestWhileIdle("anotheruser"));
     }
 
     @Test
-    public void testPerUserTestWhileIdleWithUserMapInitialized() {
+    public void testPerUserTestWhileIdleWithUserMapNotInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         ds.setPerUserTestWhileIdle(user, Boolean.FALSE);
         assertEquals(Boolean.FALSE, ds.getPerUserTestWhileIdle(user));
-        ds.setPerUserTestWhileIdle("anotheruser", Boolean.FALSE);
-        assertEquals(Boolean.FALSE, ds.getPerUserTestWhileIdle(user));
-        assertEquals(Boolean.FALSE, ds.getPerUserTestWhileIdle("anotheruser"));
     }
 
     @Test
@@ -1582,16 +1421,7 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
         assertEquals(ds.getDefaultTestWhileIdle(), ds.getPerUserTestWhileIdle("missingkey"));
     }
 
-    // -- per user time between eviction runs millis
-
-    @Test
-    public void testPerUserTimeBetweenEvictionRunsMillisMapNotInitialized() {
-        final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
-        final Map<String, Long> values = new HashMap<>();
-        values.put("key", 1L);
-        ds.setPerUserTimeBetweenEvictionRunsMillis(values);
-        assertEquals(1L, ds.getPerUserTimeBetweenEvictionRunsMillis("key"));
-    }
+    // -- per user test while idle
 
     @Test
     public void testPerUserTimeBetweenEvictionRunsMillisMapInitialized() {
@@ -1608,6 +1438,15 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
     }
 
     @Test
+    public void testPerUserTimeBetweenEvictionRunsMillisMapNotInitialized() {
+        final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
+        final Map<String, Long> values = new HashMap<>();
+        values.put("key", 1L);
+        ds.setPerUserTimeBetweenEvictionRunsMillis(values);
+        assertEquals(1L, ds.getPerUserTimeBetweenEvictionRunsMillis("key"));
+    }
+
+    @Test
     public void testPerUserTimeBetweenEvictionRunsMillisMapNotInitializedMissingKey() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         final Map<String, Long> values = new HashMap<>();
@@ -1617,20 +1456,20 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
     }
 
     @Test
-    public void testPerUserTimeBetweenEvictionRunsMillisWithUserMapNotInitialized() {
+    public void testPerUserTimeBetweenEvictionRunsMillisWithUserMapInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         ds.setPerUserTimeBetweenEvictionRunsMillis(user, 0L);
         assertEquals(0L, ds.getPerUserTimeBetweenEvictionRunsMillis(user));
+        ds.setPerUserTimeBetweenEvictionRunsMillis("anotheruser", 0L);
+        assertEquals(0L, ds.getPerUserTimeBetweenEvictionRunsMillis(user));
+        assertEquals(0L, ds.getPerUserTimeBetweenEvictionRunsMillis("anotheruser"));
     }
 
     @Test
-    public void testPerUserTimeBetweenEvictionRunsMillisWithUserMapInitialized() {
+    public void testPerUserTimeBetweenEvictionRunsMillisWithUserMapNotInitialized() {
         final PerUserPoolDataSource ds = (PerUserPoolDataSource) this.ds;
         ds.setPerUserTimeBetweenEvictionRunsMillis(user, 0L);
         assertEquals(0L, ds.getPerUserTimeBetweenEvictionRunsMillis(user));
-        ds.setPerUserTimeBetweenEvictionRunsMillis("anotheruser", 0L);
-        assertEquals(0L, ds.getPerUserTimeBetweenEvictionRunsMillis(user));
-        assertEquals(0L, ds.getPerUserTimeBetweenEvictionRunsMillis("anotheruser"));
     }
 
     @Test
@@ -1640,4 +1479,165 @@ public class TestPerUserPoolDataSource extends TestConnectionPool {
         assertEquals(ds.getDefaultTimeBetweenEvictionRunsMillis(), ds.getPerUserTimeBetweenEvictionRunsMillis("missingkey"));
     }
 
+    // -- per user time between eviction runs millis
+
+    @Test
+    public void testSerialization() throws Exception {
+        // make sure the pool has initialized
+        final Connection conn = ds.getConnection();
+        conn.close();
+
+        // serialize
+        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        final ObjectOutputStream out = new ObjectOutputStream(baos);
+        out.writeObject(ds);
+        out.close();
+        final byte[] b = baos.toByteArray();
+
+        final ByteArrayInputStream bais = new ByteArrayInputStream(b);
+        final ObjectInputStream in = new ObjectInputStream(bais);
+        final Object obj = in.readObject();
+        in.close();
+
+        assertEquals( 1, ((PerUserPoolDataSource)obj).getNumIdle() );
+    }
+
+    @Override
+    @Test
+    public void testSimple() throws Exception
+    {
+        final Connection conn = ds.getConnection();
+        assertNotNull(conn);
+        final PreparedStatement stmt = conn.prepareStatement("select * from dual");
+        assertNotNull(stmt);
+        final ResultSet rset = stmt.executeQuery();
+        assertNotNull(rset);
+        assertTrue(rset.next());
+        rset.close();
+        stmt.close();
+        conn.close();
+    }
+
+    @Override
+    @Test
+    public void testSimple2()
+        throws Exception
+    {
+        Connection conn = ds.getConnection();
+        assertNotNull(conn);
+
+        PreparedStatement stmt =
+            conn.prepareStatement("select * from dual");
+        assertNotNull(stmt);
+        ResultSet rset = stmt.executeQuery();
+        assertNotNull(rset);
+        assertTrue(rset.next());
+        rset.close();
+        stmt.close();
+
+        stmt = conn.prepareStatement("select * from dual");
+        assertNotNull(stmt);
+        rset = stmt.executeQuery();
+        assertNotNull(rset);
+        assertTrue(rset.next());
+        rset.close();
+        stmt.close();
+
+        conn.close();
+        try (Statement s = conn.createStatement()){
+            fail("Can't use closed connections");
+        } catch(final SQLException e) {
+            // expected
+        }
+
+        conn = ds.getConnection();
+        assertNotNull(conn);
+
+        stmt = conn.prepareStatement("select * from dual");
+        assertNotNull(stmt);
+        rset = stmt.executeQuery();
+        assertNotNull(rset);
+        assertTrue(rset.next());
+        rset.close();
+        stmt.close();
+
+        stmt = conn.prepareStatement("select * from dual");
+        assertNotNull(stmt);
+        rset = stmt.executeQuery();
+        assertNotNull(rset);
+        assertTrue(rset.next());
+        rset.close();
+        stmt.close();
+
+        conn.close();
+        conn = null;
+    }
+
+    @Test
+    public void testSimpleWithUsername() throws Exception
+    {
+        final Connection conn = ds.getConnection("u1", "p1");
+        assertNotNull(conn);
+        final PreparedStatement stmt = conn.prepareStatement("select * from dual");
+        assertNotNull(stmt);
+        final ResultSet rset = stmt.executeQuery();
+        assertNotNull(rset);
+        assertTrue(rset.next());
+        rset.close();
+        stmt.close();
+        conn.close();
+    }
+
+    @Test
+    public void testTransactionIsolationBehavior() throws Exception {
+        final Connection conn = getConnection();
+        assertNotNull(conn);
+        assertEquals(Connection.TRANSACTION_READ_COMMITTED,
+                     conn.getTransactionIsolation());
+        conn.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
+        conn.close();
+
+        final Connection conn2 = getConnection();
+        assertEquals(Connection.TRANSACTION_READ_COMMITTED,
+                     conn2.getTransactionIsolation());
+
+        final Connection conn3 = getConnection();
+        assertEquals(Connection.TRANSACTION_READ_COMMITTED,
+                     conn3.getTransactionIsolation());
+        conn2.close();
+        conn3.close();
+    }
+
+    // see issue https://issues.apache.org/bugzilla/show_bug.cgi?id=23843
+    // unregistered user is in the same pool as without user name
+    @Test
+    public void testUnregisteredUser() throws Exception {
+        final PerUserPoolDataSource tds = (PerUserPoolDataSource) ds;
+
+        assertEquals(0, tds.getNumActive());
+        assertEquals(0, tds.getNumIdle());
+
+        Connection conn = tds.getConnection();
+        assertNotNull(conn);
+        assertEquals(1, tds.getNumActive());
+        assertEquals(0, tds.getNumIdle());
+
+        conn.close();
+        assertEquals(0, tds.getNumActive());
+        assertEquals(1, tds.getNumIdle());
+
+        conn = tds.getConnection("u1", "p1");
+        assertNotNull(conn);
+        assertEquals(0, tds.getNumActive());
+        assertEquals(1, tds.getNumIdle());
+        assertEquals(1, tds.getNumActive("u1"));
+        assertEquals(0, tds.getNumIdle("u1"));
+
+        conn.close();
+        assertEquals(0, tds.getNumActive());
+        assertEquals(1, tds.getNumIdle());
+        assertEquals(0, tds.getNumActive("u1"));
+        assertEquals(1, tds.getNumIdle("u1"));
+    }
+
 }