package net.ttddyy.dsproxy.proxy; import net.ttddyy.dsproxy.ExecutionInfo; import net.ttddyy.dsproxy.QueryInfo; import net.ttddyy.dsproxy.listener.QueryExecutionListener; import net.ttddyy.dsproxy.proxy.jdk.ConnectionInvocationHandler; import net.ttddyy.dsproxy.proxy.jdk.JdkJdbcProxyFactory; import net.ttddyy.dsproxy.transform.QueryTransformer; import org.junit.Test; import org.mockito.ArgumentCaptor; import java.io.InputStream; import java.io.Reader; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.math.BigDecimal; import java.net.URL; import java.sql.Array; import java.sql.Blob; import java.sql.CallableStatement; import java.sql.Clob; import java.sql.Connection; import java.sql.Date; import java.sql.Ref; import java.sql.ResultSet; import java.sql.Time; import java.sql.Timestamp; import java.sql.Types; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.aMapWithSize; import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.Matchers.sameInstance; import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; /** * TODO: cleanup/refactoring * * @author Tadaya Tsuyukubo */ public class PreparedStatementProxyLogicForCallableStatementMockTest { private static final String DS_NAME = "myDS"; @Test public void testExecuteWithNoParam() throws Throwable { final String query = "{call procedure_name}"; CallableStatement stat = mock(CallableStatement.class); QueryExecutionListener listener = mock(QueryExecutionListener.class); InterceptorHolder interceptorHolder = getInterceptorHolder(listener); when(stat.execute()).thenReturn(true); PreparedStatementProxyLogic logic = getProxyLogic(stat, query, interceptorHolder); Method method = CallableStatement.class.getMethod("execute"); Object result = logic.invoke(method, null); assertThat(result, is(instanceOf(boolean.class))); assertThat((Boolean) result, is(Boolean.TRUE)); verifyListenerWithNoParam(listener, "execute", query); } @Test public void testExecuteWithParamByPosition() throws Throwable { final String query = "{call procedure_name}"; CallableStatement stat = mock(CallableStatement.class); QueryExecutionListener listener = mock(QueryExecutionListener.class); InterceptorHolder interceptorHolder = getInterceptorHolder(listener); when(stat.execute()).thenReturn(true); PreparedStatementProxyLogic logic = getProxyLogic(stat, query, interceptorHolder); setParameterByPosition(logic); Method method = CallableStatement.class.getMethod("execute"); Object result = logic.invoke(method, null); assertThat(result, is(instanceOf(boolean.class))); assertThat((Boolean) result, is(Boolean.TRUE)); verifyParametersByPosition(stat); verifyListenerWithParamByPosition(listener, "execute", query); } @Test public void testExecuteWithParamByName() throws Throwable { final String query = "{call procedure_name}"; CallableStatement stat = mock(CallableStatement.class); QueryExecutionListener listener = mock(QueryExecutionListener.class); InterceptorHolder interceptorHolder = getInterceptorHolder(listener); when(stat.execute()).thenReturn(true); PreparedStatementProxyLogic logic = getProxyLogic(stat, query, interceptorHolder); setParameterByName(logic); Method method = CallableStatement.class.getMethod("execute"); Object result = logic.invoke(method, null); assertThat(result, is(instanceOf(boolean.class))); assertThat((Boolean) result, is(true)); verifyParametersByName(stat); verifyListenerWithParamByName(listener, "execute", query); } @Test public void testExecuteUpdateWithNoParam() throws Throwable { final String query = "{call procedure_name}"; CallableStatement stat = mock(CallableStatement.class); QueryExecutionListener listener = mock(QueryExecutionListener.class); InterceptorHolder interceptorHolder = getInterceptorHolder(listener); when(stat.executeUpdate()).thenReturn(100); PreparedStatementProxyLogic logic = getProxyLogic(stat, query, interceptorHolder); Method method = CallableStatement.class.getMethod("executeUpdate"); Object result = logic.invoke(method, null); assertThat(result, is(instanceOf(int.class))); assertThat((Integer) result, is(100)); verifyListenerWithNoParam(listener, "executeUpdate", query); } @Test public void testExecuteUpdateWithParamByPosition() throws Throwable { final String query = "{call procedure_name}"; CallableStatement stat = mock(CallableStatement.class); QueryExecutionListener listener = mock(QueryExecutionListener.class); InterceptorHolder interceptorHolder = getInterceptorHolder(listener); when(stat.executeUpdate()).thenReturn(100); PreparedStatementProxyLogic logic = getProxyLogic(stat, query, interceptorHolder); setParameterByPosition(logic); Method method = CallableStatement.class.getMethod("executeUpdate"); Object result = logic.invoke(method, null); assertThat(result, is(instanceOf(int.class))); assertThat((Integer) result, is(100)); verifyParametersByPosition(stat); verifyListenerWithParamByPosition(listener, "executeUpdate", query); } @Test public void testExecuteUpdateWithParamByName() throws Throwable { final String query = "{call procedure_name}"; CallableStatement stat = mock(CallableStatement.class); QueryExecutionListener listener = mock(QueryExecutionListener.class); InterceptorHolder interceptorHolder = getInterceptorHolder(listener); when(stat.executeUpdate()).thenReturn(100); PreparedStatementProxyLogic logic = getProxyLogic(stat, query, interceptorHolder); setParameterByName(logic); Method method = CallableStatement.class.getMethod("executeUpdate"); Object result = logic.invoke(method, null); assertThat(result, is(instanceOf(int.class))); assertThat((Integer) result, is(100)); verifyParametersByName(stat); verifyListenerWithParamByName(listener, "executeUpdate", query); } @Test public void testExecuteQueryWithNoParam() throws Throwable { final String query = "{call procedure_name}"; CallableStatement stat = mock(CallableStatement.class); QueryExecutionListener listener = mock(QueryExecutionListener.class); InterceptorHolder interceptorHolder = getInterceptorHolder(listener); ResultSet mockResultSet = mock(ResultSet.class); when(stat.executeQuery()).thenReturn(mockResultSet); PreparedStatementProxyLogic logic = getProxyLogic(stat, query, interceptorHolder); Method method = CallableStatement.class.getMethod("executeQuery"); Object result = logic.invoke(method, null); assertThat(result, is(instanceOf(ResultSet.class))); assertThat((ResultSet) result, is(mockResultSet)); verifyListenerWithNoParam(listener, "executeQuery", query); } @Test public void testExecuteQueryWithParamByPosition() throws Throwable { final String query = "{call procedure_name}"; CallableStatement stat = mock(CallableStatement.class); QueryExecutionListener listener = mock(QueryExecutionListener.class); InterceptorHolder interceptorHolder = getInterceptorHolder(listener); ResultSet mockResultSet = mock(ResultSet.class); when(stat.executeQuery()).thenReturn(mockResultSet); PreparedStatementProxyLogic logic = getProxyLogic(stat, query, interceptorHolder); setParameterByPosition(logic); Method method = CallableStatement.class.getMethod("executeQuery"); Object result = logic.invoke(method, null); assertThat(result, is(instanceOf(ResultSet.class))); assertThat((ResultSet) result, is(mockResultSet)); verifyParametersByPosition(stat); verifyListenerWithParamByPosition(listener, "executeQuery", query); } @Test public void testExecuteQueryWithParamByName() throws Throwable { final String query = "{call procedure_name}"; CallableStatement stat = mock(CallableStatement.class); QueryExecutionListener listener = mock(QueryExecutionListener.class); InterceptorHolder interceptorHolder = getInterceptorHolder(listener); ResultSet mockResultSet = mock(ResultSet.class); when(stat.executeQuery()).thenReturn(mockResultSet); PreparedStatementProxyLogic logic = getProxyLogic(stat, query, interceptorHolder); setParameterByName(logic); Method method = CallableStatement.class.getMethod("executeQuery"); Object result = logic.invoke(method, null); assertThat(result, is(instanceOf(ResultSet.class))); assertThat((ResultSet) result, is(mockResultSet)); verifyParametersByName(stat); verifyListenerWithParamByName(listener, "executeQuery", query); } @Test public void testExecuteBatch() throws Throwable { final String query = "{call procedure_a}"; CallableStatement stat = mock(CallableStatement.class); QueryExecutionListener listener = mock(QueryExecutionListener.class); InterceptorHolder interceptorHolder = getInterceptorHolder(listener); PreparedStatementProxyLogic logic = getProxyLogic(stat, query, interceptorHolder); Method setString = CallableStatement.class.getMethod("setString", int.class, String.class); Method setInt = CallableStatement.class.getMethod("setInt", int.class, int.class); Method addBatch = CallableStatement.class.getMethod("addBatch"); Method executeBatch = CallableStatement.class.getMethod("executeBatch"); logic.invoke(setString, new Object[]{1, "foo"}); logic.invoke(setInt, new Object[]{2, 10}); logic.invoke(addBatch, null); logic.invoke(setString, new Object[]{1, "bar"}); logic.invoke(setInt, new Object[]{2, 20}); logic.invoke(addBatch, null); logic.invoke(setString, new Object[]{1, "baz"}); logic.invoke(setInt, new Object[]{2, 30}); logic.invoke(addBatch, null); logic.invoke(executeBatch, null); Map<String, Object> expectedArgs1 = new LinkedHashMap<String, Object>(); expectedArgs1.put("1", "foo"); expectedArgs1.put("2", 10); Map<String, Object> expectedArgs2 = new LinkedHashMap<String, Object>(); expectedArgs2.put("1", "bar"); expectedArgs2.put("2", 20); Map<String, Object> expectedArgs3 = new LinkedHashMap<String, Object>(); expectedArgs3.put("1", "baz"); expectedArgs3.put("2", 30); MockTestUtils.verifyListenerForBatch(listener, DS_NAME, query, expectedArgs1, expectedArgs2, expectedArgs3); } @Test public void testBatchWithClearBatch() throws Throwable { final String query = "{call procedure_a}"; CallableStatement stat = mock(CallableStatement.class); QueryExecutionListener listener = mock(QueryExecutionListener.class); InterceptorHolder interceptorHolder = getInterceptorHolder(listener); PreparedStatementProxyLogic logic = getProxyLogic(stat, query, interceptorHolder); Method setString = CallableStatement.class.getMethod("setString", int.class, String.class); Method setInt = CallableStatement.class.getMethod("setInt", int.class, int.class); Method addBatch = CallableStatement.class.getMethod("addBatch"); Method executeBatch = CallableStatement.class.getMethod("executeBatch"); Method clearBatch = CallableStatement.class.getMethod("clearBatch"); logic.invoke(setString, new Object[]{1, "foo"}); logic.invoke(setInt, new Object[]{2, 10}); logic.invoke(addBatch, null); logic.invoke(clearBatch, null); logic.invoke(setString, new Object[]{1, "FOO"}); logic.invoke(setInt, new Object[]{2, 20}); logic.invoke(addBatch, null); logic.invoke(executeBatch, null); verify(stat).setString(1, "foo"); verify(stat).setInt(2, 10); verify(stat).clearBatch(); verify(stat).setString(1, "FOO"); verify(stat).setInt(2, 20); verify(stat, times(2)).addBatch(); Map<String, Object> expectedArgs = new LinkedHashMap<String, Object>(); expectedArgs.put("1", "FOO"); expectedArgs.put("2", 20); MockTestUtils.verifyListenerForBatch(listener, DS_NAME, query, expectedArgs); } @Test public void testBatchWithClearParameters() throws Throwable { final String query = "{call procedure_a}"; CallableStatement stat = mock(CallableStatement.class); QueryExecutionListener listener = mock(QueryExecutionListener.class); InterceptorHolder interceptorHolder = getInterceptorHolder(listener); PreparedStatementProxyLogic logic = getProxyLogic(stat, query, interceptorHolder); Method setString = CallableStatement.class.getMethod("setString", int.class, String.class); Method setInt = CallableStatement.class.getMethod("setInt", int.class, int.class); Method addBatch = CallableStatement.class.getMethod("addBatch"); Method executeBatch = CallableStatement.class.getMethod("executeBatch"); Method clearParameters = CallableStatement.class.getMethod("clearParameters"); logic.invoke(setString, new Object[]{1, "foo"}); logic.invoke(clearParameters, null); logic.invoke(setString, new Object[]{1, "FOO"}); logic.invoke(setInt, new Object[]{2, 10}); logic.invoke(addBatch, null); logic.invoke(executeBatch, null); verify(stat).setString(1, "foo"); verify(stat).clearParameters(); verify(stat).setString(1, "FOO"); verify(stat).setInt(2, 10); verify(stat).addBatch(); Map<String, Object> expectedArgs = new LinkedHashMap<String, Object>(); expectedArgs.put("1", "FOO"); expectedArgs.put("2", 10); MockTestUtils.verifyListenerForBatch(listener, DS_NAME, query, expectedArgs); } @SuppressWarnings("unchecked") @Test public void testClearParameters() throws Throwable { final String query = "{call procedure_a}"; CallableStatement stat = mock(CallableStatement.class); QueryExecutionListener listener = mock(QueryExecutionListener.class); InterceptorHolder interceptorHolder = getInterceptorHolder(listener); PreparedStatementProxyLogic logic = getProxyLogic(stat, query, interceptorHolder); Method setString = CallableStatement.class.getMethod("setString", int.class, String.class); Method setInt = CallableStatement.class.getMethod("setInt", int.class, int.class); Method addBatch = CallableStatement.class.getMethod("addBatch"); Method executeBatch = CallableStatement.class.getMethod("executeBatch"); Method clearParameters = CallableStatement.class.getMethod("clearParameters"); logic.invoke(setString, new Object[]{1, "foo"}); logic.invoke(setInt, new Object[]{2, 10}); logic.invoke(clearParameters, new Object[]{}); logic.invoke(addBatch, new Object[]{}); logic.invoke(executeBatch, new Object[]{}); verify(stat).setString(1, "foo"); verify(stat).setInt(2, 10); verify(stat).clearParameters(); verify(stat).addBatch(); ArgumentCaptor<List> queryInfoListCaptor = ArgumentCaptor.forClass(List.class); verify(listener).afterQuery(any(ExecutionInfo.class), queryInfoListCaptor.capture()); List<QueryInfo> queryInfoList = queryInfoListCaptor.getValue(); assertThat(queryInfoList.size(), is(1)); assertThat(queryInfoList.get(0).getParametersList(), hasSize(1)); List<ParameterSetOperation> firstArgs = queryInfoList.get(0).getParametersList().get(0); assertThat("Args should be empty", firstArgs, empty()); } private InterceptorHolder getInterceptorHolder(QueryExecutionListener listener) { return new InterceptorHolder(listener, QueryTransformer.DEFAULT); } private static class Param<T> { Class<T> clazz; T value; int index; String strIndex; private Param(Class<T> clazz, T value, int index, String strIndex) { this.clazz = clazz; this.value = value; this.index = index; this.strIndex = strIndex; // null if not applicable } } private static final Param<Array> PARAM_ARRAY; private static final Param<InputStream> PARAM_ASCIISTREAM; private static final Param<BigDecimal> PARAM_BIGDECIMAL; private static final Param<InputStream> PARAM_BINARYSTREAM; private static final Param<Blob> PARAM_BLOB; private static final Param<Boolean> PARAM_BOOLEAN; private static final Param<Reader> PARAM_CHARACTERSTREAM; private static final Param<Clob> PARAM_CLOB; private static final Param<Date> PARAM_DATE; private static final Param<Double> PARAM_DOUBLE; private static final Param<Float> PARAM_FLOAT; private static final Param<Integer> PARAM_INT; private static final Param<Long> PARAM_LONG; private static final Param<Integer> PARAM_NULL; private static final Param<Object> PARAM_OBJECT; private static final Param<Ref> PARAM_REF; private static final Param<Short> PARAM_SHORT; private static final Param<String> PARAM_STRING; private static final Param<Time> PARAM_TIME; private static final Param<Timestamp> PARAM_TIMESTAMP; private static final Param<URL> PARAM_URL; static { PARAM_ARRAY = new Param<Array>(Array.class, mock(Array.class), 1, null); PARAM_ASCIISTREAM = new Param<InputStream>(InputStream.class, mock(InputStream.class), 2, "ascii"); PARAM_BIGDECIMAL = new Param<BigDecimal>(BigDecimal.class, mock(BigDecimal.class), 3, "bigdecimal"); PARAM_BINARYSTREAM = new Param<InputStream>(InputStream.class, mock(InputStream.class), 4, "binarystream"); PARAM_BLOB = new Param<Blob>(Blob.class, mock(Blob.class), 5, "blob"); PARAM_BOOLEAN = new Param<Boolean>(Boolean.class, true, 6, "boolean"); PARAM_CHARACTERSTREAM = new Param<Reader>(Reader.class, mock(Reader.class), 7, "reader"); PARAM_CLOB = new Param<Clob>(Clob.class, mock(Clob.class), 8, "clob"); PARAM_DATE = new Param<Date>(Date.class, mock(Date.class), 9, "date"); PARAM_DOUBLE = new Param<Double>(double.class, 10.0d, 10, "double"); PARAM_FLOAT = new Param<Float>(Float.class, 20f, 11, "float"); PARAM_INT = new Param<Integer>(int.class, 30, 12, "int"); PARAM_LONG = new Param<Long>(long.class, 40L, 13, "long"); PARAM_NULL = new Param<Integer>(int.class, Types.VARCHAR, 14, "null"); PARAM_OBJECT = new Param<Object>(Object.class, mock(Object.class), 15, "object"); PARAM_REF = new Param<Ref>(Ref.class, mock(Ref.class), 16, null); PARAM_SHORT = new Param<Short>(short.class, (short) 50, 17, "short"); PARAM_STRING = new Param<String>(String.class, "str", 18, "string"); PARAM_TIME = new Param<Time>(Time.class, mock(Time.class), 19, "time"); PARAM_TIMESTAMP = new Param<Timestamp>(Timestamp.class, mock(Timestamp.class), 20, "timestamp"); try { PARAM_URL = new Param<URL>(URL.class, new URL("http://foo.com"), 21, "url"); } catch (Exception e) { throw new RuntimeException("failed to initialize URL"); } } private static final List<Param> PARAMS = new ArrayList<Param>() { { add(PARAM_ARRAY); add(PARAM_ASCIISTREAM); add(PARAM_BIGDECIMAL); add(PARAM_BINARYSTREAM); add(PARAM_BLOB); add(PARAM_BOOLEAN); add(PARAM_CHARACTERSTREAM); add(PARAM_CLOB); add(PARAM_DATE); add(PARAM_DOUBLE); add(PARAM_FLOAT); add(PARAM_INT); add(PARAM_LONG); add(PARAM_NULL); add(PARAM_OBJECT); add(PARAM_REF); add(PARAM_SHORT); add(PARAM_STRING); add(PARAM_TIME); add(PARAM_TIMESTAMP); add(PARAM_URL); } }; private void setParameterByPosition(PreparedStatementProxyLogic logic) throws Throwable { Method setArray = CallableStatement.class.getMethod("setArray", int.class, Array.class); Method setAsciiStream = CallableStatement.class.getMethod("setAsciiStream", int.class, InputStream.class); Method setBigDecimal = CallableStatement.class.getMethod("setBigDecimal", int.class, BigDecimal.class); Method setBinaryStream = CallableStatement.class.getMethod("setBinaryStream", int.class, InputStream.class); Method setBlob = CallableStatement.class.getMethod("setBlob", int.class, Blob.class); Method setBoolean = CallableStatement.class.getMethod("setBoolean", int.class, boolean.class); Method setCharacterStream = CallableStatement.class.getMethod("setCharacterStream", int.class, Reader.class); Method setClob = CallableStatement.class.getMethod("setClob", int.class, Clob.class); Method setDate = CallableStatement.class.getMethod("setDate", int.class, Date.class); Method setDouble = CallableStatement.class.getMethod("setDouble", int.class, double.class); Method setFloat = CallableStatement.class.getMethod("setFloat", int.class, float.class); Method setInt = CallableStatement.class.getMethod("setInt", int.class, int.class); Method setLong = CallableStatement.class.getMethod("setLong", int.class, long.class); Method setNull = CallableStatement.class.getMethod("setNull", int.class, int.class); Method setObject = CallableStatement.class.getMethod("setObject", int.class, Object.class); Method setRef = CallableStatement.class.getMethod("setRef", int.class, Ref.class); Method setShort = CallableStatement.class.getMethod("setShort", int.class, short.class); Method setString = CallableStatement.class.getMethod("setString", int.class, String.class); Method setTime = CallableStatement.class.getMethod("setTime", int.class, Time.class); Method setTimestamp = CallableStatement.class.getMethod("setTimestamp", int.class, Timestamp.class); Method setURL = CallableStatement.class.getMethod("setURL", int.class, URL.class); logic.invoke(setArray, new Object[]{PARAM_ARRAY.index, PARAM_ARRAY.value}); logic.invoke(setAsciiStream, new Object[]{PARAM_ASCIISTREAM.index, PARAM_ASCIISTREAM.value}); logic.invoke(setBigDecimal, new Object[]{PARAM_BIGDECIMAL.index, PARAM_BIGDECIMAL.value}); logic.invoke(setBinaryStream, new Object[]{PARAM_BINARYSTREAM.index, PARAM_BINARYSTREAM.value}); logic.invoke(setBlob, new Object[]{PARAM_BLOB.index, PARAM_BLOB.value}); logic.invoke(setBoolean, new Object[]{PARAM_BOOLEAN.index, PARAM_BOOLEAN.value}); logic.invoke(setCharacterStream, new Object[]{PARAM_CHARACTERSTREAM.index, PARAM_CHARACTERSTREAM.value}); logic.invoke(setClob, new Object[]{PARAM_CLOB.index, PARAM_CLOB.value}); logic.invoke(setDate, new Object[]{PARAM_DATE.index, PARAM_DATE.value}); logic.invoke(setDouble, new Object[]{PARAM_DOUBLE.index, PARAM_DOUBLE.value}); logic.invoke(setFloat, new Object[]{PARAM_FLOAT.index, PARAM_FLOAT.value}); logic.invoke(setInt, new Object[]{PARAM_INT.index, PARAM_INT.value}); logic.invoke(setLong, new Object[]{PARAM_LONG.index, PARAM_LONG.value}); logic.invoke(setNull, new Object[]{PARAM_NULL.index, PARAM_NULL.value}); logic.invoke(setObject, new Object[]{PARAM_OBJECT.index, PARAM_OBJECT.value}); logic.invoke(setRef, new Object[]{PARAM_REF.index, PARAM_REF.value}); logic.invoke(setShort, new Object[]{PARAM_SHORT.index, PARAM_SHORT.value}); logic.invoke(setString, new Object[]{PARAM_STRING.index, PARAM_STRING.value}); logic.invoke(setTime, new Object[]{PARAM_TIME.index, PARAM_TIME.value}); logic.invoke(setTimestamp, new Object[]{PARAM_TIMESTAMP.index, PARAM_TIMESTAMP.value}); logic.invoke(setURL, new Object[]{PARAM_URL.index, PARAM_URL.value}); } private void setParameterByName(PreparedStatementProxyLogic logic) throws Throwable { Method setAsciiStream = CallableStatement.class.getMethod("setAsciiStream", String.class, InputStream.class); Method setBigDecimal = CallableStatement.class.getMethod("setBigDecimal", String.class, BigDecimal.class); Method setBinaryStream = CallableStatement.class.getMethod("setBinaryStream", String.class, InputStream.class); Method setBlob = CallableStatement.class.getMethod("setBlob", String.class, Blob.class); Method setBoolean = CallableStatement.class.getMethod("setBoolean", String.class, boolean.class); Method setCharacterStream = CallableStatement.class.getMethod("setCharacterStream", String.class, Reader.class); Method setClob = CallableStatement.class.getMethod("setClob", String.class, Clob.class); Method setDate = CallableStatement.class.getMethod("setDate", String.class, Date.class); Method setDouble = CallableStatement.class.getMethod("setDouble", String.class, double.class); Method setFloat = CallableStatement.class.getMethod("setFloat", String.class, float.class); Method setInt = CallableStatement.class.getMethod("setInt", String.class, int.class); Method setLong = CallableStatement.class.getMethod("setLong", String.class, long.class); Method setNull = CallableStatement.class.getMethod("setNull", String.class, int.class); Method setObject = CallableStatement.class.getMethod("setObject", String.class, Object.class); Method setShort = CallableStatement.class.getMethod("setShort", String.class, short.class); Method setString = CallableStatement.class.getMethod("setString", String.class, String.class); Method setTime = CallableStatement.class.getMethod("setTime", String.class, Time.class); Method setTimestamp = CallableStatement.class.getMethod("setTimestamp", String.class, Timestamp.class); Method setURL = CallableStatement.class.getMethod("setURL", String.class, URL.class); logic.invoke(setAsciiStream, new Object[]{PARAM_ASCIISTREAM.strIndex, PARAM_ASCIISTREAM.value}); logic.invoke(setBigDecimal, new Object[]{PARAM_BIGDECIMAL.strIndex, PARAM_BIGDECIMAL.value}); logic.invoke(setBinaryStream, new Object[]{PARAM_BINARYSTREAM.strIndex, PARAM_BINARYSTREAM.value}); logic.invoke(setBlob, new Object[]{PARAM_BLOB.strIndex, PARAM_BLOB.value}); logic.invoke(setBoolean, new Object[]{PARAM_BOOLEAN.strIndex, PARAM_BOOLEAN.value}); logic.invoke(setCharacterStream, new Object[]{PARAM_CHARACTERSTREAM.strIndex, PARAM_CHARACTERSTREAM.value}); logic.invoke(setClob, new Object[]{PARAM_CLOB.strIndex, PARAM_CLOB.value}); logic.invoke(setDate, new Object[]{PARAM_DATE.strIndex, PARAM_DATE.value}); logic.invoke(setDouble, new Object[]{PARAM_DOUBLE.strIndex, PARAM_DOUBLE.value}); logic.invoke(setFloat, new Object[]{PARAM_FLOAT.strIndex, PARAM_FLOAT.value}); logic.invoke(setInt, new Object[]{PARAM_INT.strIndex, PARAM_INT.value}); logic.invoke(setLong, new Object[]{PARAM_LONG.strIndex, PARAM_LONG.value}); logic.invoke(setNull, new Object[]{PARAM_NULL.strIndex, PARAM_NULL.value}); logic.invoke(setObject, new Object[]{PARAM_OBJECT.strIndex, PARAM_OBJECT.value}); logic.invoke(setShort, new Object[]{PARAM_SHORT.strIndex, PARAM_SHORT.value}); logic.invoke(setString, new Object[]{PARAM_STRING.strIndex, PARAM_STRING.value}); logic.invoke(setTime, new Object[]{PARAM_TIME.strIndex, PARAM_TIME.value}); logic.invoke(setTimestamp, new Object[]{PARAM_TIMESTAMP.strIndex, PARAM_TIMESTAMP.value}); logic.invoke(setURL, new Object[]{PARAM_URL.strIndex, PARAM_URL.value}); } private void verifyParametersByPosition(CallableStatement mockStatement) throws Exception { verify(mockStatement).setArray(PARAM_ARRAY.index, PARAM_ARRAY.value); verify(mockStatement).setAsciiStream(PARAM_ASCIISTREAM.index, PARAM_ASCIISTREAM.value); verify(mockStatement).setBigDecimal(PARAM_BIGDECIMAL.index, PARAM_BIGDECIMAL.value); verify(mockStatement).setBinaryStream(PARAM_BINARYSTREAM.index, PARAM_BINARYSTREAM.value); verify(mockStatement).setBlob(PARAM_BLOB.index, PARAM_BLOB.value); verify(mockStatement).setBoolean(PARAM_BOOLEAN.index, PARAM_BOOLEAN.value); verify(mockStatement).setCharacterStream(PARAM_CHARACTERSTREAM.index, PARAM_CHARACTERSTREAM.value); verify(mockStatement).setClob(PARAM_CLOB.index, PARAM_CLOB.value); verify(mockStatement).setDate(PARAM_DATE.index, PARAM_DATE.value); verify(mockStatement).setDouble(PARAM_DOUBLE.index, PARAM_DOUBLE.value); verify(mockStatement).setFloat(PARAM_FLOAT.index, PARAM_FLOAT.value); verify(mockStatement).setInt(PARAM_INT.index, PARAM_INT.value); verify(mockStatement).setLong(PARAM_LONG.index, PARAM_LONG.value); verify(mockStatement).setNull(PARAM_NULL.index, PARAM_NULL.value); verify(mockStatement).setObject(PARAM_OBJECT.index, PARAM_OBJECT.value); verify(mockStatement).setRef(PARAM_REF.index, PARAM_REF.value); verify(mockStatement).setShort(PARAM_SHORT.index, PARAM_SHORT.value); verify(mockStatement).setString(PARAM_STRING.index, PARAM_STRING.value); verify(mockStatement).setTime(PARAM_TIME.index, PARAM_TIME.value); verify(mockStatement).setTimestamp(PARAM_TIMESTAMP.index, PARAM_TIMESTAMP.value); verify(mockStatement).setURL(PARAM_URL.index, PARAM_URL.value); } private void verifyParametersByName(CallableStatement mockStatement) throws Exception { verify(mockStatement).setAsciiStream(PARAM_ASCIISTREAM.strIndex, PARAM_ASCIISTREAM.value); verify(mockStatement).setBigDecimal(PARAM_BIGDECIMAL.strIndex, PARAM_BIGDECIMAL.value); verify(mockStatement).setBinaryStream(PARAM_BINARYSTREAM.strIndex, PARAM_BINARYSTREAM.value); verify(mockStatement).setBlob(PARAM_BLOB.strIndex, PARAM_BLOB.value); verify(mockStatement).setBoolean(PARAM_BOOLEAN.strIndex, PARAM_BOOLEAN.value); verify(mockStatement).setCharacterStream(PARAM_CHARACTERSTREAM.strIndex, PARAM_CHARACTERSTREAM.value); verify(mockStatement).setClob(PARAM_CLOB.strIndex, PARAM_CLOB.value); verify(mockStatement).setDate(PARAM_DATE.strIndex, PARAM_DATE.value); verify(mockStatement).setDouble(PARAM_DOUBLE.strIndex, PARAM_DOUBLE.value); verify(mockStatement).setFloat(PARAM_FLOAT.strIndex, PARAM_FLOAT.value); verify(mockStatement).setInt(PARAM_INT.strIndex, PARAM_INT.value); verify(mockStatement).setLong(PARAM_LONG.strIndex, PARAM_LONG.value); verify(mockStatement).setNull(PARAM_NULL.strIndex, PARAM_NULL.value); verify(mockStatement).setObject(PARAM_OBJECT.strIndex, PARAM_OBJECT.value); verify(mockStatement).setShort(PARAM_SHORT.strIndex, PARAM_SHORT.value); verify(mockStatement).setString(PARAM_STRING.strIndex, PARAM_STRING.value); verify(mockStatement).setTime(PARAM_TIME.strIndex, PARAM_TIME.value); verify(mockStatement).setTimestamp(PARAM_TIMESTAMP.strIndex, PARAM_TIMESTAMP.value); verify(mockStatement).setURL(PARAM_URL.strIndex, PARAM_URL.value); } enum ParamStatus { NO_PARAM, BY_POSITION, BY_NAME } private void verifyListenerWithNoParam(QueryExecutionListener listener, String methodName, String query) { verifyListener(listener, methodName, query, ParamStatus.NO_PARAM); } private void verifyListenerWithParamByPosition(QueryExecutionListener listener, String methodName, String query) { verifyListener(listener, methodName, query, ParamStatus.BY_POSITION); } private void verifyListenerWithParamByName(QueryExecutionListener listener, String methodName, String query) { verifyListener(listener, methodName, query, ParamStatus.BY_NAME); } @SuppressWarnings("unchecked") private void verifyListener(QueryExecutionListener listener, String methodName, String query, ParamStatus paramStatus) { ArgumentCaptor<ExecutionInfo> executionInfoCaptor = ArgumentCaptor.forClass(ExecutionInfo.class); ArgumentCaptor<List> queryInfoListCaptor = ArgumentCaptor.forClass(List.class); verify(listener).afterQuery(executionInfoCaptor.capture(), queryInfoListCaptor.capture()); ExecutionInfo execInfo = executionInfoCaptor.getValue(); assertThat(execInfo.getMethod(), is(notNullValue())); assertThat(execInfo.getMethod().getName(), is(methodName)); assertThat(execInfo.getMethodArgs(), is(nullValue())); assertThat(execInfo.getDataSourceName(), is(DS_NAME)); assertThat(execInfo.getThrowable(), is(nullValue())); List<QueryInfo> queryInfoList = queryInfoListCaptor.getValue(); assertThat(queryInfoList.size(), is(1)); QueryInfo queryInfo = queryInfoList.get(0); assertThat(queryInfo.getQuery(), is(equalTo(query))); // TODO: clean up the comparison logic List<List<ParameterSetOperation>> queryArgsList = queryInfo.getParametersList(); assertThat("non-batch exec should have only one params.", queryArgsList, hasSize(1)); Map<String, Object> queryArgs = new HashMap<String, Object>(); for (ParameterSetOperation operation : queryArgsList.get(0)) { Object[] args = operation.getArgs(); queryArgs.put(args[0].toString(), args[1]); } if (ParamStatus.NO_PARAM != paramStatus) { if (ParamStatus.BY_POSITION == paramStatus) { assertThat(queryArgs.size(), is(PARAMS.size())); for (int i = 0; i < PARAMS.size(); i++) { Param param = PARAMS.get(i); String index = Integer.toString(param.index); // param map key is String Object value = queryArgs.get(index); assertThat(value, is(instanceOf(param.clazz))); assertThat(value, is(param.value)); } } else { // By name int totalSetParamCallForByName = 0; for (Param param : PARAMS) { String index = param.strIndex; if (index == null) { continue; // some params are only for by position } totalSetParamCallForByName++; Object value = queryArgs.get(index); assertThat(value, is(instanceOf(param.clazz))); assertThat(value, is(param.value)); } assertThat(queryArgs, aMapWithSize(totalSetParamCallForByName)); } } } private PreparedStatementProxyLogic getProxyLogic(CallableStatement cs, String query, InterceptorHolder interceptorHolder) { return new PreparedStatementProxyLogic(cs, query, interceptorHolder, DS_NAME, new JdkJdbcProxyFactory()); } @Test public void testGetTarget() throws Throwable { CallableStatement orig = mock(CallableStatement.class); PreparedStatementProxyLogic logic = getProxyLogic(orig, null, null); Method method = ProxyJdbcObject.class.getMethod("getTarget"); Object result = logic.invoke(method, null); assertThat(result, is(instanceOf(CallableStatement.class))); assertThat((CallableStatement) result, is(sameInstance(orig))); } @Test public void testUnwrap() throws Throwable { CallableStatement mock = mock(CallableStatement.class); when(mock.unwrap(String.class)).thenReturn("called"); PreparedStatementProxyLogic logic = getProxyLogic(mock, null, null); Method method = CallableStatement.class.getMethod("unwrap", Class.class); Object result = logic.invoke(method, new Object[]{String.class}); verify(mock).unwrap(String.class); assertThat(result, is(instanceOf(String.class))); assertThat((String) result, is("called")); } @Test public void testIsWrapperFor() throws Throwable { CallableStatement mock = mock(CallableStatement.class); when(mock.isWrapperFor(String.class)).thenReturn(true); PreparedStatementProxyLogic logic = getProxyLogic(mock, null, null); Method method = CallableStatement.class.getMethod("isWrapperFor", Class.class); Object result = logic.invoke(method, new Object[]{String.class}); verify(mock).isWrapperFor(String.class); assertThat(result, is(instanceOf(boolean.class))); assertThat((Boolean) result, is(true)); } @Test public void testGetConnection() throws Throwable { Connection conn = mock(Connection.class); CallableStatement stat = mock(CallableStatement.class); when(stat.getConnection()).thenReturn(conn); PreparedStatementProxyLogic logic = getProxyLogic(stat, null, null); Method method = CallableStatement.class.getMethod("getConnection"); Object result = logic.invoke(method, null); assertThat(result, is(instanceOf(Connection.class))); verify(stat).getConnection(); assertThat(Proxy.isProxyClass(result.getClass()), is(true)); InvocationHandler handler = Proxy.getInvocationHandler(result); assertThat(handler, is(instanceOf(ConnectionInvocationHandler.class))); assertThat(result, is(instanceOf(ProxyJdbcObject.class))); Object obj = ((ProxyJdbcObject) result).getTarget(); assertThat(obj, is(instanceOf(Connection.class))); Connection resultConn = (Connection) obj; assertThat(resultConn, is(sameInstance(conn))); } }