How would you test a Connection Pool
Asked Answered
T

5

12

I have implemented a very simple ConnectionPool in Java. It has no fancy features, just get/release connection methods.

How can I test it is working?

I know there are plenty of connection Pools ready to use out there, which are much more reliable than what I'll do, but I am just trying to practice to understand how connections Pool work.

Thank you!

Here is the code in case it helps:

public class ConnectionPoolImpl implements ConnectionPool {
    private Vector<PooledConnection> connections; // The connections container
    String url;
    String username; 
    String password;

    /**
     * Instanciates a new MySQLConnectionPool
     * @param nbConnectionsMax
     */
    public ConnectionPoolImpl(String DBUrl, String username, String password){
        this.connections = new Vector<PooledConnection>();
        this.url = DBUrl;
        this.username = username;
        this.password = password;
    }

    /**
     * Returns a connection from the pool, if some are available, or create a new one.
     * 
     * @return the connection.
     */
    public Connection getConnection() throws SQLException {
        synchronized(this.connections){
            // Checking if there is an available connection to return
            for(PooledConnection c : this.connections){
                if(!c.isUsed()){
                    c.setUsed();
                    return c.getConnection();
                }
            }

            // If there are none, open a new one and return it
            Connection conn = DriverManager.getConnection(url, username, password);
        PooledConnection pConn = new PooledConnection(conn);
        pConn.setUsed();
        connections.add(pConn);
        return pConn.getConnection();
        }
    }

    /**
     * Releases a connection to the pool.
     * 
     * @param con the connection to release.
     */
    public void releaseConnection(Connection con) throws SQLException {
        synchronized(this.connections){
            for(PooledConnection c : this.connections){
                if(c.getConnection().equals(con)){
                    c.setFree();
                    return;
                }
            }
        }
      }
}

And my PooledConnection.java:

public class PooledConnection {
    private Connection conn;
    private boolean used;

    public PooledConnection(Connection conn){
        this.conn = conn;
        this.used = false;
    }

    public void setUsed(){
        this.used = true;
    }

    public void setFree(){
        this.used = false;
    }

    public boolean isUsed(){
        return this.used;
    }

    public Connection getConnection(){
        return this.conn;
    }
}
Tantalite answered 27/2, 2011 at 16:57 Comment(2)
fyi, you have a bug. when you create and return a new connection, you are not marking it as used.Brittne
@jtahlborn: Oops, you're right. I corrected this one in the edit. Thanks.Tantalite
E
16

You could test that

  • getting a connection when the pool is empty gives you a connection
  • getting a connection when a connection has already been got and not released gives you another, different connection
  • releasing a connection doesn't throw any exception
  • getting a connection after one has been released gives you the same connection

Note that such a unit test would need a real database, with a real user and password to test. You could make your connection pool depend on a DataSource, and build your ConnectionPool using a mock DataSource returning mock Connections, in order to be able to test the class without depending on a real database.

Enterprise answered 27/2, 2011 at 17:22 Comment(0)
P
3

Industrial strength connection pools have the ability to check connections by making a connection and executing a simple SQL query (e.g. "SELECT 1") to ensure that connection is viable before giving it out. Yours does not.

I don't see where you can initialize the connection pool with a fixed number of connections. The whole point of a connection pool is to amortize the cost of creating a connection over all clients.

I'd worry about the design of your connection pool.

As for testing, just start writing unit tests. Since your pool will be shared, be sure to write some multi-threaded tests to make sure that it's really thread safe.

Photovoltaic answered 27/2, 2011 at 17:16 Comment(4)
Thank you for your suggestions. I am new to connection pools, so excuse me for those questions that will probably sound stupid: 1. I agree that a maximal number of connection is very important and I should add one, but are you saying that I should open a fixed number of connections during the instantiation of my ConnectionPool, or should I just create them one by one (as I do now) until a maximal value is reached?Tantalite
2. When the maximal value is reached and a thread requests a connection, is it better to return null, or to wait for a connection to be released and return it then? - 3. Isn't one of the points of having a connection pool, not to spend time opening and closing connections every time a threads want to contact the DB? If yes, isn't checking the connection before releasing it going in the opposite direction? Thank you very much!Tantalite
I'd recommend creating a number of connections according to the minimum value and then add more as needed. If another connection is requested, it's your choice to either create a new one or wait until another is released. Using a connection isn't the issue; creating one is. You don't close the connection, you simply put it back in the pool. Checking the connection before releasing it is something that all commercial and open source pools allow you to do, so I'd guess that it's not going in the opposite direction.Photovoltaic
nbarraille, you may want to start a separate question, "Critique my connection pool". Or "how would I design a connection pool?". This thread is interesting but barely addresses the question "how to test this?".Gregoor
G
3

For an integration test, you could use dbUnit to load the database with prepared data and then write tests that query the database.

For an unit test, you might consider using a mocking library such as Mockito to ensure that you get the behaviour you expect. No database necessary in this case. [EDIT: However, due to the static method calls like DriverManager.getConnection(), this will require some refactoring and/or dependency injection.]

By combining both the unit tests and integration tests (and mix in some multi-threaded unit tests), you can go a long way towards testing your work.

Gregoor answered 27/2, 2011 at 17:28 Comment(6)
Mockito won't help if the code stays as is, because the only dependency it has is the DriverManager.getConnection static method, which isn't mockable.Enterprise
Good point. It may be useful with some refactoring / dependency injection. I will edit.Gregoor
@JB Nizet, @Michael Easter: I tried to use as much DI as I could (for example the Pooled Connection doesn't create its own connection but is given one by the constructor. But I can't think of any way for the ConnectionPool not to rely on DriverManager.getConnection(), how can I do that?Tantalite
Not necessarily elegant, but here is one way: define an interface called Connectable, which has a getConnection() method. Write DefaultConnectableImpl, which implements this interface by calling the DriverManager.getConnection(). Now, if your class is given a Connectable in the ctor, then you've escaped the dependency.Gregoor
@Michael Easter: Yep, just figured it out a few minutes ago, that's great idea, now I can declare a mock implementation of this interface and test my ConnectionPool without even having a real DB for the most part.Tantalite
@nathanb FWIW, this is a concrete example of the principle "code can be simplified by introducing a new level of indirection".Gregoor
M
0

You should also test concurrency/scalability under load using multiple threads.

Magnoliamagnoliaceous answered 27/2, 2011 at 21:23 Comment(0)
B
0

sometimes you might have configured the connection pool and the connections got created successfully.

but

how do you say all the connections are being accessed? sometimes only one connection may be being used repeatedly due to a configuration issue. therefore, you can clarify that by executing this query in a loop (it is better if you can use a parallel process) select connection_id(); with connections that you created. if you have successfully configured the pool, you can see the different ids as the output.

Burnoose answered 18/8, 2022 at 20:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.