From abc8483bdf6febb3c10ea2bd20083ab389da9e3d Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Fri, 12 Aug 2011 22:13:21 +0000
Subject: [PATCH] Fix OPENDJ-177: Make connection pools Closeable

---
 opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/ConnectionFactoryTestCase.java |  139 +++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 131 insertions(+), 8 deletions(-)

diff --git a/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/ConnectionFactoryTestCase.java b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/ConnectionFactoryTestCase.java
index 0ba30b8..3ab0141 100644
--- a/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/ConnectionFactoryTestCase.java
+++ b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/ConnectionFactoryTestCase.java
@@ -33,11 +33,14 @@
 
 import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertTrue;
+import static org.mockito.Matchers.*;
+import static org.mockito.Mockito.*;
 
 import java.net.InetSocketAddress;
 import java.util.Arrays;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.logging.Level;
 
 import javax.net.ssl.SSLContext;
@@ -48,11 +51,14 @@
 import org.forgerock.opendj.ldap.responses.SearchResultEntry;
 import org.forgerock.opendj.ldap.schema.Schema;
 import org.forgerock.opendj.ldap.schema.SchemaBuilder;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
+import com.forgerock.opendj.util.CompletedFutureResult;
 import com.forgerock.opendj.util.StaticUtils;
 
 
@@ -205,7 +211,7 @@
         "online");
 
     // Connection pools.
-    factories[7][0] = Connections.newConnectionPool(onlineServer, 10);
+    factories[7][0] = Connections.newFixedConnectionPool(onlineServer, 10);
 
     // Round robin.
     factories[8][0] = Connections
@@ -220,9 +226,10 @@
         .newLoadBalancer(new RoundRobinLoadBalancingAlgorithm(Arrays.asList(
             offlineServer1, offlineServer2, onlineServer)));
     factories[13][0] = Connections
-        .newLoadBalancer(new RoundRobinLoadBalancingAlgorithm(Arrays.asList(
-            Connections.newConnectionPool(offlineServer1, 10),
-            Connections.newConnectionPool(onlineServer, 10))));
+        .newLoadBalancer(new RoundRobinLoadBalancingAlgorithm(Arrays
+            .<ConnectionFactory> asList(
+                Connections.newFixedConnectionPool(offlineServer1, 10),
+                Connections.newFixedConnectionPool(onlineServer, 10))));
 
     // Fail-over.
     factories[14][0] = Connections
@@ -237,11 +244,12 @@
         .newLoadBalancer(new FailoverLoadBalancingAlgorithm(Arrays.asList(
             offlineServer1, offlineServer2, onlineServer)));
     factories[19][0] = Connections
-        .newLoadBalancer(new FailoverLoadBalancingAlgorithm(Arrays.asList(
-            Connections.newConnectionPool(offlineServer1, 10),
-            Connections.newConnectionPool(onlineServer, 10))));
+        .newLoadBalancer(new FailoverLoadBalancingAlgorithm(Arrays
+            .<ConnectionFactory> asList(
+                Connections.newFixedConnectionPool(offlineServer1, 10),
+                Connections.newFixedConnectionPool(onlineServer, 10))));
 
-    factories[20][0] = Connections.newConnectionPool(onlineServer, 10);
+    factories[20][0] = Connections.newFixedConnectionPool(onlineServer, 10);
 
     return factories;
   }
@@ -367,4 +375,119 @@
       connection.close();
     }
   }
+
+
+
+  /**
+   * Tests connection pool closure.
+   *
+   * @throws Exception If an unexpected exception occurred.
+   */
+  @SuppressWarnings("unchecked")
+  @Test
+  public void testConnectionPoolClose() throws Exception
+  {
+    // We'll use a pool of 4 connections.
+    final int SIZE = 4;
+
+    // Count number of real connections which are open.
+    final AtomicInteger realConnectionCount = new AtomicInteger();
+    final boolean[] realConnectionIsClosed = new boolean[SIZE];
+    Arrays.fill(realConnectionIsClosed, true);
+
+    // Mock underlying connection factory which always succeeds.
+    final ConnectionFactory mockFactory = mock(ConnectionFactory.class);
+    when(mockFactory.getAsynchronousConnection(any(ResultHandler.class)))
+        .thenAnswer(new Answer<FutureResult<AsynchronousConnection>>()
+        {
+
+          public FutureResult<AsynchronousConnection> answer(
+              InvocationOnMock invocation) throws Throwable
+          {
+            // Update state.
+            final int connectionID = realConnectionCount.getAndIncrement();
+            realConnectionIsClosed[connectionID] = false;
+
+            // Mock connection decrements counter on close.
+            AsynchronousConnection mockConnection = mock(AsynchronousConnection.class);
+            doAnswer(new Answer<Void>()
+            {
+              public Void answer(InvocationOnMock invocation) throws Throwable
+              {
+                realConnectionCount.decrementAndGet();
+                realConnectionIsClosed[connectionID] = true;
+                return null;
+              }
+            }).when(mockConnection).close();
+            when(mockConnection.isValid()).thenReturn(true);
+            when(mockConnection.toString()).thenReturn("Mock connection " + connectionID);
+
+            // Excecute handler and return future.
+            ResultHandler<? super AsynchronousConnection> handler =
+              (ResultHandler<? super AsynchronousConnection>) invocation.getArguments()[0];
+            if (handler != null)
+            {
+              handler.handleResult(mockConnection);
+            }
+            return new CompletedFutureResult<AsynchronousConnection>(
+                mockConnection);
+          }
+        });
+
+    ConnectionPool pool = Connections.newFixedConnectionPool(mockFactory, SIZE);
+    Connection[] pooledConnections = new Connection[SIZE];
+    for (int i = 0; i < SIZE; i++)
+    {
+      pooledConnections[i] = pool.getConnection();
+    }
+
+    // Pool is fully utilized.
+    assertThat(realConnectionCount.get()).isEqualTo(SIZE);
+    assertThat(pooledConnections[0].isClosed()).isFalse();
+    assertThat(pooledConnections[1].isClosed()).isFalse();
+    assertThat(pooledConnections[2].isClosed()).isFalse();
+    assertThat(pooledConnections[3].isClosed()).isFalse();
+    assertThat(realConnectionIsClosed[0]).isFalse();
+    assertThat(realConnectionIsClosed[1]).isFalse();
+    assertThat(realConnectionIsClosed[2]).isFalse();
+    assertThat(realConnectionIsClosed[3]).isFalse();
+
+    // Release two connections.
+    pooledConnections[0].close();
+    pooledConnections[1].close();
+    assertThat(realConnectionCount.get()).isEqualTo(4);
+    assertThat(pooledConnections[0].isClosed()).isTrue();
+    assertThat(pooledConnections[1].isClosed()).isTrue();
+    assertThat(pooledConnections[2].isClosed()).isFalse();
+    assertThat(pooledConnections[3].isClosed()).isFalse();
+    assertThat(realConnectionIsClosed[0]).isFalse();
+    assertThat(realConnectionIsClosed[1]).isFalse();
+    assertThat(realConnectionIsClosed[2]).isFalse();
+    assertThat(realConnectionIsClosed[3]).isFalse();
+
+    // Close the pool closing the two connections immediately.
+    pool.close();
+    assertThat(realConnectionCount.get()).isEqualTo(2);
+    assertThat(pooledConnections[0].isClosed()).isTrue();
+    assertThat(pooledConnections[1].isClosed()).isTrue();
+    assertThat(pooledConnections[2].isClosed()).isFalse();
+    assertThat(pooledConnections[3].isClosed()).isFalse();
+    assertThat(realConnectionIsClosed[0]).isTrue();
+    assertThat(realConnectionIsClosed[1]).isTrue();
+    assertThat(realConnectionIsClosed[2]).isFalse();
+    assertThat(realConnectionIsClosed[3]).isFalse();
+
+    // Release two remaining connections and check that they get closed.
+    pooledConnections[2].close();
+    pooledConnections[3].close();
+    assertThat(realConnectionCount.get()).isEqualTo(0);
+    assertThat(pooledConnections[0].isClosed()).isTrue();
+    assertThat(pooledConnections[1].isClosed()).isTrue();
+    assertThat(pooledConnections[2].isClosed()).isTrue();
+    assertThat(pooledConnections[3].isClosed()).isTrue();
+    assertThat(realConnectionIsClosed[0]).isTrue();
+    assertThat(realConnectionIsClosed[1]).isTrue();
+    assertThat(realConnectionIsClosed[2]).isTrue();
+    assertThat(realConnectionIsClosed[3]).isTrue();
+  }
 }

--
Gitblit v1.10.0