You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by kr...@apache.org on 2010/07/12 13:40:42 UTC
svn commit: r963243 -
/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/J2EEDataSourceTest.java
Author: kristwaa
Date: Mon Jul 12 11:40:42 2010
New Revision: 963243
URL: http://svn.apache.org/viewvc?rev=963243&view=rev
Log:
DERBY-4709: Create test that parse client trace file to detect round-trips for Derby-4653.
Alternative test for commit/rollback flow optimization, which parses the
DRDA protocol flow log to verify that a commit/rollback flows over the network
only when required.
The test is very general, it does not test correct commit/rollback behavior for
specific database interaction sequences.
Patch file: derby-4709-1c-alternative_test.diff
Modified:
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/J2EEDataSourceTest.java
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/J2EEDataSourceTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/J2EEDataSourceTest.java?rev=963243&r1=963242&r2=963243&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/J2EEDataSourceTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/J2EEDataSourceTest.java Mon Jul 12 11:40:42 2010
@@ -21,7 +21,9 @@
package org.apache.derbyTesting.functionTests.tests.jdbcapi;
+import java.io.BufferedReader;
import java.io.File;
+import java.io.IOException;
import java.io.Serializable;
import java.security.AccessController;
import java.sql.CallableStatement;
@@ -51,9 +53,11 @@ import javax.transaction.xa.Xid;
import junit.framework.Test;
import junit.framework.TestSuite;
+import org.apache.derby.jdbc.ClientBaseDataSource;
import org.apache.derby.jdbc.ClientConnectionPoolDataSource;
import org.apache.derby.jdbc.ClientXADataSource;
import org.apache.derby.jdbc.EmbeddedSimpleDataSource;
+import org.apache.derbyTesting.functionTests.util.PrivilegedFileOpsForTests;
import org.apache.derbyTesting.functionTests.util.SecurityCheck;
import org.apache.derbyTesting.junit.BaseJDBCTestCase;
import org.apache.derbyTesting.junit.CleanDatabaseTestSetup;
@@ -62,6 +66,7 @@ import org.apache.derbyTesting.junit.J2E
import org.apache.derbyTesting.junit.JDBC;
import org.apache.derbyTesting.junit.JDBCClient;
import org.apache.derbyTesting.junit.JDBCDataSource;
+import org.apache.derbyTesting.junit.SupportFilesSetup;
import org.apache.derbyTesting.junit.TestConfiguration;
/**
@@ -175,6 +180,10 @@ public class J2EEDataSourceTest extends
//suite.addTest(new J2EEDataSourceTest(
// "testClientMessageTextConnectionAttribute"));
suite.addTest(new J2EEDataSourceTest("testConnectionFlowCommit"));
+ suite.addTest(new J2EEDataSourceTest("testConnectionFlowCommitAlt"));
+ // Disabled because rollback flow optimization hasn't been implemented.
+ // See DERBY-4687
+ //suite.addTest(new J2EEDataSourceTest("testConnectionFlowRollbackAlt"));
return suite;
}
@@ -213,8 +222,8 @@ public class J2EEDataSourceTest extends
suite.addTest(TestConfiguration.clientServerDecorator(
baseSuite(":client")));
// Add the tests that only run with client
- suite.addTest(TestConfiguration.clientServerDecorator(
- getClientSuite()));
+ suite.addTest(new SupportFilesSetup(
+ TestConfiguration.clientServerDecorator(getClientSuite())));
// Add the tests that only run with embedded
suite.addTest(getEmbeddedSuite("embedded"));
// Add the tests relying on getting timeouts.
@@ -2126,7 +2135,201 @@ public class J2EEDataSourceTest extends
s.close();
}
-
+
+ /**
+ * Alternative test for making sure "redundant" rollbacks, i.e. rollbacks
+ * invoked when no transaction is in progress, don't result in a rollback
+ * command being flowed to the server.
+ *
+ * @throws IOException if reading/parsing the trace file fails
+ * @throws SQLException if something goes wrong
+ */
+ public void testConnectionFlowRollbackAlt()
+ throws IOException, SQLException {
+ Object[] dataSources = new Object[] {
+ JDBCDataSource.getDataSource(),
+ J2EEDataSource.getConnectionPoolDataSource(),
+ J2EEDataSource.getXADataSource()
+ };
+ for (int i=0; i < dataSources.length; i++) {
+ Object ds = dataSources[i];
+ // Run test sequence without invoking extra rollbacks.
+ int flowsBase = testConnectionFlowCommitRollback(ds, false, false);
+ // Run test sequence with extra rollbacks - these should not result
+ // in a rollback command being flowed to the server.
+ int flowsExtra = testConnectionFlowCommitRollback(ds, true, false);
+ assertEquals("Rollback optimization not working for connections " +
+ "originating from " + ds.getClass().getName(),
+ flowsBase, flowsExtra);
+ }
+ }
+
+ /**
+ * Alternative test for making sure "redundant" commits, i.e. commits
+ * invoked when no transaction is in progress, don't result in a commit
+ * command being flowed to the server.
+ *
+ * @throws IOException if reading/parsing the trace file fails
+ * @throws SQLException if something goes wrong
+ */
+ public void testConnectionFlowCommitAlt()
+ throws IOException, SQLException {
+ Object[] dataSources = new Object[] {
+ JDBCDataSource.getDataSource(),
+ J2EEDataSource.getConnectionPoolDataSource(),
+ J2EEDataSource.getXADataSource()
+ };
+ for (int i=0; i < dataSources.length; i++) {
+ Object ds = dataSources[i];
+ // Run test sequence without invoking extra commits.
+ int flowsBase = testConnectionFlowCommitRollback(ds, false, true);
+ // Run test sequence with extra commits - these should not result in
+ // a commit command being flowed to the server.
+ int flowsExtra = testConnectionFlowCommitRollback(ds, true, true);
+ assertEquals("Commit optimization not working for connections " +
+ "originating from " + ds.getClass().getName(),
+ flowsBase, flowsExtra);
+ }
+ }
+
+ /**
+ * Performs a test sequence accessing the server, then parses the client
+ * connection trace file to obtain the number of commit or rollback
+ * commands flowed from the client to the server.
+ *
+ * @param ds data source used to obtain a connection to the database
+ * (must be using the test framework defaults)
+ * @param invokeExtra if {@code true} extra invocations of either commit or
+ * rollback are performed (depending on value of {@code isCommit})
+ * @param isCommit if {@code true}, commits are invoked, otherwise
+ * rollbacks are invoked
+ * @return The number of wire flows detected (depending on value of
+ * {@code isCommit}).
+ * @throws IOException if reading/parsing the trace file fails
+ * @throws SQLException if something goes wrong
+ */
+ private int testConnectionFlowCommitRollback(
+ Object ds, boolean invokeExtra, boolean isCommit)
+ throws IOException, SQLException {
+ final int extraInvokations = invokeExtra ? 25 : 0;
+ final int rowCount = 10;
+ final boolean isXA = ds instanceof ClientXADataSource;
+ final boolean isCP = ds instanceof ClientConnectionPoolDataSource;
+ // Generate trace file name and define trace behavior.
+ String dsType = (isXA ? "xa_" : (isCP ? "cp_" : ""));
+ String tbl = "ds_" + dsType +
+ (invokeExtra ? "base_" : "extra_") +
+ (isCommit ? "commit" : "rollback");
+ File traceFile = SupportFilesSetup.getReadWrite(tbl + ".trace");
+ J2EEDataSource.setBeanProperty(ds, "traceFile",
+ PrivilegedFileOpsForTests.getAbsolutePath(traceFile));
+ J2EEDataSource.setBeanProperty(ds, "traceFileAppend", Boolean.FALSE);
+ J2EEDataSource.setBeanProperty( ds, "traceLevel",
+ new Integer(ClientBaseDataSource.TRACE_ALL));
+
+ // Obtain connection.
+ PooledConnection physicalCon = null;
+ Connection con;
+ if (isXA) {
+ physicalCon = ((XADataSource)ds).getXAConnection();
+ con = physicalCon.getConnection();
+ } else if (isCP) {
+ physicalCon = ((ClientConnectionPoolDataSource)ds).
+ getPooledConnection();
+ con = physicalCon.getConnection();
+ } else {
+ con = ((DataSource)ds).getConnection();
+ }
+ con.setAutoCommit(false);
+
+ // Run test sequence.
+ // step 0: create table
+ Statement stmt = con.createStatement();
+ stmt.executeUpdate("create table " + tbl + " (id int)");
+ con.commit(); // Unconditional commit to persist table
+ endTranscation(con, isCommit, extraInvokations);
+ // step 1: insert data
+ PreparedStatement ps =
+ con.prepareStatement("insert into " + tbl + " values (?)");
+ for (int i=0; i < rowCount; i++) {
+ ps.setInt(1, i);
+ ps.executeUpdate();
+ endTranscation(con, isCommit, extraInvokations);
+ }
+ ps.close();
+ // Unconditional commit, should catch "missed" rollbacks above when we
+ // do a select with another connection at the end.
+ con.commit();
+ // step 2: select data
+ ResultSet rs = stmt.executeQuery("select count(*) from " + tbl);
+ rs.next();
+ rs.getInt(1);
+ rs.close();
+ endTranscation(con, isCommit, extraInvokations);
+ // step 3: values clause
+ rs = stmt.executeQuery("values 7");
+ assertTrue(rs.next());
+ assertEquals(7, rs.getInt(1));
+ rs.close();
+ stmt.close();
+ endTranscation(con, isCommit, extraInvokations);
+ con.close();
+ if (physicalCon != null) {
+ physicalCon.close();
+ }
+
+ // step 4: table content validation
+ stmt = createStatement();
+ rs = stmt.executeQuery("select count(*) from " + tbl);
+ rs.next();
+ assertEquals("Potential COMMIT/ROLLBACK protocol error",
+ isCommit ? rowCount : 0, rs.getInt(1));
+
+ // Parse the trace file for commits or rollbacks.
+ String token = "SEND BUFFER: " + (isXA ? "SYNCCTL" :
+ (isCommit ? "RDBCMM" : "RDBRLLBCK"));
+ int tokenCount = 0;
+ BufferedReader r = new BufferedReader(
+ PrivilegedFileOpsForTests.getFileReader(traceFile));
+ String line;
+ while ((line = r.readLine()) != null) {
+ if (line.startsWith("[derby]") && line.indexOf(token) != -1) {
+ println((isCommit ? "COMMIT: " : "ROLLBACK: ") + line);
+ tokenCount++;
+ }
+ }
+ r.close();
+ assertTrue("Parsing failed, no COMMITS/ROLLBACKS detected",
+ tokenCount > 0);
+ println(ds.getClass().getName() + ", invokeExtra=" + invokeExtra +
+ ", isCommit=" + isCommit + ", tokenCount=" + tokenCount);
+ return tokenCount;
+ }
+
+ /**
+ * Ends a transaction by invoking at least one commit or rollback.
+ *
+ * @param con the connection to work on
+ * @param isCommit if {@code true} commit is invoked, otherwise rollback
+ * is invoked
+ * @param count the number of extra commits or rollbacks to invoke
+ * @throws SQLException if a commit/rollback fails
+ */
+ private void endTranscation(Connection con, boolean isCommit, int count)
+ throws SQLException {
+ if (isCommit) {
+ con.commit();
+ for (int i=0; i < count; i++) {
+ con.commit();
+ }
+ } else {
+ con.rollback();
+ for (int i=0; i < count; i++) {
+ con.rollback();
+ }
+ }
+ }
+
/**
* Check setTransactioIsolation and with four connection in connection pool
* for DERBY-4343 case