db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From kahat...@apache.org
Subject svn commit: r548696 - in /db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang: ErrorMessageTest.java _Suite.java
Date Tue, 19 Jun 2007 11:36:00 GMT
Author: kahatlen
Date: Tue Jun 19 04:35:59 2007
New Revision: 548696

URL: http://svn.apache.org/viewvc?view=rev&rev=548696
Log:
DERBY-2829: Write a test which verifies that timeout errors contain
information about the locks involved

Regression tests for DERBY-2817.

Added:
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/ErrorMessageTest.java
  (with props)
Modified:
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/_Suite.java

Added: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/ErrorMessageTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/ErrorMessageTest.java?view=auto&rev=548696
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/ErrorMessageTest.java
(added)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/ErrorMessageTest.java
Tue Jun 19 04:35:59 2007
@@ -0,0 +1,198 @@
+/*
+ * Class org.apache.derbyTesting.functionTests.tests.lang.ErrorMessageTest
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.derbyTesting.functionTests.tests.lang;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Properties;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import org.apache.derbyTesting.junit.BaseJDBCTestCase;
+import org.apache.derbyTesting.junit.CleanDatabaseTestSetup;
+import org.apache.derbyTesting.junit.DatabasePropertyTestSetup;
+import org.apache.derbyTesting.junit.JDBC;
+
+public class ErrorMessageTest extends BaseJDBCTestCase {
+    public ErrorMessageTest(String name) {
+        super(name);
+    }
+
+    /**
+     * Create a test suite with all the tests in this class. The tests are only
+     * run in embedded mode since they test the messages generated by the
+     * embedded driver.
+     */
+    public static Test suite() {
+
+        if (JDBC.vmSupportsJSR169()) {
+            // Foundation 1.1 doesn't support the regex classes. Return an
+            // empty test suite.
+            return new TestSuite("ErrorMessageTest");
+        }
+
+        Test test = new TestSuite(ErrorMessageTest.class, "ErrorMessageTest");
+        // create some data to work on
+        test = new CleanDatabaseTestSetup(test) {
+            protected void decorateSQL(Statement s) throws SQLException {
+                s.executeUpdate("create table t (id int primary key, " +
+                                "text varchar(10))");
+                s.executeUpdate("insert into t (id) values 1, 2");
+            }
+        };
+        Properties prop = new Properties();
+        // set timeouts so that the tests finish sooner
+        prop.setProperty("derby.locks.waitTimeout", "4");
+        prop.setProperty("derby.locks.deadlockTimeout", "2");
+        // make sure lock table is dumped on wait timeout
+        prop.setProperty("derby.locks.deadlockTrace", "true");
+        test = new DatabasePropertyTestSetup(test, prop);
+        return test;
+    }
+
+    /**
+     * Test that a wait timeout prints the lock table correctly when the
+     * <code>derby.locks.deadlockTrace</code> property is set. DERBY-2817
+     */
+    public void testWaitTimeout() throws SQLException {
+        getConnection().setAutoCommit(false);
+        Statement s = createStatement();
+        assertUpdateCount(s, 1, "update t set text='xxx' where id=1");
+        Connection c2 = openDefaultConnection();
+        Statement s2 = c2.createStatement();
+        try {
+            // the first transaction has locked row with id=1, so this query
+            // will time out
+            JDBC.assertDrainResults(
+                    s2.executeQuery("select * from t where id=1"));
+            fail("Expected lock timeout");
+        } catch (SQLException e) {
+            assertSQLState("Not a timeout", "40XL2", e);
+
+            // check that information about the victim is printed
+            String[] msg = e.getMessage().split("\n");
+            assertEquals("*** The following row is the victim ***", msg[4]);
+            assertEquals("*** The above row is the victim ***", msg[6]);
+            String[] victim = msg[5].split(" *\\|");
+            assertTrue("Invalid XID string: " + victim[0],
+                       victim[0].matches("\\d+"));
+            assertEquals("Victim should be a row lock", "ROW", victim[1]);
+            assertEquals("Victim should be a shared lock", "S", victim[2]);
+            assertEquals("Victim should be waiting", "WAIT", victim[5]);
+
+            // check that the rest of the lock table is dumped
+            boolean locksDumped = false;
+            for (int i = 7; i < msg.length - 1; i++) {
+                String[] tokens = msg[i].split(" *\\|");
+                assertTrue("Invalid XID string: " + tokens[0],
+                           tokens[0].matches("\\d+"));
+                assertTrue("Unexpected lock type: " + tokens[1],
+                           tokens[1].matches("ROW|TABLE"));
+                assertTrue("Unexpected lock mode: " + tokens[2],
+                           tokens[2].matches("S|X|IX|IS"));
+                assertEquals("Expected lock to be granted", "GRANT", tokens[5]);
+                locksDumped = true;
+            }
+            assertTrue("No locks dumped", locksDumped);
+        }
+        s.close();
+        s2.close();
+        c2.close();
+    }
+
+    /**
+     * Test that the error message from a deadlock timeout contains information
+     * about the locks involved in the deadlock. DERBY-2817
+     */
+    public void testDeadlockTimeout()
+            throws SQLException, InterruptedException {
+        getConnection().setAutoCommit(false);
+        Statement s = createStatement();
+        assertUpdateCount(s, 1, "update t set text='xxx' where id=1");
+
+        // start another transaction that needs to wait for the first one
+        Connection c2 = openDefaultConnection();
+        c2.setAutoCommit(false);
+        final Statement s2 = c2.createStatement();
+        assertUpdateCount(s2, 1, "update t set text='yyy' where id=2");
+        final SQLException[] holder = new SQLException[2];
+        Thread t = new Thread(new Runnable() {
+                public void run() {
+                    try {
+                        // will wait since the other transaction has locked the
+                        // row exclusively
+                        JDBC.assertDrainResults(
+                            s2.executeQuery("select * from t where id=1"));
+                    } catch (SQLException e) {
+                        holder[0] = e;
+                    }
+                }
+            });
+        t.start();
+
+        // Execute a query that needs to wait for c2 to finish. Now, c1 is
+        // waiting for c2, and c2 is waiting for c1.
+        try {
+            JDBC.assertDrainResults(
+                s.executeQuery("select * from t where id=2"));
+        } catch (SQLException e) {
+            holder[1] = e;
+        }
+
+        t.join();
+
+        String msg;
+        // check that only one of the transactions failed
+        if (holder[0] != null) {
+            assertSQLState("Not a deadlock", "40001", holder[0]);
+            assertNull("Only one of the waiters should be aborted", holder[1]);
+            msg = holder[0].getMessage();
+        } else {
+            assertSQLState("Not a deadlock", "40001", holder[1]);
+            msg = holder[1].getMessage();
+        }
+
+        String[] lines = msg.split("\n");
+        assertEquals("Unexpected number of lines in message", 8, lines.length);
+
+        Pattern[] patterns = new Pattern[] {
+            Pattern.compile("Lock : ROW, T, \\(\\d+,\\d+\\)"),
+            Pattern.compile(" *Waiting XID : \\{\\d+, S\\} , APP, " +
+                            "select \\* from t where id=(1|2)"),
+            Pattern.compile(" *Granted XID : \\{\\d+, X\\} *"),
+        };
+
+        // check the descriptions of the two locks involved in the deadlock
+        for (int i = 0; i < patterns.length * 2; i++) {
+            String line = lines[i+1];
+            Matcher m = patterns[i%patterns.length].matcher(line);
+            assertTrue("mismatch: " + line, m.matches());
+        }
+
+        s.close();
+        s2.close();
+        c2.rollback();
+        c2.close();
+    }
+}

Propchange: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/ErrorMessageTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/_Suite.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/_Suite.java?view=diff&rev=548696&r1=548695&r2=548696
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/_Suite.java
(original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/_Suite.java
Tue Jun 19 04:35:59 2007
@@ -139,6 +139,9 @@
             // also, test calls procedures which use DriverManager
             // to get the default connection.
             suite.addTest(GrantRevokeDDLTest.suite());
+
+            // test uses regex classes that are not available in Foundation 1.1
+            suite.addTest(ErrorMessageTest.suite());
         }
 
         return suite;



Mime
View raw message