Package com.jolbox.bonecp

Source Code of com.jolbox.bonecp.TestConnectionHandle

/**
*  Copyright 2010 Wallace Wadge
*
*    Licensed under the Apache License, Version 2.0 (the "License");
*    you may not use this file except in compliance with the License.
*    You may obtain a copy of the License at
*
*        http://www.apache.org/licenses/LICENSE-2.0
*
*    Unless required by applicable law or agreed to in writing, software
*    distributed under the License is distributed on an "AS IS" BASIS,
*    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*    See the License for the specific language governing permissions and
*    limitations under the License.
*/
package com.jolbox.bonecp;


import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static org.easymock.EasyMock.anyInt;
import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.aryEq;
import static org.easymock.EasyMock.createNiceMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.expectLastCall;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.reset;
import static org.easymock.EasyMock.verify;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.fail;

import java.lang.ref.Reference;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;

import junit.framework.Assert;

import org.easymock.EasyMock;
import org.easymock.IAnswer;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;

import com.google.common.base.FinalizableReferenceQueue;
import com.google.common.collect.MapMaker;

/**
* Mock unit testing for Connection Handle class.
* @author wwadge
*
*/
public class TestConnectionHandle {
  /** Test class handle. */
  private ConnectionHandle testClass;
  /** Mock handle. */
  private ConnectionHandle mockConnection = createNiceMock(ConnectionHandle.class);
  /** Mock handle. */
  private IStatementCache mockPreparedStatementCache = createNiceMock(IStatementCache.class);
  /** Mock handle. */
  private IStatementCache mockCallableStatementCache = createNiceMock(IStatementCache.class);
  /** Mock handle. */
  private BoneCP mockPool = createNiceMock(BoneCP.class);
  /** Mock handle. */
  private Logger mockLogger;
  /** Mock handle. */
  private StatementCache testStatementCache = new StatementCache(100, false, new Statistics(this.mockPool));
  /** Config clone. */
  private BoneCPConfig config;

  /** Reset everything.
   * @throws SecurityException
   * @throws NoSuchFieldException
   * @throws IllegalArgumentException
   * @throws IllegalAccessException
   */
  @Before
  public void before() throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException{
    reset(this.mockConnection, this.mockPreparedStatementCache, this.mockPool, this.mockCallableStatementCache);

    this.config = CommonTestUtils.getConfigClone();
    this.mockPool.connectionStrategy = new DefaultConnectionStrategy(this.mockPool);
    expect(this.mockPool.getConfig()).andReturn(this.config).anyTimes();

    expect(this.mockConnection.getPool()).andReturn(this.mockPool).anyTimes();
    expect(this.mockConnection.isLogStatementsEnabled()).andReturn(true).anyTimes();
    replay(this.mockConnection, this.mockPool);

    this.config.setCloseOpenStatements(true);
    this.config.setTransactionRecoveryEnabled(false);
    this.config.setStatementsCacheSize(1);
    this.config.setStatisticsEnabled(true);
    this.config.setDefaultAutoCommit(true);
    this.config.setDefaultCatalog("foo");

    this.testClass = ConnectionHandle.createTestConnectionHandle(this.mockConnection, this.mockPreparedStatementCache, this.mockCallableStatementCache, this.mockPool);

    this.mockPool.closeConnectionWatch=true;
    this.mockLogger = TestUtils.mockLogger(testClass.getClass());

    this.testClass.logicallyClosed.set(false);

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

    field = this.testClass.getClass().getDeclaredField("statistics");
    field.setAccessible(true);
    field.set(this.testClass, new Statistics(this.mockPool));

    reset(this.mockConnection, this.mockPreparedStatementCache, this.mockPool, this.mockCallableStatementCache);
  }


  /** For test. */
  static int count=1;


  /** Test bounce of inner connection.
   * @throws IllegalArgumentException
   * @throws SecurityException
   * @throws IllegalAccessException
   * @throws InvocationTargetException
   */
  @Test
  public void testStandardMethods() throws IllegalArgumentException, SecurityException,  IllegalAccessException, InvocationTargetException{
    Set<String> skipTests = new HashSet<String>();
    skipTests.add("close");
    skipTests.add("getConnection");
    skipTests.add("markPossiblyBroken");
    skipTests.add("trackStatement");
    skipTests.add("checkClosed");
    skipTests.add("isClosed");
    skipTests.add("internalClose");
    skipTests.add("prepareCall");
    skipTests.add("prepareStatement");
    skipTests.add("setClientInfo");
    skipTests.add("getConnectionLastUsed");
    skipTests.add("setConnectionLastUsed");
    skipTests.add("getConnectionLastReset")
    skipTests.add("setConnectionLastReset");
    skipTests.add("isPossiblyBroken")
    skipTests.add("getOriginatingPartition");
    skipTests.add("setOriginatingPartition");
    skipTests.add("renewConnection");
    skipTests.add("clearStatementCaches");
    skipTests.add("obtainInternalConnection");
    skipTests.add("refreshConnection");
    skipTests.add("recreateConnectionHandle");
    skipTests.add("fillConnectionFields");
    skipTests.add("createConnectionHandle");
    if (CommonTestUtils.jvmMajorVersion < 7){
      skipTests.add("getNetworkTimeout");
      skipTests.add("setNetworkTimeout");
      skipTests.add("getSchema");
      skipTests.add("setSchema");
      skipTests.add("abort");

    }

    skipTests.add("sendInitSQL");
    skipTests.add("$VRi"); // this only comes into play when code coverage is started. Eclemma bug?
    expect(this.mockPool.getConfig()).andReturn(this.config).anyTimes();
    replay(this.mockPool);
    testClass.closeOpenStatements = true;
    CommonTestUtils.testStatementBounceMethod(this.mockConnection, this.testClass, skipTests, this.mockConnection);
  }
 

  /** Test marking of possibly broken status.
   * @throws SecurityException
   * @throws NoSuchFieldException
   * @throws IllegalArgumentException
   * @throws IllegalAccessException
   */
  @Test
  public void testMarkPossiblyBroken() throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException{
    Field field = this.testClass.getClass().getDeclaredField("possiblyBroken");
    field.setAccessible(true);
    field.set(this.testClass, false);
    this.testClass.markPossiblyBroken(new SQLException());
    Assert.assertTrue(field.getBoolean(this.testClass));

    // Test that a db fatal error will lead to the pool being instructed to terminate all connections (+ log)
    expect(this.mockPool.getDbIsDown()).andReturn(new AtomicBoolean()).anyTimes();
    this.mockPool.connectionStrategy.terminateAllConnections();
    this.mockLogger.error((String)anyObject(), anyObject());
    replay(this.mockPool);
    this.testClass.markPossiblyBroken(new SQLException("test", "08001"));
    verify(this.mockPool);


  }

  /** Test. */
  boolean interrupted = false;
  /** Test. */
  boolean started = false;
  /** 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
   * @throws InterruptedException
   */
  @Test
  public void testClose() throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, SQLException, InterruptedException{

    this.testClass.doubleCloseCheck = true;
    Connection mockInternalConnection = EasyMock.createNiceMock(Connection.class);
    this.testClass.setInternalConnection(mockInternalConnection);

    this.testClass.renewConnection();
    this.mockPool.releaseConnection((Connection)anyObject());
    expectLastCall().once().andThrow(new SQLException()).once();
    expect(this.mockPool.getFinalizableRefs()).andReturn(new HashMap<Connection, Reference<ConnectionHandle>>()).anyTimes();
    expect(this.mockPool.getConfig()).andReturn(this.config).anyTimes();
    expect(mockInternalConnection.isClosed()).andReturn(false).anyTimes();
    replay(this.mockPool, mockInternalConnection);

    // create a thread so that we can check that thread.interrupt was called during connection close.
    //    final Thread thisThread = Thread.currentThread();
    Thread testThread = new Thread(new Runnable() {

      public void run() {
        try {
          TestConnectionHandle.this.started = true;
          while(true){
            Thread.sleep(20);
          }
        } catch (Exception e) {
          TestConnectionHandle.this.interrupted = true;

        }
      }
    });
    testThread.start();
    while (!this.started){
      Thread.sleep(20);
    }
    this.testClass.setThreadWatch(testThread);
    this.testClass.close();
    testThread.join();
    assertTrue(this.interrupted); // thread should have been interrupted

    // logically mark the connection as closed
    Assert.assertTrue(this.testClass.logicallyClosed.get());
    assertTrue(this.testClass.isClosed());




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

  }

  @Test
  public void testCloseWithRollback() throws SQLException{
    Connection mockConnection = EasyMock.createNiceMock(Connection.class);
    this.testClass.logicallyClosed.set(false);
    this.testClass.resetConnectionOnClose = true;
    this.testClass.connectionTrackingDisabled = true;
    this.testClass.setInternalConnection(mockConnection);
    mockConnection.rollback();
    expect(mockConnection.getAutoCommit()).andReturn(false);
    mockConnection.setAutoCommit(true);
    replay(mockConnection);
    try{
      this.testClass.close();
    } catch(NullPointerException e){
      // we don't care about the rest of the method
    }
    verify(mockConnection);
  }

 
  @Test
  public void testCloseWithExceptionsOnRecreate() throws SQLException{
    Connection mockConnection = EasyMock.createNiceMock(Connection.class);
    this.testClass.logicallyClosed.set(false);
    this.testClass.resetConnectionOnClose = false;
    this.testClass.connectionTrackingDisabled = true;
    this.testClass.setInternalConnection(mockConnection);
    expect(mockConnection.getAutoCommit()).andReturn(false);
    expect(this.mockPool.getConfig()).andReturn(new BoneCPConfig()).anyTimes();
    this.mockPool.releaseConnection((Connection)anyObject());
    expectLastCall().andAnswer(new IAnswer<Object>() {

      public Object answer() throws Throwable {
        testClass.logicallyClosed.set(false);

        throw new SQLException();
      }
    });

    replay(mockConnection, mockPool);
    try{
      this.testClass.close();
    } catch(SQLException e){
      // expected
    }
    verify(mockConnection);
  }
  @Test
  public void testCloseWithRollbackThrowingException() throws SQLException{
    //coverage test
    Connection mockConnection = EasyMock.createNiceMock(Connection.class);
    this.testClass.logicallyClosed.set(false);
    this.testClass.resetConnectionOnClose = true;
    this.testClass.connectionTrackingDisabled = true;
    this.testClass.setInternalConnection(mockConnection);
    mockConnection.rollback();
    expect(mockConnection.getAutoCommit()).andThrow(new SQLException("FOO", "123"));
    replay(mockConnection);
    try{
      this.testClass.close();
      fail("exception was expected");
    } catch(SQLException e){
    }
    verify(mockConnection);
  }
  @Test
  public void testCloseWithRollbackNoResetAutoCommit() throws SQLException{
    // same test but let's set autocommit is set to true (the usual default)
    Connection mockConnection = EasyMock.createNiceMock(Connection.class);
    this.testClass.logicallyClosed.set(false);
    this.testClass.resetConnectionOnClose = true;
    this.testClass.connectionTrackingDisabled = true;
    this.testClass.setInternalConnection(mockConnection);

    mockConnection.rollback();
    expect(mockConnection.getAutoCommit()).andReturn(true);
    replay(mockConnection);
    try{
      this.testClass.close();
    } catch(NullPointerException e){
      // we don't care about the rest of the method
    }

    verify(mockConnection);
  }


  @Test
  public void testCloseWithOpenStatementsMakeSureTheyAreClosed() throws SQLException{
    Connection mockConnection = EasyMock.createNiceMock(Connection.class);
    this.testClass.logicallyClosed.set(false);
    this.testClass.closeOpenStatements = true;
    this.testClass.detectUnclosedStatements = true;

    this.testClass.setInternalConnection(mockConnection);

    this.testClass.trackedStatement = new MapMaker().makeMap();
    Statement mockStatement = EasyMock.createNiceMock(Statement.class);
    this.testClass.trackedStatement.put(mockStatement, "foo");
    mockStatement.close();

    Logger oldLogger = ConnectionHandle.logger;
    try{
      ConnectionHandle.logger = mockLogger;
      mockLogger.warn((String)anyObject());
      replay(mockStatement, mockConnection, mockLogger);
      try{
        this.testClass.close();
      } catch(NullPointerException e){
        // we don't care about the rest of the method
      }
    } finally {
      ConnectionHandle.logger = oldLogger;
    }

    verify(mockConnection, mockStatement, mockLogger);
  }
 
  @Test
  public void testCloseWithOpenStatementsMakeSureTheyAreClosedButNotLogger() throws SQLException{
    // Test mostly for coverage.
    Connection mockConnection = EasyMock.createNiceMock(Connection.class);
    this.testClass.logicallyClosed.set(false);
    this.testClass.closeOpenStatements = true;
    this.testClass.detectUnclosedStatements = false;

    this.testClass.setInternalConnection(mockConnection);

    this.testClass.trackedStatement = new MapMaker().makeMap();
    Statement mockStatement = EasyMock.createNiceMock(Statement.class);
    this.testClass.trackedStatement.put(mockStatement, "foo");
    mockStatement.close();

      mockLogger.warn((String)anyObject());
      replay(mockStatement, mockConnection);
      try{
        this.testClass.close();
      } catch(NullPointerException e){
        // we don't care about the rest of the method
      }

    verify(mockConnection, mockStatement);
  }


  /** Tests sendInitialSQL method.
   * @throws SecurityException
   * @throws NoSuchFieldException
   * @throws IllegalArgumentException
   * @throws IllegalAccessException
   * @throws SQLException
   */
  @Test
  public void testSendInitialSQL() throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException, SQLException{

    BoneCPConfig mockConfig = createNiceMock(BoneCPConfig.class);
    expect(this.mockPool.getConfig()).andReturn(mockConfig).anyTimes();

    expect(mockConfig.getInitSQL()).andReturn("test").anyTimes();
    this.testClass.setInternalConnection(this.mockConnection);

    Statement mockStatement = createNiceMock(Statement.class);
    expect(this.mockConnection.createStatement()).andReturn(mockStatement).times(2).andReturn(null).once();
    expect(mockStatement.execute("test")).andReturn(true).once().andThrow(new SQLException()).once();
    mockStatement.close();
    expectLastCall().times(2);
    replay(mockConfig, this.mockPool, this.mockConnection, mockStatement);
    this.testClass.sendInitSQL();

    try{
      this.testClass.sendInitSQL(); // second time statement should fail and be closed
      fail("An exception should be thrown");
    } catch (SQLException e){
      // do nothing
    }


    try{
      this.testClass.sendInitSQL(); // third time, just for null check. Should never happen in real life unless
      // driver fails
      fail("Should throw NPE");
    } catch (NullPointerException e){
      // do nothing
    }

    verify(this.mockConnection,  mockStatement);

    ConnectionHandle.testSupport = true;
    reset(this.mockConnection, mockStatement);
    expect(this.mockConnection.createStatement()).andReturn(mockStatement).once();
    expect(mockStatement.execute("test")).andReturn(true).once();
    replay(this.mockConnection, mockStatement);
    this.testClass.sendInitSQL();
    ConnectionHandle.testSupport = false;


    verify(mockConfig, this.mockPool, this.mockConnection,  mockStatement);



  }

  @Test
  public void testCoverage(){
    this.testClass.url = "foo";
    assertEquals("foo", this.testClass.getUrl());
  }

  /**
   * @throws SecurityException
   * @throws NoSuchFieldException
   * @throws IllegalArgumentException
   * @throws IllegalAccessException
   * @throws SQLException
   */
  @Test
  public void testDoubleClose() throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException, SQLException{
    this.testClass.doubleCloseCheck = true;
    this.testClass.logicallyClosed.set(true);


    this.testClass.doubleCloseException = "fakeexception";
    this.mockLogger.error((String)anyObject(), anyObject());
    expectLastCall().once();

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

    this.testClass.close();
  }

  @Test
  public void testDoubleCloseNoLogging() throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException, SQLException{
    // coverage
    this.testClass.doubleCloseCheck = true;
    this.testClass.logicallyClosed.set(true);


    this.testClass.doubleCloseException = null;

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

    this.testClass.close();
  }

  /** 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);

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

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

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

    Field f = this.testClass.getClass().getDeclaredField("finalizableRefs");
    f.setAccessible(true);
    f.set(this.testClass, refs);

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

    verify(mockStatement, this.mockConnection, mockStatementHandles);
  }
 
  @SuppressWarnings("unchecked")
  @Test
  public void testInternalCloseCoverage() throws SQLException {
    this.testClass.connectionTrackingDisabled = false;
    this.testClass.finalizableRefs = new MapMaker().makeMap();
    this.testClass.finalizableRefs.put(this.testClass.connection, createNiceMock(Reference.class));
    this.testClass.internalClose();
    assertTrue(this.testClass.finalizableRefs.isEmpty());
   
    this.testClass.connectionTrackingDisabled = false;
    this.testClass.finalizableRefs = null// should never happen
    this.testClass.internalClose();
   
    // should not fail if connection was somehow destroy.
    this.testClass.connection = null;
    this.testClass.internalClose();

   
  }


  /** Test for check closed routine.
   * @throws SecurityException
   * @throws NoSuchFieldException
   * @throws IllegalArgumentException
   * @throws IllegalAccessException
   * @throws InvocationTargetException
   * @throws NoSuchMethodException
   */
  @Test
  public void testCheckClosed() throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, NoSuchMethodException{

    this.testClass.renewConnection();

    // call the method (should not throw an exception)
    Method method = this.testClass.getClass().getDeclaredMethod("checkClosed");
    method.setAccessible(true);
    method.invoke(this.testClass);

    // logically mark the connection as closed
    this.testClass.logicallyClosed.set(true);

    try{
      method.invoke(this.testClass);
      fail("Should have thrown an exception");
    } catch (Throwable t){
      // do nothing.
    }
  }

  @Test
  public void testToString(){
    expect(mockPool.getConfig()).andReturn(new BoneCPConfig()).anyTimes();
    replay(mockPool);
    assertNotNull(this.testClass.toString());
  }


  /** Test renewal of connection.
   * @throws SecurityException
   * @throws NoSuchFieldException
   * @throws IllegalArgumentException
   * @throws IllegalAccessException
   */
  @Test
  public void testRenewConnection() throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException{
    Field field = this.testClass.getClass().getDeclaredField("doubleCloseCheck");
    field.setAccessible(true);
    field.set(this.testClass, true);

    this.testClass.logicallyClosed.set(true);


    this.testClass.renewConnection();
    assertFalsethis.testClass.logicallyClosed.get());


  }
  /** Tests various getter/setters.
   * @throws IllegalArgumentException
   * @throws IllegalAccessException
   * @throws SecurityException
   * @throws NoSuchFieldException
   */
  @SuppressWarnings("deprecation")
  @Test
  public void testSettersGetters() throws IllegalArgumentException, IllegalAccessException, SecurityException, NoSuchFieldException {
    ConnectionPartition mockPartition = createNiceMock(ConnectionPartition.class);
    this.testClass.setOriginatingPartition(mockPartition);
    assertEquals(mockPartition, this.testClass.getOriginatingPartition());

    this.testClass.setConnectionLastResetInMs(123);
    assertEquals(this.testClass.getConnectionLastResetInMs(), 123);
    assertEquals(this.testClass.getConnectionLastReset(), 123);

    this.testClass.setConnectionLastUsedInMs(456);
    assertEquals(this.testClass.getConnectionLastUsedInMs(), 456);
    assertEquals(this.testClass.getConnectionLastUsed(), 456);

    Field field = this.testClass.getClass().getDeclaredField("possiblyBroken");
    field.setAccessible(true);
    field.setBoolean(this.testClass, true);
    assertTrue(this.testClass.isPossiblyBroken());

    field = this.testClass.getClass().getDeclaredField("connectionCreationTimeInMs");
    field.setAccessible(true);
    field.setLong(this.testClass, 1234L);
    assertEquals(1234L, this.testClass.getConnectionCreationTime());

    Object debugHandle = new Object();
    this.testClass.setDebugHandle(debugHandle);
    assertEquals(debugHandle, this.testClass.getDebugHandle());

    this.testClass.setInternalConnection(this.mockConnection);
    assertEquals(this.mockConnection, this.testClass.getInternalConnection());
    assertEquals(this.mockConnection, this.testClass.getRawConnection());

    this.testClass.logicallyClosed.set(true);

    assertTrue(this.testClass.isClosed());

    this.testClass.setLogStatementsEnabled(true);
    assertTrue(this.testClass.isLogStatementsEnabled());

    assertEquals(this.testClass.getPool(), this.mockPool);
    ArrayList<ReplayLog> testLog = new ArrayList<ReplayLog>();
    this.testClass.setReplayLog(testLog);
    assertEquals(this.testClass.getReplayLog(), testLog);
    this.testClass.setInReplayMode(true);
    assertTrue(this.testClass.isInReplayMode());
    this.testClass.setInReplayMode(false);

    this.testClass.threadUsingConnection = Thread.currentThread();
    assertEquals(Thread.currentThread(), this.testClass.getThreadUsingConnection());

    this.testClass.setThreadWatch(Thread.currentThread());
    assertEquals(Thread.currentThread(), this.testClass.getThreadWatch());

  }

  /**
   *  Simple test.
   */
  @Test
  public void testIsConnectionHandleAlive(){
    // just make sure this is bounced off to the right place
    reset(this.mockPool);
    expect(this.mockPool.isConnectionHandleAlive(this.testClass)).andReturn(true).once();
    replay(this.mockPool);
    this.testClass.isConnectionAlive();
    verify(this.mockPool);
  }

  /** Tests isExpired method.
   * @throws SecurityException
   * @throws NoSuchFieldException
   * @throws IllegalArgumentException
   * @throws IllegalAccessException
   */
  @Test
  public void testIsExpired() throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException{
    this.testClass.maxConnectionAgeInMs = 1234L;
    this.testClass.connectionCreationTimeInMs = System.currentTimeMillis();
    assertTrue(this.testClass.isExpired(System.currentTimeMillis() + 9999L));


    assertFalse(this.testClass.isExpired(System.currentTimeMillis()));
    this.testClass.maxConnectionAgeInMs = 0L;
    assertFalse(this.testClass.isExpired(System.currentTimeMillis()));


    this.testClass.maxConnectionAgeInMs = 0L;
    assertFalse(this.testClass.isExpired());
    this.testClass.maxConnectionAgeInMs = 1L;

    this.testClass.connectionCreationTimeInMs = System.currentTimeMillis() + 9999L;
    assertFalse(this.testClass.isExpired());
    this.testClass.connectionCreationTimeInMs = 0;
    assertTrue(this.testClass.isExpired());

  }

  @Test
  public void testMaybeCaptureStackTrace(){
    assertEquals("", this.testClass.maybeCaptureStackTrace());
    this.testClass.detectUnclosedStatements = true;
    assertNotSame("", this.testClass.maybeCaptureStackTrace());
    this.testClass.detectUnclosedStatements = false;
  }

  @Test
  public void testRefreshConnection() throws SQLException{
    Connection mockInternalConnection =  createNiceMock(Connection.class);
    this.testClass.connection = mockInternalConnection;
    mockInternalConnection.close();
    expectLastCall().once();
    replay(mockInternalConnection);
    this.testClass.refreshConnection();

    assertNotSame(mockInternalConnection, this.testClass.getInternalConnection());
    verify(mockInternalConnection);

    this.testClass.connection = mockInternalConnection;
    reset(this.mockPool, mockInternalConnection);
    mockInternalConnection.close();
    expectLastCall().once();

    expect(this.mockPool.obtainRawInternalConnection()).andThrow(new SQLException("foo", "1234")).once();
    replay(this.mockPool, mockInternalConnection);
    try{
      this.testClass.refreshConnection();
      fail("Should throw exception");
    } catch(SQLException e){
      // do nothing
    }
  }

  @Test
  public void testUntrackStatement(){
    StatementHandle mockStatement = createNiceMock(StatementHandle.class);
    this.testClass.trackedStatement.put(mockStatement, "");
    this.testClass.closeOpenStatements = false;
    assertTrue(this.testClass.trackedStatement.containsKey(mockStatement)); // should be a NOP
    this.testClass.closeOpenStatements = true;
    this.testClass.untrackStatement(mockStatement);
    assertFalse(this.testClass.trackedStatement.containsKey(mockStatement));


  }

  /** Prepare statement tests.
   * @throws SecurityException
   * @throws IllegalArgumentException
   * @throws NoSuchFieldException
   * @throws IllegalAccessException
   * @throws NoSuchMethodException
   * @throws InvocationTargetException
   */
  @Test
  public void testPrepareStatement() throws SecurityException, IllegalArgumentException,  NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException{
    expect(this.mockPool.captureStackTrace((String)anyObject())).andReturn("").anyTimes();
    expect(this.mockPool.getConfig()).andReturn(this.config).anyTimes();
    replay(this.mockPool);
    this.config.setStatementsCacheSize(1);
    prepareStatementTest(String.class);
    prepareStatementTest(String.class, int.class);
    prepareStatementTest(String.class, int[].class);
    prepareStatementTest(String.class, String[].class);
    prepareStatementTest(String.class, int.class, int.class);
    prepareStatementTest(String.class, int.class, int.class, int.class);
  }

  /** Callable statement tests.
   * @throws SecurityException
   * @throws IllegalArgumentException
   * @throws NoSuchFieldException
   * @throws IllegalAccessException
   * @throws NoSuchMethodException
   * @throws InvocationTargetException
   */
  @Test
  public void testCallableStatement() throws SecurityException, IllegalArgumentException,  NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException{
    expect(this.mockPool.captureStackTrace((String)anyObject())).andReturn("").anyTimes();
    expect(this.mockPool.getConfig()).andReturn(this.config).anyTimes();
    this.config.setStatisticsEnabled(true);

    replay(this.mockPool);

    callableStatementTest(String.class);
    callableStatementTest(String.class, int.class, int.class);
    callableStatementTest(String.class, int.class, int.class, int.class);
  }


  /** Test routine.
   * @param args
   * @throws SecurityException
   * @throws NoSuchFieldException
   * @throws IllegalArgumentException
   * @throws IllegalAccessException
   * @throws NoSuchMethodException
   * @throws InvocationTargetException
   */
  @SuppressWarnings("rawtypes")
  private void prepareStatementTestClass... args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InvocationTargetException{
    Object[] params = new Object[args.length];
    for (int i=0; i < args.length; i++){
      params[i] = CommonTestUtils.instanceMap.get(args[i]);
    }

    Method prepStatementMethod = this.testClass.getClass().getMethod("prepareStatement", args);

    PreparedStatementHandle mockStatement = createNiceMock(PreparedStatementHandle.class);
    mockStatement.setOpenStackTrace((String)anyObject());
    expectLastCall().anyTimes();

    this.testClass.renewConnection(); // logically open the connection

    // fetching a statement that is found in cache. Statement should be returned and marked as being (logically) open
    doStatementMock(this.mockPreparedStatementCache, mockStatement, params, args);

    //    mockStatement.setLogicallyOpen();
    //    expectLastCall();
    replay(mockStatement, this.mockPreparedStatementCache);
    prepStatementMethod.invoke(this.testClass, params);
    verify(mockStatement, this.mockPreparedStatementCache);

    reset(mockStatement, this.mockPreparedStatementCache);


    // test for a cache miss
    doStatementMock(this.mockPreparedStatementCache, null, params, args);
    // we should be creating the preparedStatement because it's not in the cache
    expect(prepStatementMethod.invoke(this.mockConnection, params)).andReturn(mockStatement);

    replay(mockStatement, this.mockPreparedStatementCache, this.mockConnection);
    prepStatementMethod.invoke(this.testClass, params);
    verify(mockStatement, this.mockPreparedStatementCache, this.mockConnection);


    // test for cache miss + sql exception
    reset(mockStatement, this.mockPreparedStatementCache, this.mockConnection);

    Method mockConnectionPrepareStatementMethod = this.mockConnection.getClass().getMethod("prepareStatement", args);

    //    expect(this.mockPreparedStatementCache.get((String)anyObject())).andReturn(null).once();
    doStatementMock(this.mockPreparedStatementCache, null, params, args);

    // we should be trying to create the preparedStatement because it's not in the cache
    expect(mockConnectionPrepareStatementMethod.invoke(this.mockConnection, params)).andThrow(new SQLException("test", "Z"));

    replay(mockStatement, this.mockPreparedStatementCache, this.mockConnection);
    try{
      prepStatementMethod.invoke(this.testClass, params);
      fail("Should have thrown an exception");
    } catch (Throwable t) {
      // do nothing
    }

    verify(mockStatement, this.mockPreparedStatementCache, this.mockConnection);



    // test for no cache defined
    reset(mockStatement, this.mockPreparedStatementCache, this.mockConnection);
    boolean oldState = this.testClass.statementCachingEnabled;

    this.testClass.statementCachingEnabled = false;

    // we should be creating the preparedStatement because it's not in the cache
    expect(mockConnectionPrepareStatementMethod.invoke(this.mockConnection, params)).andReturn(mockStatement);

    replay(mockStatement, this.mockPreparedStatementCache, this.mockConnection);
    prepStatementMethod.invoke(this.testClass, params);
    verify(mockStatement, this.mockPreparedStatementCache, this.mockConnection);
    // restore sanity
    this.testClass.statementCachingEnabled = oldState;

    reset(mockStatement, this.mockPreparedStatementCache, this.mockConnection);

  }

  /** Mock setup.
   * @param cache
   * @param returnVal
   * @param params
   * @param args
   */
  private void doStatementMock(IStatementCache cache, StatementHandle returnVal, Object[] params, Class<?>... args) {
    expect(cache.get((String)anyObject())).andReturn(returnVal).anyTimes();
    //    expect(cache.calculateCacheKey((String)anyObject())).andReturn(testStatementCache.calculateCacheKey((String)params[0])).anyTimes();

    if (args.length == 2) {
      if (params[1].getClass().equals(Integer.class)){

        expect(cache.calculateCacheKey((String)anyObject(), anyInt())).andReturn(this.testStatementCache.calculateCacheKey((String)params[0], (Integer)params[1])).anyTimes();
        expect(cache.get((String)anyObject(), anyInt())).andReturn(returnVal).anyTimes();
      }     
      expect(cache.calculateCacheKey((String)anyObject(), aryEq(new int[]{0,1}))).andReturn(this.testStatementCache.calculateCacheKey((String)params[0], new int[]{0,1})).anyTimes();
      expect(cache.get((String)anyObject(), aryEq(new int[]{0,1}))).andReturn(returnVal).anyTimes();

      expect(cache.calculateCacheKey((String)anyObject(), (String[])anyObject())).andReturn(this.testStatementCache.calculateCacheKey((String)params[0], new String[]{"test", "bar"})).anyTimes();
      expect(cache.get((String)anyObject(), (String[])anyObject())).andReturn(returnVal).anyTimes();
    }
    if (args.length == 3) {
      expect(cache.calculateCacheKey((String)anyObject(), anyInt(), anyInt())).andReturn(this.testStatementCache.calculateCacheKey((String)params[0], (Integer)params[1], (Integer)params[2])).anyTimes();
      expect(cache.get((String)anyObject(), anyInt(), anyInt())).andReturn(returnVal).anyTimes();
    }
    if (args.length == 4) {
      expect(cache.calculateCacheKey((String)anyObject(), anyInt(), anyInt(), anyInt())).andReturn(this.testStatementCache.calculateCacheKey((String)params[0], (Integer)params[1], (Integer)params[2], (Integer)params[3])).anyTimes();
      expect(cache.get((String)anyObject(), anyInt(), anyInt(), anyInt())).andReturn(returnVal).anyTimes();
    }

  }

  /** Test routine for callable statements.
   * @param args
   * @throws SecurityException
   * @throws NoSuchFieldException
   * @throws IllegalArgumentException
   * @throws IllegalAccessException
   * @throws NoSuchMethodException
   * @throws InvocationTargetException
   */
  @SuppressWarnings("all")
  private void callableStatementTest(Class... args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InvocationTargetException{
    Object[] params = new Object[args.length];
    for (int i=0; i < args.length; i++){
      params[i] = CommonTestUtils.instanceMap.get(args[i]);
    }

    Method prepCallMethod = this.testClass.getClass().getMethod("prepareCall", args);

    CallableStatementHandle mockStatement = createNiceMock(CallableStatementHandle.class);
    ConcurrentLinkedQueue<Statement> mockStatementHandles = createNiceMock(ConcurrentLinkedQueue.class);


    this.testClass.renewConnection(); // logically open the connection

    // fetching a statement that is found in cache. Statement should be returned and marked as being (logically) open
    doStatementMock(this.mockCallableStatementCache, mockStatement, params, args);

    //    expect(this.mockCallableStatementCache.get((String)anyObject())).andReturn(mockStatement).anyTimes();

    //    ((StatementHandle)mockStatement).setLogicallyOpen();
    //    expectLastCall();
    replay(mockStatement, this.mockCallableStatementCache);
    prepCallMethod.invoke(this.testClass, params);
    verify(mockStatement, this.mockCallableStatementCache);

    reset(mockStatement, this.mockCallableStatementCache, mockStatementHandles);


    // test for a cache miss
    doStatementMock(this.mockCallableStatementCache, null, params, args);

    // we should be creating the preparedStatement because it's not in the cache
    expect(prepCallMethod.invoke(this.mockConnection, params)).andReturn(mockStatement);
    // we should be tracking this statement
    expect(mockStatementHandles.add(mockStatement)).andReturn(true);

    replay(mockStatement, this.mockCallableStatementCache, this.mockConnection, mockStatementHandles);
    prepCallMethod.invoke(this.testClass, params);
    verify(mockStatement, this.mockCallableStatementCache, this.mockConnection);


    // test for cache miss + sql exception
    reset(mockStatement, this.mockCallableStatementCache, this.mockConnection);

    Method mockConnectionPrepareCallMethod = this.mockConnection.getClass().getMethod("prepareCall", args);

    //    expect(this.mockCallableStatementCache.get((String)anyObject())).andReturn(null).once();
    doStatementMock(this.mockCallableStatementCache, null, params, args);

    // we should be creating the preparedStatement because it's not in the cache
    expect(mockConnectionPrepareCallMethod.invoke(this.mockConnection, params)).andThrow(new SQLException("test", "Z"));

    replay(mockStatement, this.mockCallableStatementCache, this.mockConnection);
    try{
      prepCallMethod.invoke(this.testClass, params);
      fail("Should have thrown an exception");
    } catch (Throwable t) {
      // do nothing
    }

    verify(mockStatement, this.mockCallableStatementCache, this.mockConnection);



    // test for no cache defined
    reset(mockStatement, this.mockCallableStatementCache, this.mockConnection);
    boolean oldState = this.testClass.statementCachingEnabled;

    this.testClass.statementCachingEnabled = false;


    // we should be creating the preparedStatement because it's not in the cache
    expect(mockConnectionPrepareCallMethod.invoke(this.mockConnection, params)).andReturn(mockStatement);

    replay(mockStatement, this.mockCallableStatementCache, this.mockConnection);
    prepCallMethod.invoke(this.testClass, params);
    verify(mockStatement, this.mockCallableStatementCache, this.mockConnection);
    // restore sanity
    this.testClass.statementCachingEnabled = oldState;

    reset(mockStatement, this.mockCallableStatementCache, this.mockConnection);

  }

  /**
   */
  @Test
  public void testSetClientInfo() {
    Properties prop = new Properties();
    try {
      this.mockConnection.setClientInfo(prop);
      replay(this.mockConnection);
      this.testClass.setClientInfo(prop);
      verify(this.mockConnection);

      reset(this.mockConnection);

      String name = "name";
      String value = "val";
      this.mockConnection.setClientInfo(name, value);
      replay(this.mockConnection);
      this.testClass.setClientInfo(name, value);
      verify(this.mockConnection);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }

  }

  // 
  //  /** Tests that a thrown exception will call the onAcquireFail hook.
  //   * @throws SQLException
  //   */
  //  @Test
  //  public void testConstructorFail() throws SQLException{
  //    BoneCPConfig mockConfig = createNiceMock(BoneCPConfig.class);
  //    ConnectionHook mockConnectionHook = createNiceMock(CoverageHook.class);
  //    expect(this.mockPool.getConfig()).andReturn(mockConfig).anyTimes();
  ////    expect(mockConfig.getReleaseHelperThreads()).andReturn(1).once();
  //    expect(mockConfig.getConnectionHook()).andReturn(mockConnectionHook).once();
  //    expect(mockConnectionHook.onAcquireFail((Throwable)anyObject(), (AcquireFailConfig)anyObject())).andReturn(false).once();
  //    replay(this.mockPool, mockConfig, mockConnectionHook);
  //    try{
  //      new ConnectionH("", "", "", this.mockPool);
  //      fail("Should throw an exception");
  //    } catch (Throwable t){
  //      // do nothing.
  //    }
  //    verify(this.mockPool, mockConfig, this.mockPool);
  //  }
  //

  /**
   * Test for clear statement caches.
   */
  @Test
  public void testClearStatementCaches(){

    this.testClass.statementCachingEnabled = true;
    this.mockPreparedStatementCache.clear();
    expectLastCall().once();
    this.mockCallableStatementCache.clear();
    expectLastCall().once();

    replay(this.mockPreparedStatementCache, this.mockCallableStatementCache);
    this.testClass.clearStatementCaches(true);
    verify(this.mockPreparedStatementCache, this.mockCallableStatementCache);
    reset(this.mockPreparedStatementCache, this.mockCallableStatementCache);


    this.mockPool.closeConnectionWatch = true;
    this.mockPreparedStatementCache.checkForProperClosure();
    expectLastCall().once();
    this.mockCallableStatementCache.checkForProperClosure();
    expectLastCall().once();

    replay(this.mockPreparedStatementCache, this.mockCallableStatementCache);
    this.testClass.clearStatementCaches(false);
    verify(this.mockPreparedStatementCache, this.mockCallableStatementCache);

  }

  /**
   *
   */
  @Test
  public void testStackTraceAndTxResolve(){
    this.testClass.setAutoCommitStackTrace("foo");
    this.testClass.getAutoCommitStackTrace();
    assertEquals("foo", this.testClass.getAutoCommitStackTrace());
    this.testClass.txResolved = true;
    assertTrue(this.testClass.isTxResolved());
  }

  /**
   * @throws SQLException
   *
   */
  @Test
  public void testAutoCommitSetToFalse() throws SQLException{
    this.testClass.detectUnresolvedTransactions = true;
    expect(this.mockPool.captureStackTrace((String)anyObject())).andReturn("foo").once();
    replay(this.mockPool);
    this.testClass.setAutoCommit(false);
    assertNotNull(this.testClass.getAutoCommitStackTrace());
  }

}
TOP

Related Classes of com.jolbox.bonecp.TestConnectionHandle

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.