summaryrefslogtreecommitdiff
path: root/src/interfaces/jdbc/org/postgresql/test
diff options
context:
space:
mode:
authorDave Cramer <davec@fastcrypt.com>2002-07-30 11:41:10 +0000
committerDave Cramer <davec@fastcrypt.com>2002-07-30 11:41:10 +0000
commitc82fed3d87e6a80044c97096340f6475a2ae5588 (patch)
tree83c4446017b497703170b5c6934bf48840412643 /src/interfaces/jdbc/org/postgresql/test
parent6410c222656a71788047cce2f4c23e1304975425 (diff)
Added DataSource code and tests submitted by Aaron Mulder
Diffstat (limited to 'src/interfaces/jdbc/org/postgresql/test')
-rw-r--r--src/interfaces/jdbc/org/postgresql/test/jdbc2/optional/BaseDataSourceTest.java160
-rw-r--r--src/interfaces/jdbc/org/postgresql/test/jdbc2/optional/ConnectionPoolTest.java327
-rw-r--r--src/interfaces/jdbc/org/postgresql/test/jdbc2/optional/OptionalTestSuite.java24
-rw-r--r--src/interfaces/jdbc/org/postgresql/test/jdbc2/optional/SimpleDataSourceTest.java38
4 files changed, 549 insertions, 0 deletions
diff --git a/src/interfaces/jdbc/org/postgresql/test/jdbc2/optional/BaseDataSourceTest.java b/src/interfaces/jdbc/org/postgresql/test/jdbc2/optional/BaseDataSourceTest.java
new file mode 100644
index 00000000000..f26fca20c91
--- /dev/null
+++ b/src/interfaces/jdbc/org/postgresql/test/jdbc2/optional/BaseDataSourceTest.java
@@ -0,0 +1,160 @@
+package org.postgresql.test.jdbc2.optional;
+
+import junit.framework.TestCase;
+import org.postgresql.test.JDBC2Tests;
+import org.postgresql.jdbc2.optional.SimpleDataSource;
+import org.postgresql.jdbc2.optional.BaseDataSource;
+
+import java.sql.*;
+
+/**
+ * Common tests for all the BaseDataSource implementations. This is
+ * a small variety to make sure that a connection can be opened and
+ * some basic queries run. The different BaseDataSource subclasses
+ * have different subclasses of this which add additional custom
+ * tests.
+ *
+ * @author Aaron Mulder (ammulder@chariotsolutions.com)
+ * @version $Revision: 1.1 $
+ */
+public abstract class BaseDataSourceTest extends TestCase {
+ protected Connection con;
+ protected BaseDataSource bds;
+
+ /**
+ * Constructor required by JUnit
+ */
+ public BaseDataSourceTest(String name) {
+ super(name);
+ }
+
+ /**
+ * Creates a test table using a standard connection (not from a
+ * DataSource).
+ */
+ protected void setUp() throws Exception {
+ con = JDBC2Tests.openDB();
+ JDBC2Tests.createTable(con, "poolingtest", "id int4 not null primary key, name varchar(50)");
+ Statement stmt = con.createStatement();
+ stmt.executeUpdate("INSERT INTO poolingtest VALUES (1, 'Test Row 1')");
+ stmt.executeUpdate("INSERT INTO poolingtest VALUES (2, 'Test Row 2')");
+ JDBC2Tests.closeDB(con);
+ }
+
+ /**
+ * Removes the test table using a standard connection (not from
+ * a DataSource)
+ */
+ protected void tearDown() throws Exception {
+ con = JDBC2Tests.openDB();
+ JDBC2Tests.dropTable(con, "poolingtest");
+ JDBC2Tests.closeDB(con);
+ }
+
+ /**
+ * Gets a connection from the current BaseDataSource
+ */
+ protected Connection getDataSourceConnection() throws SQLException {
+ initializeDataSource();
+ return bds.getConnection();
+ }
+
+ /**
+ * Creates an instance of the current BaseDataSource for
+ * testing. Must be customized by each subclass.
+ */
+ protected abstract void initializeDataSource();
+
+ /**
+ * Test to make sure you can instantiate and configure the
+ * appropriate DataSource
+ */
+ public void testCreateDataSource() {
+ initializeDataSource();
+ }
+
+ /**
+ * Test to make sure you can get a connection from the DataSource,
+ * which in turn means the DataSource was able to open it.
+ */
+ public void testGetConnection() {
+ try {
+ con = getDataSourceConnection();
+ con.close();
+ } catch (SQLException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ /**
+ * A simple test to make sure you can execute SQL using the
+ * Connection from the DataSource
+ */
+ public void testUseConnection() {
+ try {
+ con = getDataSourceConnection();
+ Statement st = con.createStatement();
+ ResultSet rs = st.executeQuery("SELECT COUNT(*) FROM poolingtest");
+ if(rs.next()) {
+ int count = rs.getInt(1);
+ if(rs.next()) {
+ fail("Should only have one row in SELECT COUNT result set");
+ }
+ if(count != 2) {
+ fail("Count returned "+count+" expecting 2");
+ }
+ } else {
+ fail("Should have one row in SELECT COUNT result set");
+ }
+ rs.close();
+ st.close();
+ con.close();
+ } catch (SQLException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ /**
+ * A test to make sure you can execute DDL SQL using the
+ * Connection from the DataSource.
+ */
+ public void testDdlOverConnection() {
+ try {
+ con = getDataSourceConnection();
+ JDBC2Tests.dropTable(con, "poolingtest");
+ JDBC2Tests.createTable(con, "poolingtest", "id int4 not null primary key, name varchar(50)");
+ con.close();
+ } catch (SQLException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ /**
+ * A test to make sure the connections are not being pooled by the
+ * current DataSource. Obviously need to be overridden in the case
+ * of a pooling Datasource.
+ */
+ public void testNotPooledConnection() {
+ try {
+ con = getDataSourceConnection();
+ String name = con.toString();
+ con.close();
+ con = getDataSourceConnection();
+ String name2 = con.toString();
+ con.close();
+ assertTrue(!name.equals(name2));
+ } catch (SQLException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ /**
+ * Eventually, we must test stuffing the DataSource in JNDI and
+ * then getting it back out and make sure it's still usable. This
+ * should ideally test both Serializable and Referenceable
+ * mechanisms. Will probably be multiple tests when implemented.
+ */
+ public void testJndi() {
+ // TODO: Put the DS in JNDI, retrieve it, and try some of this stuff again
+ }
+}
diff --git a/src/interfaces/jdbc/org/postgresql/test/jdbc2/optional/ConnectionPoolTest.java b/src/interfaces/jdbc/org/postgresql/test/jdbc2/optional/ConnectionPoolTest.java
new file mode 100644
index 00000000000..5802f156caa
--- /dev/null
+++ b/src/interfaces/jdbc/org/postgresql/test/jdbc2/optional/ConnectionPoolTest.java
@@ -0,0 +1,327 @@
+package org.postgresql.test.jdbc2.optional;
+
+import org.postgresql.jdbc2.optional.ConnectionPool;
+import org.postgresql.test.JDBC2Tests;
+import javax.sql.*;
+import java.sql.*;
+
+/**
+ * Tests for the ConnectionPoolDataSource and PooledConnection
+ * implementations. They are tested together because the only client
+ * interface to the PooledConnection is through the CPDS.
+ *
+ * @author Aaron Mulder (ammulder@chariotsolutions.com)
+ * @version $Revision: 1.1 $
+ */
+public class ConnectionPoolTest extends BaseDataSourceTest {
+ /**
+ * Constructor required by JUnit
+ */
+ public ConnectionPoolTest(String name) {
+ super(name);
+ }
+
+ /**
+ * Creates and configures a ConnectionPool
+ */
+ protected void initializeDataSource() {
+ if(bds == null) {
+ bds = new ConnectionPool();
+ String db = JDBC2Tests.getURL();
+ if(db.indexOf('/') > -1) {
+ db = db.substring(db.lastIndexOf('/')+1);
+ } else if(db.indexOf(':') > -1) {
+ db = db.substring(db.lastIndexOf(':')+1);
+ }
+ bds.setDatabaseName(db);
+ bds.setUser(JDBC2Tests.getUser());
+ bds.setPassword(JDBC2Tests.getPassword());
+ }
+ }
+
+ /**
+ * Though the normal client interface is to grab a Connection, in
+ * order to test the middleware/server interface, we need to deal
+ * with PooledConnections. Some tests use each.
+ */
+ protected PooledConnection getPooledConnection() throws SQLException {
+ initializeDataSource();
+ return ((ConnectionPool)bds).getPooledConnection();
+ }
+
+ /**
+ * Instead of just fetching a Connection from the ConnectionPool,
+ * get a PooledConnection, add a listener to close it when the
+ * Connection is closed, and then get the Connection. Without
+ * the listener the PooledConnection (and thus the physical connection)
+ * would never by closed. Probably not a disaster during testing, but
+ * you never know.
+ */
+ protected Connection getDataSourceConnection() throws SQLException {
+ initializeDataSource();
+ final PooledConnection pc = getPooledConnection();
+ // Since the pooled connection won't be reused in these basic tests, close it when the connection is closed
+ pc.addConnectionEventListener(new ConnectionEventListener() {
+ public void connectionClosed(ConnectionEvent event) {
+ try {
+ pc.close();
+ } catch (SQLException e) {
+ fail("Unable to close PooledConnection: "+e);
+ }
+ }
+
+ public void connectionErrorOccurred(ConnectionEvent event) {
+ }
+ });
+ return pc.getConnection();
+ }
+
+ /**
+ * Makes sure that if you get a connection from a PooledConnection,
+ * close it, and then get another one, you're really using the same
+ * physical connection. Depends on the implementation of toString
+ * for the connection handle.
+ */
+ public void testPoolReuse() {
+ try {
+ PooledConnection pc = getPooledConnection();
+ con = pc.getConnection();
+ String name = con.toString();
+ con.close();
+ con = pc.getConnection();
+ String name2 = con.toString();
+ con.close();
+ pc.close();
+ assertTrue("Physical connection doesn't appear to be reused across PooledConnection wrappers", name.equals(name2));
+ } catch (SQLException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ /**
+ * Makes sure that when you request a connection from the
+ * PooledConnection, and previous connection it might have given
+ * out is closed. See JDBC 2.0 Optional Package spec section
+ * 6.2.3
+ */
+ public void testPoolCloseOldWrapper() {
+ try {
+ PooledConnection pc = getPooledConnection();
+ con = pc.getConnection();
+ Connection con2 = pc.getConnection();
+ try {
+ con.createStatement();
+ fail("Original connection wrapper should be closed when new connection wrapper is generated");
+ } catch(SQLException e) {}
+ try {
+ con.close();
+ fail("Original connection wrapper should be closed when new connection wrapper is generated");
+ } catch(SQLException e) {}
+ con2.close();
+ pc.close();
+ } catch (SQLException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ /**
+ * Makes sure that if you get two connection wrappers from the same
+ * PooledConnection, they are different, even though the represent
+ * the same physical connection. See JDBC 2.0 Optional Pacakge spec
+ * section 6.2.2
+ */
+ public void testPoolNewWrapper() {
+ try {
+ PooledConnection pc = getPooledConnection();
+ con = pc.getConnection();
+ Connection con2 = pc.getConnection();
+ con2.close();
+ pc.close();
+ assertTrue("Two calls to PooledConnection.getConnection should not return the same connection wrapper", con != con2);
+ } catch (SQLException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ /**
+ * Makes sure that exactly one close event is fired for each time a
+ * connection handle is closed. Also checks that events are not
+ * fired after a given handle has been closed once.
+ */
+ public void testCloseEvent() {
+ try {
+ PooledConnection pc = getPooledConnection();
+ CountClose cc = new CountClose();
+ pc.addConnectionEventListener(cc);
+ con = pc.getConnection();
+ assertTrue(cc.getCount() == 0);
+ assertTrue(cc.getErrorCount() == 0);
+ con.close();
+ assertTrue(cc.getCount() == 1);
+ assertTrue(cc.getErrorCount() == 0);
+ con = pc.getConnection();
+ assertTrue(cc.getCount() == 1);
+ assertTrue(cc.getErrorCount() == 0);
+ con.close();
+ assertTrue(cc.getCount() == 2);
+ assertTrue(cc.getErrorCount() == 0);
+ try {
+ con.close();
+ fail("Should not be able to close a connection wrapper twice");
+ } catch (SQLException e) {}
+ assertTrue(cc.getCount() == 2);
+ assertTrue(cc.getErrorCount() == 0);
+ pc.close();
+ } catch (SQLException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ /**
+ * Makes sure that close events are not fired after a listener has
+ * been removed.
+ */
+ public void testNoCloseEvent() {
+ try {
+ PooledConnection pc = getPooledConnection();
+ CountClose cc = new CountClose();
+ pc.addConnectionEventListener(cc);
+ con = pc.getConnection();
+ assertTrue(cc.getCount() == 0);
+ assertTrue(cc.getErrorCount() == 0);
+ con.close();
+ assertTrue(cc.getCount() == 1);
+ assertTrue(cc.getErrorCount() == 0);
+ pc.removeConnectionEventListener(cc);
+ con = pc.getConnection();
+ assertTrue(cc.getCount() == 1);
+ assertTrue(cc.getErrorCount() == 0);
+ con.close();
+ assertTrue(cc.getCount() == 1);
+ assertTrue(cc.getErrorCount() == 0);
+ } catch (SQLException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ /**
+ * Makes sure that a listener can be removed while dispatching
+ * events. Sometimes this causes a ConcurrentModificationException
+ * or something.
+ */
+ public void testInlineCloseEvent() {
+ try {
+ PooledConnection pc = getPooledConnection();
+ RemoveClose rc1 = new RemoveClose();
+ RemoveClose rc2 = new RemoveClose();
+ RemoveClose rc3 = new RemoveClose();
+ pc.addConnectionEventListener(rc1);
+ pc.addConnectionEventListener(rc2);
+ pc.addConnectionEventListener(rc3);
+ con = pc.getConnection();
+ con.close();
+ con = pc.getConnection();
+ con.close();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+ }
+
+ /**
+ * Tests that a close event is not generated when a connection
+ * handle is closed automatically due to a new connection handle
+ * being opened for the same PooledConnection. See JDBC 2.0
+ * Optional Package spec section 6.3
+ */
+ public void testAutomaticCloseEvent() {
+ try {
+ PooledConnection pc = getPooledConnection();
+ CountClose cc = new CountClose();
+ pc.addConnectionEventListener(cc);
+ con = pc.getConnection();
+ assertTrue(cc.getCount() == 0);
+ assertTrue(cc.getErrorCount() == 0);
+ con.close();
+ assertTrue(cc.getCount() == 1);
+ assertTrue(cc.getErrorCount() == 0);
+ con = pc.getConnection();
+ assertTrue(cc.getCount() == 1);
+ assertTrue(cc.getErrorCount() == 0);
+ // Open a 2nd connection, causing the first to be closed. No even should be generated.
+ Connection con2 = pc.getConnection();
+ assertTrue("Connection handle was not closed when new handle was opened", con.isClosed());
+ assertTrue(cc.getCount() == 1);
+ assertTrue(cc.getErrorCount() == 0);
+ con2.close();
+ assertTrue(cc.getCount() == 2);
+ assertTrue(cc.getErrorCount() == 0);
+ pc.close();
+ } catch (SQLException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ /**
+ * Makes sure the isClosed method on a connection wrapper does what
+ * you'd expect. Checks the usual case, as well as automatic
+ * closure when a new handle is opened on the same physical connection.
+ */
+ public void testIsClosed() {
+ try {
+ PooledConnection pc = getPooledConnection();
+ Connection con = pc.getConnection();
+ assertTrue(!con.isClosed());
+ con.close();
+ assertTrue(con.isClosed());
+ con = pc.getConnection();
+ Connection con2 = pc.getConnection();
+ assertTrue(con.isClosed());
+ assertTrue(!con2.isClosed());
+ con2.close();
+ assertTrue(con.isClosed());
+ pc.close();
+ } catch (SQLException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ /**
+ * Helper class to remove a listener during event dispatching.
+ */
+ private class RemoveClose implements ConnectionEventListener {
+ public void connectionClosed(ConnectionEvent event) {
+ ((PooledConnection)event.getSource()).removeConnectionEventListener(this);
+ }
+
+ public void connectionErrorOccurred(ConnectionEvent event) {
+ ((PooledConnection)event.getSource()).removeConnectionEventListener(this);
+ }
+ }
+
+ /**
+ * Helper class that implements the event listener interface, and
+ * counts the number of events it sees.
+ */
+ private class CountClose implements ConnectionEventListener {
+ private int count = 0, errorCount = 0;
+ public void connectionClosed(ConnectionEvent event) {
+ count++;
+ }
+
+ public void connectionErrorOccurred(ConnectionEvent event) {
+ errorCount++;
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public int getErrorCount() {
+ return errorCount;
+ }
+
+ public void clear() {
+ count = errorCount = 0;
+ }
+ }
+}
diff --git a/src/interfaces/jdbc/org/postgresql/test/jdbc2/optional/OptionalTestSuite.java b/src/interfaces/jdbc/org/postgresql/test/jdbc2/optional/OptionalTestSuite.java
new file mode 100644
index 00000000000..ded7503a457
--- /dev/null
+++ b/src/interfaces/jdbc/org/postgresql/test/jdbc2/optional/OptionalTestSuite.java
@@ -0,0 +1,24 @@
+package org.postgresql.test.jdbc2.optional;
+
+import junit.framework.TestSuite;
+
+/**
+ * Test suite for the JDBC 2.0 Optional Package implementation. This
+ * includes the DataSource, ConnectionPoolDataSource, and
+ * PooledConnection implementations.
+ *
+ * @author Aaron Mulder (ammulder@chariotsolutions.com)
+ * @version $Revision: 1.1 $
+ */
+public class OptionalTestSuite extends TestSuite {
+ /**
+ * Gets the test suite for the entire JDBC 2.0 Optional Package
+ * implementation.
+ */
+ public static TestSuite suite() {
+ TestSuite suite = new TestSuite();
+ suite.addTestSuite(SimpleDataSourceTest.class);
+ suite.addTestSuite(ConnectionPoolTest.class);
+ return suite;
+ }
+}
diff --git a/src/interfaces/jdbc/org/postgresql/test/jdbc2/optional/SimpleDataSourceTest.java b/src/interfaces/jdbc/org/postgresql/test/jdbc2/optional/SimpleDataSourceTest.java
new file mode 100644
index 00000000000..1c917db6a1b
--- /dev/null
+++ b/src/interfaces/jdbc/org/postgresql/test/jdbc2/optional/SimpleDataSourceTest.java
@@ -0,0 +1,38 @@
+package org.postgresql.test.jdbc2.optional;
+
+import org.postgresql.test.JDBC2Tests;
+import org.postgresql.jdbc2.optional.SimpleDataSource;
+
+/**
+ * Performs the basic tests defined in the superclass. Just adds the
+ * configuration logic.
+ *
+ * @author Aaron Mulder (ammulder@chariotsolutions.com)
+ * @version $Revision: 1.1 $
+ */
+public class SimpleDataSourceTest extends BaseDataSourceTest {
+ /**
+ * Constructor required by JUnit
+ */
+ public SimpleDataSourceTest(String name) {
+ super(name);
+ }
+
+ /**
+ * Creates and configures a new SimpleDataSource.
+ */
+ protected void initializeDataSource() {
+ if(bds == null) {
+ bds = new SimpleDataSource();
+ String db = JDBC2Tests.getURL();
+ if(db.indexOf('/') > -1) {
+ db = db.substring(db.lastIndexOf('/')+1);
+ } else if(db.indexOf(':') > -1) {
+ db = db.substring(db.lastIndexOf(':')+1);
+ }
+ bds.setDatabaseName(db);
+ bds.setUser(JDBC2Tests.getUser());
+ bds.setPassword(JDBC2Tests.getPassword());
+ }
+ }
+}