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.PreparedStatement; 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.hasItem; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.core.Is.is; import static org.mockito.Mockito.mock; /** * @author Tadaya Tsuyukubo */ public class PreparedStatementQueryTransformTest { 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 statement = rawDataSource.getConnection().createStatement(); statement.addBatch("create table foo ( id integer primary key, name varchar(10) );"); statement.addBatch("create table bar ( id integer primary key, name varchar(10) );"); statement.addBatch("insert into foo ( id, name )values (1, 'foo');"); statement.addBatch("insert into bar ( id, name )values (100, 'bar');"); statement.executeBatch(); } @After public void teardown() throws Exception { interceptedQueries.clear(); TestUtils.shutdown(rawDatasource); } 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 = ?"; } }; QueryExecutionListener queryListener = mock(QueryExecutionListener.class); InterceptorHolder interceptorHolder = new InterceptorHolder(queryListener, transformer); return new JdkJdbcProxyFactory().createConnection(rawDatasource.getConnection(), interceptorHolder); } @Test public void testCreatePreparedStatement() throws Exception { getProxyConnectionForUpdate().prepareStatement("UPDATE foo SET name = ?"); // when preparedStatement method is called, intercept should be called assertThat(interceptedQueries, hasSize(1)); assertThat(interceptedQueries, hasItem("UPDATE foo SET name = ?")); } @Test public void testExecuteWithSelect() throws Exception { PreparedStatement ps = getProxyConnectionForSelect().prepareStatement("SELECT name FROM foo"); boolean result = ps.execute(); assertThat(result, is(true)); // verify intercepted query assertThat(interceptedQueries, hasSize(1)); assertThat(interceptedQueries, hasItem("SELECT name FROM foo")); } @Test public void testExecuteWithUpdate() throws Exception { PreparedStatement ps = getProxyConnectionForUpdate().prepareStatement("UPDATE foo SET name = ?"); ps.setString(1, "FOO"); boolean result = ps.execute(); assertThat(result, is(false)); // verify intercepted query assertThat(interceptedQueries, hasSize(1)); assertThat(interceptedQueries, hasItem("UPDATE foo SET name = ?")); // 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("FOO")); } @Test public void testExecuteQuery() throws Exception { PreparedStatement ps = getProxyConnectionForSelect().prepareStatement("SELECT name FROM foo"); ResultSet resultSet = ps.executeQuery(); assertThat(resultSet.next(), is(true)); assertThat(resultSet.getInt("id"), is(100)); assertThat(resultSet.getString("name"), is("bar")); // verify intercepted query assertThat(interceptedQueries, hasSize(1)); assertThat(interceptedQueries, hasItem("SELECT name FROM foo")); } @Test public void testExecuteUpdate() throws Exception { PreparedStatement ps = getProxyConnectionForUpdate().prepareStatement("UPDATE foo SET name = ?"); ps.setString(1, "FOO"); int count = ps.executeUpdate(); assertThat(count, is(1)); // verify intercepted query assertThat(interceptedQueries, hasSize(1)); assertThat(interceptedQueries, hasItem("UPDATE foo SET name = ?")); // 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("FOO")); } @Test public void testExecuteBatch() throws Exception { PreparedStatement ps = getProxyConnectionForUpdate().prepareStatement("UPDATE foo SET name = ?"); ps.setString(1, "FOO1"); ps.addBatch(); ps.setString(1, "FOO2"); ps.addBatch(); int[] result = ps.executeBatch(); assertThat(result.length, is(2)); assertThat(result[0], is(1)); assertThat(result[1], is(1)); // verify intercepted query assertThat(interceptedQueries, hasSize(1)); assertThat(interceptedQueries, hasItem("UPDATE foo SET name = ?")); // 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("FOO2")); } @Test public void testClearBatch() throws Exception { PreparedStatement ps = getProxyConnectionForUpdate().prepareStatement("UPDATE foo SET name = ?"); ps.clearBatch(); // even though batch is canceled, interceptor was called once. assertThat(interceptedQueries, hasSize(1)); assertThat(interceptedQueries, hasItem("UPDATE foo SET name = ?")); } }