/**
   * Closing a connection handle should release that connection back in the pool and mark it as
   * closed.
   *
   * @throws SecurityException
   * @throws NoSuchFieldException
   * @throws IllegalArgumentException
   * @throws IllegalAccessException
   * @throws InvocationTargetException
   * @throws NoSuchMethodException
   * @throws SQLException
   */
  @Test
  public void testClose()
      throws SecurityException, NoSuchFieldException, IllegalArgumentException,
          IllegalAccessException, InvocationTargetException, NoSuchMethodException, SQLException {

    Field field = testClass.getClass().getDeclaredField("doubleCloseCheck");
    field.setAccessible(true);
    field.set(testClass, true);

    testClass.renewConnection();
    mockPool.releaseConnection((Connection) anyObject());
    expectLastCall().once().andThrow(new SQLException()).once();
    replay(mockPool);

    testClass.close();

    // logically mark the connection as closed
    field = testClass.getClass().getDeclaredField("logicallyClosed");

    field.setAccessible(true);
    Assert.assertTrue(field.getBoolean(testClass));
    assertTrue(testClass.isClosed());

    testClass.renewConnection();
    try {
      testClass.close(); // 2nd time should throw an exception
      fail("Should have thrown an exception");
    } catch (Throwable t) {
      // do nothing.
    }

    verify(mockPool);
  }
  /**
   * Closing a connection handle should release that connection back in the pool and mark it as
   * closed.
   *
   * @throws SecurityException
   * @throws NoSuchFieldException
   * @throws IllegalArgumentException
   * @throws IllegalAccessException
   * @throws InvocationTargetException
   * @throws NoSuchMethodException
   * @throws SQLException
   */
  @SuppressWarnings("unchecked")
  @Test
  public void testInternalClose()
      throws SecurityException, NoSuchFieldException, IllegalArgumentException,
          IllegalAccessException, InvocationTargetException, NoSuchMethodException, SQLException {
    ConcurrentLinkedQueue<Statement> mockStatementHandles =
        createNiceMock(ConcurrentLinkedQueue.class);
    StatementHandle mockStatement = createNiceMock(StatementHandle.class);

    mockConnection.close();
    expectLastCall().once().andThrow(new SQLException()).once();

    Map<Connection, Reference<ConnectionHandle>> refs =
        new HashMap<Connection, Reference<ConnectionHandle>>();
    expect(mockPool.getFinalizableRefs()).andReturn(refs).anyTimes();
    FinalizableReferenceQueue finalizableRefQueue = new FinalizableReferenceQueue();

    expect(mockPool.getFinalizableRefQueue()).andReturn(finalizableRefQueue).anyTimes();
    expect(mockConnection.getPool()).andReturn(mockPool).anyTimes();

    replay(mockStatement, mockConnection, mockStatementHandles, mockPool);
    testClass.internalClose();
    try {
      testClass.internalClose(); // 2nd time should throw exception
      fail("Should have thrown an exception");
    } catch (Throwable t) {
      // do nothing.
    }

    verify(mockStatement, mockConnection, mockStatementHandles);
  }
  /**
   * Prepared statement tests.
   *
   * @throws SQLException
   * @throws SecurityException
   * @throws NoSuchFieldException
   * @throws IllegalArgumentException
   * @throws IllegalAccessException
   */
  @Test
  public void testPreparedStatement()
      throws SQLException, SecurityException, NoSuchFieldException, IllegalArgumentException,
          IllegalAccessException {
    BoneCP dsb = null;
    CommonTestUtils.logTestInfo("Tests that prepared statements are obtained from cache when set.");
    config.setMinConnectionsPerPartition(10);
    config.setMaxConnectionsPerPartition(20);
    config.setAcquireIncrement(5);
    config.setPartitionCount(1);
    config.setStatementsCacheSize(1);
    config.setLogStatementsEnabled(true);
    config.setStatementReleaseHelperThreads(0);
    dsb = new BoneCP(config);

    ConnectionHandle con = (ConnectionHandle) dsb.getConnection();
    Field preparedStatement = con.getClass().getDeclaredField("preparedStatementCache");
    preparedStatement.setAccessible(true);
    // switch to our mock
    preparedStatement.set(con, mockCache);
    expect(mockCache.get(isA(String.class))).andReturn(null);
    //		mockCache.put(isA(String.class), isA(PreparedStatement.class));

    replay(mockCache);
    Statement statement = con.prepareStatement(CommonTestUtils.TEST_QUERY);
    statement.close();
    verify(mockCache);

    reset(mockCache);
    expect(mockCache.get(isA(String.class))).andReturn(null);
    replay(mockCache);

    con.prepareStatement(CommonTestUtils.TEST_QUERY);
    statement.close();
    verify(mockCache);
    dsb.shutdown();
    statement.close();
    con.close();
    CommonTestUtils.logPass();
  }
  /**
   * @throws SecurityException
   * @throws NoSuchFieldException
   * @throws IllegalArgumentException
   * @throws IllegalAccessException
   * @throws SQLException
   */
  @Test
  public void testDoubleClose()
      throws SecurityException, NoSuchFieldException, IllegalArgumentException,
          IllegalAccessException, SQLException {
    Field field = testClass.getClass().getDeclaredField("doubleCloseCheck");
    field.setAccessible(true);
    field.set(testClass, true);

    field = testClass.getClass().getDeclaredField("logicallyClosed");
    field.setAccessible(true);
    field.set(testClass, true);

    field = testClass.getClass().getDeclaredField("doubleCloseException");
    field.setAccessible(true);
    field.set(testClass, "fakeexception");
    mockLogger.error((String) anyObject(), anyObject());
    expectLastCall().once();

    mockPool.releaseConnection((Connection) anyObject());
    expectLastCall().once().andThrow(new SQLException()).once();
    replay(mockLogger, mockPool);

    testClass.close();
  }