package net.ttddyy.dsproxy.transform;
import net.ttddyy.dsproxy.TestUtils;
import net.ttddyy.dsproxy.listener.QueryExecutionListener;
import net.ttddyy.dsproxy.proxy.InterceptorHolder;
import net.ttddyy.dsproxy.proxy.jdk.JdkJdbcProxyFactory;
import org.hsqldb.jdbc.JDBCDataSource;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.core.Is.is;
import static org.mockito.Mockito.mock;
/**
* @author Tadaya Tsuyukubo
*/
public class StatementQueryTransformTest {
private DataSource rawDatasource;
private List<String> interceptedQueries = new ArrayList<String>();
@Before
public void setup() throws Exception {
// real datasource
JDBCDataSource rawDataSource = new JDBCDataSource();
rawDataSource.setDatabase("jdbc:hsqldb:mem:aname");
rawDataSource.setUser("sa");
this.rawDatasource = rawDataSource;
// populate datasource
Statement stat = rawDataSource.getConnection().createStatement();
stat.addBatch("create table foo ( id integer primary key, name varchar(10) );");
stat.addBatch("create table bar ( id integer primary key, name varchar(10) );");
stat.addBatch("insert into foo ( id, name )values (1, 'foo');");
stat.addBatch("insert into bar ( id, name )values (100, 'bar');");
stat.executeBatch();
}
@After
public void teardown() throws Exception {
TestUtils.shutdown(rawDatasource);
interceptedQueries.clear();
}
private Connection getProxyConnectionForSelect() throws Exception {
return getProxyConnection(true);
}
private Connection getProxyConnectionForUpdate() throws Exception {
return getProxyConnection(false);
}
private Connection getProxyConnection(final boolean isSelect) throws Exception {
QueryTransformer transformer = new QueryTransformer() {
public String transformQuery(TransformInfo transformInfo) {
interceptedQueries.add(transformInfo.getQuery());
return isSelect ? "SELECT * FROM bar" : "UPDATE bar SET name = 'BAR'";
}
};
QueryExecutionListener queryListener = mock(QueryExecutionListener.class);
InterceptorHolder interceptorHolder = new InterceptorHolder(queryListener, transformer);
return new JdkJdbcProxyFactory().createConnection(rawDatasource.getConnection(), interceptorHolder);
}
@Test
public void testExecuteWithSelect() throws Exception {
Statement stat = getProxyConnectionForSelect().createStatement();
boolean result = stat.execute("SELECT name FROM foo");
assertThat(result, is(true));
// verify intercepted query
assertThat(interceptedQueries, hasSize(1));
assertThat(interceptedQueries, hasItem("SELECT name FROM foo"));
}
@Test
public void testExecuteWithUpdate() throws Exception {
// stmt.execute() with update statement. (expect false)
Statement stat = getProxyConnectionForUpdate().createStatement();
boolean result = stat.execute("UPDATE foo SET name = 'FOO'");
assertThat(result, is(false));
// verify intercepted query
assertThat(interceptedQueries, hasSize(1));
assertThat(interceptedQueries, hasItem("UPDATE foo SET name = 'FOO'"));
// verify bar is updated instead of foo
ResultSet rs = rawDatasource.getConnection().createStatement().executeQuery("SELECT name FROM foo");
assertThat(rs.next(), is(true));
assertThat(rs.getString("name"), is("foo"));
rs = rawDatasource.getConnection().createStatement().executeQuery("SELECT name FROM bar");
assertThat(rs.next(), is(true));
assertThat(rs.getString("name"), is("BAR"));
}
@Test
public void testExecuteQuery() throws Exception {
Statement stat = getProxyConnectionForSelect().createStatement();
ResultSet resultSet = stat.executeQuery("SELECT name FROM foo");
assertThat(resultSet.next(), is(true));
assertThat(resultSet.getInt("id"), is(100));
assertThat(resultSet.getString("name"), is("bar"));
assertThat(interceptedQueries, hasSize(1));
assertThat(interceptedQueries.get(0), is("SELECT name FROM foo"));
}
@Test
public void testExecuteUpdate() throws Exception {
Statement stat = getProxyConnectionForUpdate().createStatement();
int count = stat.executeUpdate("UPDATE foo SET name = 'FOO'");
assertThat(count, is(1));
assertThat(interceptedQueries, hasSize(1));
assertThat(interceptedQueries.get(0), is("UPDATE foo SET name = 'FOO'"));
// verify bar is updated instead of foo
ResultSet rs = rawDatasource.getConnection().createStatement().executeQuery("SELECT name FROM foo");
assertThat(rs.next(), is(true));
assertThat(rs.getString("name"), is("foo"));
rs = rawDatasource.getConnection().createStatement().executeQuery("SELECT name FROM bar");
assertThat(rs.next(), is(true));
assertThat(rs.getString("name"), is("BAR"));
}
@Test
public void testExecuteBatch() throws Exception {
Statement stat = getProxyConnectionForUpdate().createStatement();
stat.addBatch("UPDATE foo SET name = 'FOO1'");
stat.addBatch("UPDATE foo SET name = 'FOO2'");
int[] result = stat.executeBatch();
assertThat(result.length, is(2));
assertThat(result[0], is(1));
assertThat(result[1], is(1));
assertThat(interceptedQueries, hasSize(2));
assertThat(interceptedQueries.get(0), is("UPDATE foo SET name = 'FOO1'"));
assertThat(interceptedQueries.get(1), is("UPDATE foo SET name = 'FOO2'"));
// verify bar is updated instead of foo
ResultSet rs = rawDatasource.getConnection().createStatement().executeQuery("SELECT name FROM foo");
assertThat(rs.next(), is(true));
assertThat(rs.getString("name"), is("foo"));
rs = rawDatasource.getConnection().createStatement().executeQuery("SELECT name FROM bar");
assertThat(rs.next(), is(true));
assertThat(rs.getString("name"), is("BAR"));
}
@Test
public void testClearBatch() throws Exception {
Statement stat = getProxyConnectionForUpdate().createStatement();
stat.addBatch("UPDATE foo SET name = 'FOO1'");
stat.addBatch("UPDATE foo SET name = 'FOO2'");
stat.clearBatch();
int[] result = stat.executeBatch();
assertThat(result.length, is(0));
// even though batch is canceled, interceptor should be called
assertThat(interceptedQueries, hasSize(2));
assertThat(interceptedQueries, hasItems("UPDATE foo SET name = 'FOO1'", "UPDATE foo SET name = 'FOO2'"));
// verify data should not be changed
ResultSet rs = rawDatasource.getConnection().createStatement().executeQuery("SELECT name FROM foo");
assertThat(rs.next(), is(true));
assertThat(rs.getString("name"), is("foo"));
rs = rawDatasource.getConnection().createStatement().executeQuery("SELECT name FROM bar");
assertThat(rs.next(), is(true));
assertThat(rs.getString("name"), is("bar"));
}
}