summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Winkler2009-07-08 08:45:16 (EDT)
committerStefan Winkler2009-07-08 08:45:16 (EDT)
commitd8395e78c49f2a52d195008718fbad60c426ef24 (patch)
tree9326afd0a615fe198b978c7d9b2c656e63287c3e
parent386c5b7edc011f75cd072cec7a36cbfccd81a50f (diff)
downloadcdo-d8395e78c49f2a52d195008718fbad60c426ef24.zip
cdo-d8395e78c49f2a52d195008718fbad60c426ef24.tar.gz
cdo-d8395e78c49f2a52d195008718fbad60c426ef24.tar.bz2
[282828] [DB] [Test] Provide unit tests to check DBMS transaction behavior
https://bugs.eclipse.org/bugs/show_bug.cgi?id=282828
-rw-r--r--plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/capabilities/AbstractCapabilityTest.java340
-rw-r--r--plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/capabilities/DerbyTest.java45
-rw-r--r--plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/capabilities/H2Test.java40
-rw-r--r--plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/capabilities/HsqlTest.java41
-rw-r--r--plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/capabilities/MysqlTest.java42
5 files changed, 508 insertions, 0 deletions
diff --git a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/capabilities/AbstractCapabilityTest.java b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/capabilities/AbstractCapabilityTest.java
new file mode 100644
index 0000000..56e9390
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/capabilities/AbstractCapabilityTest.java
@@ -0,0 +1,340 @@
+/**
+ * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.emf.cdo.tests.db.capabilities;
+
+import org.eclipse.net4j.db.IDBConnectionProvider;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import junit.framework.TestCase;
+
+/**
+ * This is a simple test case that can be used to analyze how a DBMS handles DML in the middle of a transaction.
+ *
+ * @author Stefan Winkler
+ */
+public abstract class AbstractCapabilityTest extends TestCase
+{
+ public AbstractCapabilityTest(String name)
+ {
+ super(name);
+ }
+
+ abstract protected IDBConnectionProvider getConnectionProvider();
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ // create table
+ Connection conn = getConnectionProvider().getConnection();
+ conn.setAutoCommit(false);
+ Statement stmt = conn.createStatement();
+
+ // make sure tables don't exist!
+ try
+ {
+ stmt.execute("drop table status_table");
+ }
+ catch (Exception e)
+ {
+ }
+
+ try
+ {
+ stmt.execute("drop table change_table");
+ }
+ catch (Exception e)
+ {
+ }
+
+ stmt.execute("create table status_table (trans varchar(255), status varchar(255))");
+ stmt.execute("insert into status_table values ('transaction1', 'unchanged')");
+ stmt.execute("insert into status_table values ('transaction2', 'unchanged')");
+
+ stmt.execute("create table change_table (trans varchar(255), status varchar(255))");
+ stmt.execute("insert into change_table values ('transaction1', 'unchanged')");
+ stmt.execute("insert into change_table values ('transaction2', 'unchanged')");
+
+ conn.commit();
+ stmt.close();
+ conn.close();
+ };
+
+ @Override
+ protected void tearDown() throws Exception
+ {
+ Connection conn = getConnectionProvider().getConnection();
+ conn.setAutoCommit(true);
+ Statement stmt = conn.createStatement();
+
+ stmt.execute("drop table status_table");
+ stmt.execute("drop table change_table");
+
+ stmt.close();
+ conn.close();
+
+ }
+
+ public void testDirtyRead() throws Exception
+ {
+ msg("TEST " + getClass().getSimpleName() + " - DIRTY READ");
+ msg("----------------------------------------------------------");
+ msg("Transaction 1 changes a value, transaction 2 will read the value.");
+ msg("The value of transaction 2 should be UNCHANGED (else we have a dirty read)");
+
+ Thread t = new Thread()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ IDBConnectionProvider provider = getConnectionProvider();
+ Connection transaction1 = provider.getConnection();
+ transaction1.setAutoCommit(false);
+ Statement tx1stmt = transaction1.createStatement();
+ tx1stmt.executeUpdate("update status_table set status = 'changed' where trans = 'transaction1'");
+ msg("Read value (transaction 1) is "
+ + select(transaction1, "select status from status_table where trans = 'transaction1'").toUpperCase());
+ sleep(1000);
+
+ transaction1.rollback();
+ transaction1.close();
+ }
+ catch (Exception e)
+ {
+ throw new Error(e);
+ }
+ };
+ };
+ t.start();
+
+ Thread.sleep(300);
+
+ IDBConnectionProvider provider = getConnectionProvider();
+ Connection transaction2 = provider.getConnection();
+
+ transaction2.setAutoCommit(false);
+
+ msg("Read value (transaction 2) is "
+ + select(transaction2, "select status from status_table where trans = 'transaction1'").toUpperCase());
+ msg("----------------------------------------------------------");
+ transaction2.rollback();
+ transaction2.close();
+ }
+
+ public void testRollback() throws Exception
+ {
+ msg("TEST " + getClass().getSimpleName() + " - ROLLBACK");
+ msg("----------------------------------------------------------");
+ msg("Transaction changes a value and does a rollback.");
+ msg("The value of after rollback should be UNCHANGED.");
+
+ IDBConnectionProvider provider = getConnectionProvider();
+ Connection transaction1 = provider.getConnection();
+ transaction1.setAutoCommit(false);
+
+ Statement tx1stmt = transaction1.createStatement();
+ tx1stmt.executeUpdate("update status_table set status = 'changed' where trans = 'transaction1'");
+
+ msg("Read value before rollback is "
+ + select(transaction1, "select status from status_table where trans = 'transaction1'").toUpperCase());
+
+ transaction1.rollback();
+ transaction1.close();
+
+ Connection view = provider.getConnection();
+ msg("Read value after rollback is "
+ + select(view, "select status from status_table where trans = 'transaction1'").toUpperCase());
+ view.close();
+ msg("----------------------------------------------------------");
+ }
+
+ public void testDml() throws Exception
+ {
+ msg("TEST " + getClass().getSimpleName() + " - DML");
+ msg("----------------------------------------------------------");
+ msg("Transaction 1 will execute DML, transaction 2 will just change its data.");
+
+ Thread t = new Thread()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ IDBConnectionProvider provider = getConnectionProvider();
+ Connection transaction2 = provider.getConnection();
+ Statement tx2stmt = transaction2.createStatement();
+ transaction2.setAutoCommit(false);
+ tx2stmt.executeUpdate("update status_table set status = 'changed' where trans = 'transaction2'");
+ tx2stmt.executeUpdate("update change_table set status = 'changed' where trans = 'transaction2'");
+ tx2stmt.close();
+ sleep(1000);
+ transaction2.rollback();
+ transaction2.close();
+ }
+ catch (Exception e)
+ {
+ throw new Error(e);
+ }
+ }
+ };
+ t.start();
+
+ Thread.sleep(100);
+
+ IDBConnectionProvider provider = getConnectionProvider();
+ Connection transaction1 = provider.getConnection();
+ transaction1.setAutoCommit(false);
+
+ Statement tx1stmt = transaction1.createStatement();
+
+ tx1stmt.executeUpdate("update status_table set status = 'changed' where trans = 'transaction1'");
+ tx1stmt.executeUpdate("update change_table set status = 'changed' where trans = 'transaction1'");
+
+ tx1stmt.execute("alter table change_table add new_column varchar(255) default 'added column present'");
+
+ tx1stmt.close();
+
+ transaction1.rollback();
+ transaction1.close();
+
+ t.join();
+
+ Connection view = provider.getConnection();
+
+ msg("transaction1: unchanged table record is "
+ + select(view, "select status from status_table where trans = 'transaction1'").toUpperCase());
+ msg("transaction2: unchanged table record is "
+ + select(view, "select status from status_table where trans = 'transaction2'").toUpperCase());
+
+ msg("transaction1: changed table record is "
+ + select(view, "select status from change_table where trans = 'transaction1'").toUpperCase());
+ msg("transaction2: changed table record is "
+ + select(view, "select status from change_table where trans = 'transaction2'").toUpperCase());
+
+ String present = "present";
+ try
+ {
+ select(view, "select new_column from change_table where trans = 'transaction2'");
+ }
+ catch (SQLException e)
+ {
+ present = "not present";
+ }
+
+ msg("Added column is " + present.toUpperCase());
+ view.close();
+
+ msg("----------------------------------------------------------");
+
+ }
+
+ private void msg(String string)
+ {
+ System.out.println(string);
+ }
+
+ private String select(Connection conn, String sql) throws SQLException
+ {
+ ResultSet rs = null;
+ try
+ {
+ rs = conn.createStatement().executeQuery(sql);
+ rs.next();
+ return rs.getString(1);
+ }
+ finally
+ {
+ if (rs != null)
+ {
+ try
+ {
+ rs.close();
+ }
+ catch (SQLException ex)
+ {
+ // NOP
+ }
+ }
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private void sqlDump(Connection conn, String sql)
+ {
+ ResultSet rs = null;
+ try
+ {
+ System.out.format("Dumping output of %s\n", sql); //$NON-NLS-1$
+ rs = conn.createStatement().executeQuery(sql);
+ int numCol = rs.getMetaData().getColumnCount();
+
+ StringBuilder row = new StringBuilder(" ");
+ for (int c = 1; c <= numCol; c++)
+ {
+ row.append(String.format("%15s | ", rs.getMetaData().getColumnLabel(c))); //$NON-NLS-1$
+ }
+
+ System.out.println(row.toString());
+
+ row = new StringBuilder();
+ for (int c = 1; c <= numCol; c++)
+ {
+ row.append("-----------------+"); //$NON-NLS-1$
+ }
+
+ System.out.println(row.toString());
+
+ while (rs.next())
+ {
+ row = new StringBuilder(" ");
+ for (int c = 1; c <= numCol; c++)
+ {
+ row.append(String.format("%15s | ", rs.getString(c))); //$NON-NLS-1$
+ }
+
+ System.out.println(row.toString());
+ }
+
+ row = new StringBuilder();
+ for (int c = 1; c <= numCol; c++)
+ {
+ row.append("-----------------+"); //$NON-NLS-1$
+ }
+
+ System.out.println(row.toString());
+ }
+ catch (SQLException ex)
+ {
+ // NOP
+ }
+ finally
+ {
+ if (rs != null)
+ {
+ try
+ {
+ rs.close();
+ }
+ catch (SQLException ex)
+ {
+ // NOP
+ }
+ }
+ }
+ }
+
+}
diff --git a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/capabilities/DerbyTest.java b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/capabilities/DerbyTest.java
new file mode 100644
index 0000000..7216c95
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/capabilities/DerbyTest.java
@@ -0,0 +1,45 @@
+/**
+ * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.emf.cdo.tests.db.capabilities;
+
+import org.eclipse.net4j.db.DBUtil;
+import org.eclipse.net4j.db.IDBConnectionProvider;
+import org.eclipse.net4j.util.io.TMPUtil;
+
+import org.apache.derby.jdbc.EmbeddedDataSource;
+
+import java.io.File;
+
+/**
+ * @author Stefan Winkler
+ */
+public class DerbyTest extends AbstractCapabilityTest
+{
+ public DerbyTest()
+ {
+ super("derby");
+ File dbFolder = TMPUtil.createTempFolder("derby_", "_test", new File("c:/temp"));
+ dbFolder.delete();
+ EmbeddedDataSource derbyds = new EmbeddedDataSource();
+ derbyds.setDatabaseName(dbFolder.getAbsolutePath());
+ derbyds.setCreateDatabase("create");
+ provider = DBUtil.createConnectionProvider(derbyds);
+
+ }
+
+ IDBConnectionProvider provider = null;
+
+ @Override
+ protected IDBConnectionProvider getConnectionProvider()
+ {
+ return provider;
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/capabilities/H2Test.java b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/capabilities/H2Test.java
new file mode 100644
index 0000000..5d2af41
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/capabilities/H2Test.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.emf.cdo.tests.db.capabilities;
+
+import org.eclipse.net4j.db.DBUtil;
+import org.eclipse.net4j.db.IDBConnectionProvider;
+
+import org.h2.jdbcx.JdbcDataSource;
+
+/**
+ * @author Stefan Winkler
+ */
+public class H2Test extends AbstractCapabilityTest
+{
+ public H2Test()
+ {
+ super("h2");
+ JdbcDataSource h2ds = new JdbcDataSource();
+ h2ds = new JdbcDataSource();
+ h2ds.setURL("jdbc:h2:file:c:/temp/h2test");
+ h2ds.setUser("sa");
+ provider = DBUtil.createConnectionProvider(h2ds);
+ }
+
+ IDBConnectionProvider provider = null;
+
+ @Override
+ protected IDBConnectionProvider getConnectionProvider()
+ {
+ return provider;
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/capabilities/HsqlTest.java b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/capabilities/HsqlTest.java
new file mode 100644
index 0000000..5c409d2
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/capabilities/HsqlTest.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.emf.cdo.tests.db.capabilities;
+
+import org.eclipse.net4j.db.DBUtil;
+import org.eclipse.net4j.db.IDBConnectionProvider;
+
+import org.hsqldb.jdbc.jdbcDataSource;
+
+/**
+ * @author Stefan Winkler
+ */
+public class HsqlTest extends AbstractCapabilityTest
+{
+
+ public HsqlTest()
+ {
+ super("hsqldb");
+ jdbcDataSource hsqlds = new jdbcDataSource();
+ hsqlds.setDatabase("jdbc:hsqldb:file:c:/temp/hsql_test");
+ hsqlds.setUser("sa");
+
+ provider = DBUtil.createConnectionProvider(hsqlds);
+ }
+
+ IDBConnectionProvider provider = null;
+
+ @Override
+ protected IDBConnectionProvider getConnectionProvider()
+ {
+ return provider;
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/capabilities/MysqlTest.java b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/capabilities/MysqlTest.java
new file mode 100644
index 0000000..5cfa883
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/capabilities/MysqlTest.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.emf.cdo.tests.db.capabilities;
+
+import org.eclipse.net4j.db.DBUtil;
+import org.eclipse.net4j.db.IDBConnectionProvider;
+
+import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
+
+/**
+ * @author Stefan Winkler
+ */
+public class MysqlTest extends AbstractCapabilityTest
+{
+
+ private IDBConnectionProvider provider;
+
+ public MysqlTest()
+ {
+ super("mysql");
+ MysqlDataSource mysqlds = new MysqlDataSource();
+ mysqlds.setUrl("jdbc:mysql://localhost:33306/winkler_r2");
+ mysqlds.setUser("winkler");
+ mysqlds.setPassword("winkler");
+ provider = DBUtil.createConnectionProvider(mysqlds);
+ }
+
+ @Override
+ protected IDBConnectionProvider getConnectionProvider()
+ {
+ return provider;
+ }
+
+}