JDBCBase { protected final <T> T executeQuery(final String sql, final StatementWithReturnBlock<T> queryBlock) throws Exception { checkState(initialized); setupConnection(); checkNotNull(connection); boolean committed = false; try { T returnValue = withStatement(connection, sql, queryBlock); connection.commit(); committed = true; return returnValue; } finally { if (!committed) { connection.rollback(); cleanupConnection(); } } } protected  JDBCBase(String url, String username, @Nullable String password); synchronized final void initialize(); synchronized final void teardown();  }
@Test public void shouldRollbackCommitAndCloseConnectionIfExceptionIsThrownInExecuteQuery() throws Exception { when(mockConnection.prepareStatement(anyString())).thenReturn(mockPreparedStatement); final JDBCBase.StatementWithReturnBlock<?> mockStatementWithReturnBlock = mock(JDBCBase.StatementWithReturnBlock.class); doThrow(IllegalArgumentException.class).when(mockStatementWithReturnBlock).use(mockPreparedStatement); initializeJDBCTestSubclass(); assertThatExceptionIsThrown(new Callable<Void>() { @Override public Void call() throws Exception { jdbcTestSubclass.executeQuery("NO SQL", mockStatementWithReturnBlock); return null; } }, IllegalArgumentException.class); InOrder inOrder = inOrder(mockPreparedStatement, mockConnection); inOrder.verify(mockPreparedStatement).close(); inOrder.verify(mockConnection).rollback(); inOrder.verify(mockConnection).close(); }
@Test public void shouldCreateSecondConnectionAfterFirstThrowsExceptionInsideExecuteQuery() throws Exception { PreparedStatement mockReplacedPreparedStatement = mock(PreparedStatement.class); when(mockConnection.prepareStatement(anyString())).thenReturn(mockPreparedStatement); when(mockReplacedConnection.prepareStatement(anyString())).thenReturn(mockReplacedPreparedStatement); final JDBCBase.StatementWithReturnBlock<?> mockStatementWithReturnBlock = mock(JDBCBase.StatementWithReturnBlock.class); final List<PreparedStatement> statementsUsed = Lists.newArrayList(); doAnswer(new Answer() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { statementsUsed.add((PreparedStatement) invocation.getArguments()[0]); if (statementsUsed.size() == 1) { throw new IllegalArgumentException("first invocation"); } return null; } }).when(mockStatementWithReturnBlock).use(any(PreparedStatement.class)); initializeJDBCTestSubclass(); assertThatExceptionIsThrown(new Callable<Void>() { @Override public Void call() throws Exception { jdbcTestSubclass.executeQuery("SOME SQL", mockStatementWithReturnBlock); return null; } }, IllegalArgumentException.class); InOrder inOrder = inOrder(mockPreparedStatement, mockConnection); inOrder.verify(mockPreparedStatement).close(); inOrder.verify(mockConnection).rollback(); inOrder.verify(mockConnection).close(); jdbcTestSubclass.executeQuery("ANOTHER SQL QUERY", mockStatementWithReturnBlock); assertThat(statementsUsed, hasSize(2)); assertThat(statementsUsed, contains(mockPreparedStatement, mockReplacedPreparedStatement)); }
@Test public void shouldCommitIfExecuteQuerySucceeds() throws Exception { when(mockConnection.prepareStatement(anyString())).thenReturn(mockPreparedStatement); final JDBCBase.StatementWithReturnBlock<?> mockStatementWithReturnBlock = mock(JDBCBase.StatementWithReturnBlock.class); initializeJDBCTestSubclass(); jdbcTestSubclass.executeQuery("SOME SQL", mockStatementWithReturnBlock); InOrder inOrder = inOrder(mockPreparedStatement, mockConnection); inOrder.verify(mockConnection).commit(); inOrder.verify(mockPreparedStatement).close(); inOrder.verify(mockConnection).commit(); inOrder.verify(mockConnection, times(0)).close(); }