// Copyright (c) 2005 Dustin Sallings <dustin@spy.net> package net.spy.db; import java.io.FileInputStream; import java.io.InputStream; import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; import org.jmock.Mock; import org.jmock.MockObjectTestCase; /** * Test the SQL Runner. */ public class SQLRunnerTest extends MockObjectTestCase { private static final String QUERY1="update some_table set val=1\n"; private static final String QUERY2="update other_table set val=1\n" + "otherval=2\n"; private Mock getSuccessfulMockFor(String query) { Mock rv=mock(Statement.class); rv.expects(once()).method("setQueryTimeout") .with(eq(37)); rv.expects(once()).method("executeUpdate") .with(eq(query)) .will(returnValue(1)); rv.expects(once()).method("close"); return(rv); } private String getScriptPath() { String path=(String)System.getProperties().get("basedir") + "/src/test/net/spy/test/test.sql"; return(path); } private void runSuccessfulTest(boolean withAutocommit) throws Exception { Mock connMock=mock(Connection.class); boolean origAutoCommit=false; connMock.expects(once()).method("getAutoCommit") .will(returnValue(origAutoCommit)); if(withAutocommit != origAutoCommit) { connMock.expects(once()).method("setAutoCommit") .with(eq(withAutocommit)); } connMock.expects(atLeastOnce()).method("createStatement") .will(onConsecutiveCalls( returnValue(getSuccessfulMockFor(QUERY1).proxy()), returnValue(getSuccessfulMockFor(QUERY2).proxy()))); if(!withAutocommit) { connMock.expects(once()).method("commit"); } if(withAutocommit != origAutoCommit) { connMock.expects(once()).method("setAutoCommit") .with(eq(origAutoCommit)); } InputStream f=new FileInputStream(getScriptPath()); SQLRunner sr=new SQLRunner((Connection)connMock.proxy()); sr.setTimeout(37); sr.runScript(f, withAutocommit, false); f.close(); } /** * Test a successful script execution with autocommit on. */ public void testSuccessfulScriptWithAutocommit() throws Exception { runSuccessfulTest(true); } /** * Test a successful script with autocommit off. */ public void testSuccessfulScriptWithoutAutocommit() throws Exception { runSuccessfulTest(false); } /** * Test invocations over a plain unhappy Connection. */ public void testFailingEarlyFailingOften() throws Exception { Mock connMock=mock(Connection.class); connMock.expects(once()).method("getAutoCommit") .will(throwException(new SQLException("bug off1"))); connMock.expects(once()).method("rollback") .will(throwException(new SQLException("bug off2"))); // XXX: This should probably not be invoked in the error case connMock.expects(once()).method("setAutoCommit") .with(eq(true)) .will(throwException(new SQLException("bug off3"))); // Run the script InputStream f=new FileInputStream(getScriptPath()); SQLRunner sr=new SQLRunner((Connection)connMock.proxy()); try { sr.runScript(f); } catch(SQLException e) { assertEquals("bug off1", e.getMessage()); } f.close(); } private Statement getBadStatement(String query) { Mock badMock=mock(Statement.class); badMock.expects(once()).method("setQueryTimeout") .with(eq(37)); badMock.expects(once()).method("executeUpdate") .with(eq(QUERY2)) .will(throwException(new SQLException("bug off"))); badMock.expects(once()).method("close"); return((Statement)badMock.proxy()); } /** * Test a single failing query. */ public void testFailingQuery() throws Exception { Mock connMock=mock(Connection.class); boolean origAutoCommit=true; // Set up the connection connMock.expects(once()).method("getAutoCommit") .will(returnValue(origAutoCommit)); connMock.expects(once()).method("setAutoCommit") .with(eq(false)); connMock.expects(atLeastOnce()).method("createStatement") .will(onConsecutiveCalls( returnValue(getSuccessfulMockFor(QUERY1).proxy()), returnValue(getBadStatement(QUERY2)))); connMock.expects(once()).method("rollback"); connMock.expects(once()).method("setAutoCommit") .with(eq(true)); InputStream f=new FileInputStream(getScriptPath()); SQLRunner sr=new SQLRunner((Connection)connMock.proxy()); sr.setTimeout(37); try { sr.runScript(f); fail("Expected an exception out of this invocation"); } catch(SQLException e) { assertEquals("bug off", e.getMessage()); } f.close(); } /** * Test a single failing query with the errok flag. The whole script will * be considered a success here, but an individual query will fail to * complete. */ public void testFailingQueryWithErrOk() throws Exception { Mock connMock=mock(Connection.class); boolean origAutoCommit=false; // Set up the connection connMock.expects(once()).method("getAutoCommit") .will(returnValue(origAutoCommit)); connMock.expects(once()).method("setAutoCommit") .with(eq(true)); connMock.expects(atLeastOnce()).method("createStatement") .will(onConsecutiveCalls( returnValue(getSuccessfulMockFor(QUERY1).proxy()), returnValue(getBadStatement(QUERY2)))); connMock.expects(once()).method("setAutoCommit") .with(eq(false)); InputStream f=new FileInputStream(getScriptPath()); SQLRunner sr=new SQLRunner((Connection)connMock.proxy()); sr.setTimeout(37); sr.runScript(f, true, true); f.close(); } }