package com.vladmihalcea.flexypool.strategy; import com.vladmihalcea.flexypool.adaptor.PoolAdapter; import com.vladmihalcea.flexypool.adaptor.PoolAdapterFactory; import com.vladmihalcea.flexypool.config.Configuration; import com.vladmihalcea.flexypool.connection.ConnectionRequestContext; import com.vladmihalcea.flexypool.exception.AcquireTimeoutException; import com.vladmihalcea.flexypool.metric.Histogram; import com.vladmihalcea.flexypool.metric.Metrics; import com.vladmihalcea.flexypool.metric.MetricsFactory; import com.vladmihalcea.flexypool.common.ConfigurationProperties; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; import java.util.concurrent.atomic.AtomicInteger; import static org.junit.Assert.assertSame; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.same; import static org.mockito.Mockito.*; /** * IncrementPoolOnTimeoutConnectionAcquiringStrategyTest - IncrementPoolOnTimeoutConnectionAcquiringStrategy Test * * @author Vlad Mihalcea */ public class IncrementPoolOnTimeoutConnectionAcquiringStrategyTest { @Mock private DataSource dataSource; @Mock private PoolAdapter<DataSource> poolAdapter; @Mock private Connection connection; @Mock private Metrics metrics; @Mock private Histogram maxPoolSizeHistogram; @Mock private Histogram overflowPoolSizeHistogram; private Configuration<DataSource> configuration; private ConnectionRequestContext connectionRequestContext; @Before public void before() { MockitoAnnotations.initMocks(this); configuration = new Configuration.Builder<DataSource>( getClass().getName(), dataSource, new PoolAdapterFactory<DataSource>() { @Override public PoolAdapter<DataSource> newInstance(ConfigurationProperties<DataSource, Metrics, PoolAdapter<DataSource>> configurationProperties) { return poolAdapter; } } ) .setMetricsFactory(new MetricsFactory() { @Override public Metrics newInstance(ConfigurationProperties configurationProperties) { return metrics; } }) .build(); when(metrics.histogram(IncrementPoolOnTimeoutConnectionAcquiringStrategy.MAX_POOL_SIZE_HISTOGRAM)).thenReturn(maxPoolSizeHistogram); when(metrics.histogram(IncrementPoolOnTimeoutConnectionAcquiringStrategy.OVERFLOW_POOL_SIZE_HISTOGRAM)).thenReturn(overflowPoolSizeHistogram); connectionRequestContext = new ConnectionRequestContext.Builder().build(); when(poolAdapter.getTargetDataSource()).thenReturn(dataSource); } @Test public void testConnectionAcquiredInOneAttempt() throws SQLException { when(poolAdapter.getConnection(same(connectionRequestContext))).thenReturn(connection); when(poolAdapter.getMaxPoolSize()).thenReturn(1); IncrementPoolOnTimeoutConnectionAcquiringStrategy incrementPoolOnTimeoutConnectionAcquiringStrategy = new IncrementPoolOnTimeoutConnectionAcquiringStrategy.Factory<DataSource>(5).newInstance(configuration); assertSame(connection, incrementPoolOnTimeoutConnectionAcquiringStrategy.getConnection(connectionRequestContext)); verify(poolAdapter, never()).setMaxPoolSize(anyInt()); verify(maxPoolSizeHistogram, times(1)).update(1); verify(overflowPoolSizeHistogram, never()).update(anyLong()); } @Test public void testConnectionAcquiredInTwoAttempts() throws SQLException { when(poolAdapter.getConnection(same(connectionRequestContext))) .thenThrow(new AcquireTimeoutException(new Exception())) .thenReturn(connection); when(poolAdapter.getMaxPoolSize()).thenReturn(2); IncrementPoolOnTimeoutConnectionAcquiringStrategy incrementPoolOnTimeoutConnectionAcquiringStrategy = new IncrementPoolOnTimeoutConnectionAcquiringStrategy.Factory<DataSource>(5).newInstance(configuration); assertSame(connection, incrementPoolOnTimeoutConnectionAcquiringStrategy.getConnection(connectionRequestContext)); verify(poolAdapter, times(1)).setMaxPoolSize(3); verify(maxPoolSizeHistogram, times(1)).update(2); verify(maxPoolSizeHistogram, times(1)).update(3); verify(overflowPoolSizeHistogram, times(1)).update(1); } @Test public void testConnectionNotAcquiredAfterAllAttempts() throws SQLException { Exception rootException = new Exception(); when(poolAdapter.getConnection(same(connectionRequestContext))) .thenThrow(new AcquireTimeoutException(rootException)); final AtomicInteger maxPoolSize = new AtomicInteger(2); when(poolAdapter.getMaxPoolSize()).thenAnswer(new Answer<Integer>() { @Override public Integer answer(InvocationOnMock invocationOnMock) throws Throwable { return maxPoolSize.get(); } }); doAnswer(new Answer() { @Override public Object answer(InvocationOnMock invocationOnMock) throws Throwable { Integer nextPoolSize = (Integer) invocationOnMock.getArguments()[0]; maxPoolSize.set(nextPoolSize); return nextPoolSize; } }).when(poolAdapter).setMaxPoolSize(anyInt()); IncrementPoolOnTimeoutConnectionAcquiringStrategy incrementPoolOnTimeoutConnectionAcquiringStrategy = new IncrementPoolOnTimeoutConnectionAcquiringStrategy.Factory<DataSource>(5).newInstance(configuration); try { incrementPoolOnTimeoutConnectionAcquiringStrategy.getConnection(connectionRequestContext); } catch (SQLException e) { assertSame(rootException, e.getCause()); } verify(poolAdapter, times(1)).setMaxPoolSize(3); verify(poolAdapter, times(1)).setMaxPoolSize(4); verify(poolAdapter, times(1)).setMaxPoolSize(5); verify(maxPoolSizeHistogram, times(1)).update(2); verify(maxPoolSizeHistogram, times(1)).update(3); verify(maxPoolSizeHistogram, times(1)).update(4); verify(maxPoolSizeHistogram, times(1)).update(5); verify(overflowPoolSizeHistogram, times(1)).update(1); verify(overflowPoolSizeHistogram, times(1)).update(2); verify(overflowPoolSizeHistogram, times(1)).update(3); } @Test public void testConnectionAcquiredInOneAttemptWithTimeoutThreshold() throws SQLException { when(poolAdapter.getConnection(same(connectionRequestContext))).thenAnswer(new Answer<Object>() { @Override public Object answer(InvocationOnMock invocationOnMock) throws Throwable { Thread.sleep(150); return connection; } }); when(poolAdapter.getMaxPoolSize()).thenReturn(1); IncrementPoolOnTimeoutConnectionAcquiringStrategy incrementPoolOnTimeoutConnectionAcquiringStrategy = new IncrementPoolOnTimeoutConnectionAcquiringStrategy.Factory<DataSource>(5, 100).newInstance(configuration); assertSame(connection, incrementPoolOnTimeoutConnectionAcquiringStrategy.getConnection(connectionRequestContext)); verify(poolAdapter, times(1)).setMaxPoolSize(2); verify(maxPoolSizeHistogram, times(1)).update(1); verify(maxPoolSizeHistogram, times(1)).update(2); verify(overflowPoolSizeHistogram, times(1)).update(1); } @Test public void testConnectionAcquiredInOneAttemptWithTimeoutThresholdMaxSizeReached() throws SQLException { when(poolAdapter.getConnection(same(connectionRequestContext))).thenAnswer(new Answer<Object>() { @Override public Object answer(InvocationOnMock invocationOnMock) throws Throwable { Thread.sleep(150); return connection; } }); when(poolAdapter.getMaxPoolSize()).thenReturn(5); IncrementPoolOnTimeoutConnectionAcquiringStrategy incrementPoolOnTimeoutConnectionAcquiringStrategy = new IncrementPoolOnTimeoutConnectionAcquiringStrategy.Factory<DataSource>(5, 100).newInstance(configuration); assertSame(connection, incrementPoolOnTimeoutConnectionAcquiringStrategy.getConnection(connectionRequestContext)); verify(poolAdapter, never()).setMaxPoolSize(anyInt()); verify(maxPoolSizeHistogram, times(1)).update(5); verify(overflowPoolSizeHistogram, never()).update(anyLong()); } @Test public void testConnectionAcquiredInOneAttemptWithTimeoutThresholdMaxSizeReachedConcurrently() throws SQLException { when(poolAdapter.getConnection(same(connectionRequestContext))).thenAnswer(new Answer<Object>() { @Override public Object answer(InvocationOnMock invocationOnMock) throws Throwable { Thread.sleep(150); return connection; } }); when(poolAdapter.getMaxPoolSize()) .thenReturn(3, 4, 4, 5); IncrementPoolOnTimeoutConnectionAcquiringStrategy incrementPoolOnTimeoutConnectionAcquiringStrategy = new IncrementPoolOnTimeoutConnectionAcquiringStrategy.Factory<DataSource>(5, 100).newInstance(configuration); assertSame(connection, incrementPoolOnTimeoutConnectionAcquiringStrategy.getConnection(connectionRequestContext)); verify(poolAdapter, never()).setMaxPoolSize(anyInt()); verify(maxPoolSizeHistogram, times(1)).update(3); verify(overflowPoolSizeHistogram, never()).update(anyLong()); } }