You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2011/05/04 21:02:56 UTC
svn commit: r1099559 [1/2] - in
/httpcomponents/httpasyncclient/trunk/httpasyncclient/src:
main/java/org/apache/http/impl/nio/pool/
test/java/org/apache/http/impl/nio/concurrent/
test/java/org/apache/http/impl/nio/pool/
Author: olegk
Date: Wed May 4 19:02:55 2011
New Revision: 1099559
URL: http://svn.apache.org/viewvc?rev=1099559&view=rev
Log:
Fixed multiple bugs in non-blocking connection management code; near 100% test coverage for session pooling classes
Added:
httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/concurrent/
httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/concurrent/BasicFutureCallback.java (with props)
httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/concurrent/TestBasicFuture.java (with props)
httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/pool/
httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/pool/BasicPoolEntryCallback.java (with props)
httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/pool/TestPoolEntry.java (with props)
httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/pool/TestRouteSpecificPool.java (with props)
httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/pool/TestSessionPool.java (with props)
Modified:
httpcomponents/httpasyncclient/trunk/httpasyncclient/src/main/java/org/apache/http/impl/nio/pool/LeaseRequest.java
httpcomponents/httpasyncclient/trunk/httpasyncclient/src/main/java/org/apache/http/impl/nio/pool/PoolEntry.java
httpcomponents/httpasyncclient/trunk/httpasyncclient/src/main/java/org/apache/http/impl/nio/pool/RouteSpecificPool.java
httpcomponents/httpasyncclient/trunk/httpasyncclient/src/main/java/org/apache/http/impl/nio/pool/SessionPool.java
Modified: httpcomponents/httpasyncclient/trunk/httpasyncclient/src/main/java/org/apache/http/impl/nio/pool/LeaseRequest.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpasyncclient/trunk/httpasyncclient/src/main/java/org/apache/http/impl/nio/pool/LeaseRequest.java?rev=1099559&r1=1099558&r2=1099559&view=diff
==============================================================================
--- httpcomponents/httpasyncclient/trunk/httpasyncclient/src/main/java/org/apache/http/impl/nio/pool/LeaseRequest.java (original)
+++ httpcomponents/httpasyncclient/trunk/httpasyncclient/src/main/java/org/apache/http/impl/nio/pool/LeaseRequest.java Wed May 4 19:02:55 2011
@@ -69,7 +69,7 @@ class LeaseRequest<T, E extends PoolEntr
buffer.append("][");
buffer.append(this.state);
buffer.append("]");
- return super.toString();
+ return buffer.toString();
}
}
Modified: httpcomponents/httpasyncclient/trunk/httpasyncclient/src/main/java/org/apache/http/impl/nio/pool/PoolEntry.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpasyncclient/trunk/httpasyncclient/src/main/java/org/apache/http/impl/nio/pool/PoolEntry.java?rev=1099559&r1=1099558&r2=1099559&view=diff
==============================================================================
--- httpcomponents/httpasyncclient/trunk/httpasyncclient/src/main/java/org/apache/http/impl/nio/pool/PoolEntry.java (original)
+++ httpcomponents/httpasyncclient/trunk/httpasyncclient/src/main/java/org/apache/http/impl/nio/pool/PoolEntry.java Wed May 4 19:02:55 2011
@@ -66,6 +66,7 @@ public abstract class PoolEntry<T> {
} else {
this.validUnit = Long.MAX_VALUE;
}
+ this.expiry = this.validUnit;
}
protected T getRoute() {
Modified: httpcomponents/httpasyncclient/trunk/httpasyncclient/src/main/java/org/apache/http/impl/nio/pool/RouteSpecificPool.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpasyncclient/trunk/httpasyncclient/src/main/java/org/apache/http/impl/nio/pool/RouteSpecificPool.java?rev=1099559&r1=1099558&r2=1099559&view=diff
==============================================================================
--- httpcomponents/httpasyncclient/trunk/httpasyncclient/src/main/java/org/apache/http/impl/nio/pool/RouteSpecificPool.java (original)
+++ httpcomponents/httpasyncclient/trunk/httpasyncclient/src/main/java/org/apache/http/impl/nio/pool/RouteSpecificPool.java Wed May 4 19:02:55 2011
@@ -29,8 +29,8 @@ package org.apache.http.impl.nio.pool;
import java.net.SocketTimeoutException;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.LinkedList;
-import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
@@ -72,10 +72,21 @@ class RouteSpecificPool<T, E extends Poo
public E getFreeEntry(final Object state) {
if (!this.availableSessions.isEmpty()) {
- ListIterator<E> it = this.availableSessions.listIterator(this.availableSessions.size());
- while (it.hasPrevious()) {
- E entry = it.previous();
- if (entry.getState() == null || entry.getState().equals(state)) {
+ if (state != null) {
+ Iterator<E> it = this.availableSessions.iterator();
+ while (it.hasNext()) {
+ E entry = it.next();
+ if (state.equals(entry.getState())) {
+ it.remove();
+ this.leasedSessions.add(entry);
+ return entry;
+ }
+ }
+ }
+ Iterator<E> it = this.availableSessions.iterator();
+ while (it.hasNext()) {
+ E entry = it.next();
+ if (entry.getState() == null) {
it.remove();
this.leasedSessions.add(entry);
return entry;
@@ -85,17 +96,16 @@ class RouteSpecificPool<T, E extends Poo
return null;
}
- public E deleteLastUsed() {
- return this.availableSessions.poll();
- }
-
public boolean remove(final E entry) {
if (entry == null) {
throw new IllegalArgumentException("Pool entry may not be null");
}
- boolean foundLeased = this.leasedSessions.remove(entry);
- boolean foundFree = this.availableSessions.remove(entry);
- return foundLeased || foundFree;
+ if (!this.availableSessions.remove(entry)) {
+ if (!this.leasedSessions.remove(entry)) {
+ return false;
+ }
+ }
+ return true;
}
public void freeEntry(final E entry, boolean reusable) {
@@ -177,7 +187,7 @@ class RouteSpecificPool<T, E extends Poo
buffer.append("][pending: ");
buffer.append(this.pendingSessions.size());
buffer.append("]");
- return super.toString();
+ return buffer.toString();
}
}
Modified: httpcomponents/httpasyncclient/trunk/httpasyncclient/src/main/java/org/apache/http/impl/nio/pool/SessionPool.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpasyncclient/trunk/httpasyncclient/src/main/java/org/apache/http/impl/nio/pool/SessionPool.java?rev=1099559&r1=1099558&r2=1099559&view=diff
==============================================================================
--- httpcomponents/httpasyncclient/trunk/httpasyncclient/src/main/java/org/apache/http/impl/nio/pool/SessionPool.java (original)
+++ httpcomponents/httpasyncclient/trunk/httpasyncclient/src/main/java/org/apache/http/impl/nio/pool/SessionPool.java Wed May 4 19:02:55 2011
@@ -78,6 +78,12 @@ public abstract class SessionPool<T, E e
if (routeResolver == null) {
throw new IllegalArgumentException("Route resolver may not be null");
}
+ if (defaultMaxPerRoute <= 0) {
+ throw new IllegalArgumentException("Max per route value may not be negative or zero");
+ }
+ if (maxTotal <= 0) {
+ throw new IllegalArgumentException("Max total value may not be negative or zero");
+ }
this.ioreactor = ioreactor;
this.factory = factory;
this.sessionRequestCallback = new InternalSessionRequestCallback();
@@ -132,7 +138,10 @@ public abstract class SessionPool<T, E e
throw new IllegalArgumentException("Route may not be null");
}
if (tunit == null) {
- throw new IllegalArgumentException("Time unit must not be null.");
+ throw new IllegalArgumentException("Time unit may not be null.");
+ }
+ if (callback == null) {
+ throw new IllegalArgumentException("Callback may not be null.");
}
if (this.isShutDown) {
throw new IllegalStateException("Session pool has been shut down");
@@ -164,7 +173,8 @@ public abstract class SessionPool<T, E e
if (reusable) {
this.availableSessions.add(entry);
} else {
- entryShutdown(entry);
+ IOSession iosession = entry.getIOSession();
+ iosession.close();
}
processPendingRequests();
}
@@ -173,17 +183,6 @@ public abstract class SessionPool<T, E e
}
}
- private int getAllocatedTotal() {
- return this.leasedSessions.size() +
- this.pendingSessions.size() +
- this.availableSessions.size();
- }
-
- private void entryShutdown(final PoolEntry<T> entry) {
- IOSession iosession = entry.getIOSession();
- iosession.close();
- }
-
private void processPendingRequests() {
ListIterator<LeaseRequest<T, E>> it = this.leasingRequests.listIterator();
while (it.hasNext()) {
@@ -194,15 +193,6 @@ public abstract class SessionPool<T, E e
int timeout = request.getConnectTimeout();
PoolEntryCallback<T, E> callback = request.getCallback();
- if (getAllocatedTotal() >= this.maxTotal) {
- if (!this.availableSessions.isEmpty()) {
- E entry = this.availableSessions.remove();
- entryShutdown(entry);
- RouteSpecificPool<T, E> pool = getPool(entry.getRoute());
- pool.remove(entry);
- }
- }
-
RouteSpecificPool<T, E> pool = getPool(request.getRoute());
E entry = null;
for (;;) {
@@ -211,7 +201,10 @@ public abstract class SessionPool<T, E e
break;
}
IOSession iosession = entry.getIOSession();
- if (iosession.isClosed() || entry.isExpired(System.currentTimeMillis())) {
+ if (entry.isExpired(System.currentTimeMillis())) {
+ iosession.close();
+ }
+ if (iosession.isClosed()) {
this.availableSessions.remove(entry);
pool.freeEntry(entry, false);
} else {
@@ -223,30 +216,41 @@ public abstract class SessionPool<T, E e
this.availableSessions.remove(entry);
this.leasedSessions.add(entry);
callback.completed(entry);
- } else {
- int max = getMaxPerRoute(route);
- if (pool.getAvailableCount() > 0 && pool.getAllocatedCount() >= max) {
- entry = pool.deleteLastUsed();
- if (entry != null) {
- this.availableSessions.remove(entry);
- entryShutdown(entry);
- }
+ continue;
+ }
+ if (pool.getAllocatedCount() < getMaxPerRoute(route)) {
+ int totalUsed = this.pendingSessions.size() + this.leasedSessions.size();
+ int freeCapacity = Math.max(this.maxTotal - totalUsed, 0);
+ if (freeCapacity == 0) {
+ continue;
}
- if (pool.getAllocatedCount() < max) {
- it.remove();
- SessionRequest sessionRequest = this.ioreactor.connect(
- this.routeResolver.resolveRemoteAddress(route),
- this.routeResolver.resolveLocalAddress(route),
- route,
- this.sessionRequestCallback);
- sessionRequest.setConnectTimeout(timeout);
- this.pendingSessions.add(sessionRequest);
- pool.addPending(sessionRequest, callback);
+ int totalAvailable = this.availableSessions.size();
+ if (totalAvailable > freeCapacity - 1) {
+ dropLastUsed();
}
+ it.remove();
+ SessionRequest sessionRequest = this.ioreactor.connect(
+ this.routeResolver.resolveRemoteAddress(route),
+ this.routeResolver.resolveLocalAddress(route),
+ route,
+ this.sessionRequestCallback);
+ sessionRequest.setConnectTimeout(timeout);
+ this.pendingSessions.add(sessionRequest);
+ pool.addPending(sessionRequest, callback);
}
}
}
+ private void dropLastUsed() {
+ if (!this.availableSessions.isEmpty()) {
+ E entry = this.availableSessions.removeFirst();
+ IOSession iosession = entry.getIOSession();
+ iosession.close();
+ RouteSpecificPool<T, E> pool = getPool(entry.getRoute());
+ pool.remove(entry);
+ }
+ }
+
protected void requestCompleted(final SessionRequest request) {
if (this.isShutDown) {
return;
@@ -405,8 +409,11 @@ public abstract class SessionPool<T, E e
while (it.hasNext()) {
E entry = it.next();
if (entry.getUpdated() <= deadline) {
+ IOSession iosession = entry.getIOSession();
+ iosession.close();
+ RouteSpecificPool<T, E> pool = getPool(entry.getRoute());
+ pool.remove(entry);
it.remove();
- entryShutdown(entry);
}
}
processPendingRequests();
@@ -423,8 +430,11 @@ public abstract class SessionPool<T, E e
while (it.hasNext()) {
E entry = it.next();
if (entry.isExpired(now)) {
+ IOSession iosession = entry.getIOSession();
+ iosession.close();
+ RouteSpecificPool<T, E> pool = getPool(entry.getRoute());
+ pool.remove(entry);
it.remove();
- entryShutdown(entry);
}
}
processPendingRequests();
@@ -437,13 +447,13 @@ public abstract class SessionPool<T, E e
public String toString() {
StringBuilder buffer = new StringBuilder();
buffer.append("[leased: ");
- buffer.append(this.leasedSessions.size());
+ buffer.append(this.leasedSessions);
buffer.append("][available: ");
- buffer.append(this.availableSessions.size());
+ buffer.append(this.availableSessions);
buffer.append("][pending: ");
- buffer.append(this.pendingSessions.size());
+ buffer.append(this.pendingSessions);
buffer.append("]");
- return super.toString();
+ return buffer.toString();
}
class InternalSessionRequestCallback implements SessionRequestCallback {
Added: httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/concurrent/BasicFutureCallback.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/concurrent/BasicFutureCallback.java?rev=1099559&view=auto
==============================================================================
--- httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/concurrent/BasicFutureCallback.java (added)
+++ httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/concurrent/BasicFutureCallback.java Wed May 4 19:02:55 2011
@@ -0,0 +1,73 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.http.impl.nio.concurrent;
+
+import org.apache.http.nio.concurrent.FutureCallback;
+
+class BasicFutureCallback<T> implements FutureCallback<T> {
+
+ private T result;
+ private Exception ex;
+ private boolean completed;
+ private boolean failed;
+ private boolean cancelled;
+
+ public void completed(final T result) {
+ this.result = result;
+ this.completed = true;
+ }
+
+ public T getResult() {
+ return this.result;
+ }
+
+ public Exception getException() {
+ return this.ex;
+ }
+
+ public void failed(final Exception ex) {
+ this.ex = ex;
+ this.failed = true;
+ }
+
+ public void cancelled() {
+ this.cancelled = true;
+ }
+
+ public boolean isCompleted() {
+ return this.completed;
+ }
+
+ public boolean isFailed() {
+ return this.failed;
+ }
+
+ public boolean isCancelled() {
+ return this.cancelled;
+ }
+
+}
\ No newline at end of file
Propchange: httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/concurrent/BasicFutureCallback.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/concurrent/BasicFutureCallback.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/concurrent/BasicFutureCallback.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/concurrent/TestBasicFuture.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/concurrent/TestBasicFuture.java?rev=1099559&view=auto
==============================================================================
--- httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/concurrent/TestBasicFuture.java (added)
+++ httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/concurrent/TestBasicFuture.java Wed May 4 19:02:55 2011
@@ -0,0 +1,231 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.http.impl.nio.concurrent;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import junit.framework.Assert;
+
+import org.apache.http.nio.concurrent.BasicFuture;
+import org.junit.Test;
+
+public class TestBasicFuture {
+
+ @Test
+ public void testCompleted() throws Exception {
+ BasicFutureCallback<Object> callback = new BasicFutureCallback<Object>();
+ BasicFuture<Object> future = new BasicFuture<Object>(callback);
+
+ Assert.assertFalse(future.isDone());
+
+ Object result = new Object();
+ Exception boom = new Exception();
+ future.completed(result);
+ future.failed(boom);
+ Assert.assertTrue(callback.isCompleted());
+ Assert.assertSame(result, callback.getResult());
+ Assert.assertFalse(callback.isFailed());
+ Assert.assertNull(callback.getException());
+ Assert.assertFalse(callback.isCancelled());
+
+ Assert.assertSame(result, future.get());
+ Assert.assertTrue(future.isDone());
+ Assert.assertFalse(future.isCancelled());
+
+ }
+
+ @Test
+ public void testCompletedWithTimeout() throws Exception {
+ BasicFutureCallback<Object> callback = new BasicFutureCallback<Object>();
+ BasicFuture<Object> future = new BasicFuture<Object>(callback);
+
+ Assert.assertFalse(future.isDone());
+
+ Object result = new Object();
+ Exception boom = new Exception();
+ future.completed(result);
+ future.failed(boom);
+ Assert.assertTrue(callback.isCompleted());
+ Assert.assertSame(result, callback.getResult());
+ Assert.assertFalse(callback.isFailed());
+ Assert.assertNull(callback.getException());
+ Assert.assertFalse(callback.isCancelled());
+
+ Assert.assertSame(result, future.get(1, TimeUnit.MILLISECONDS));
+ Assert.assertTrue(future.isDone());
+ Assert.assertFalse(future.isCancelled());
+ }
+
+ @Test
+ public void testFailed() throws Exception {
+ BasicFutureCallback<Object> callback = new BasicFutureCallback<Object>();
+ BasicFuture<Object> future = new BasicFuture<Object>(callback);
+ Object result = new Object();
+ Exception boom = new Exception();
+ future.failed(boom);
+ future.completed(result);
+ Assert.assertFalse(callback.isCompleted());
+ Assert.assertNull(callback.getResult());
+ Assert.assertTrue(callback.isFailed());
+ Assert.assertSame(boom, callback.getException());
+ Assert.assertFalse(callback.isCancelled());
+
+ try {
+ future.get();
+ } catch (ExecutionException ex) {
+ Assert.assertSame(boom, ex.getCause());
+ }
+ Assert.assertTrue(future.isDone());
+ Assert.assertFalse(future.isCancelled());
+ }
+
+ @Test
+ public void testCancelled() throws Exception {
+ BasicFutureCallback<Object> callback = new BasicFutureCallback<Object>();
+ BasicFuture<Object> future = new BasicFuture<Object>(callback);
+ Object result = new Object();
+ Exception boom = new Exception();
+ future.cancel(true);
+ future.failed(boom);
+ future.completed(result);
+ Assert.assertFalse(callback.isCompleted());
+ Assert.assertNull(callback.getResult());
+ Assert.assertFalse(callback.isFailed());
+ Assert.assertNull(callback.getException());
+ Assert.assertTrue(callback.isCancelled());
+
+ Assert.assertNull(future.get());
+ Assert.assertTrue(future.isDone());
+ Assert.assertTrue(future.isCancelled());
+ }
+
+ @Test
+ public void testAsyncCompleted() throws Exception {
+ final BasicFuture<Object> future = new BasicFuture<Object>(null);
+ final Object result = new Object();
+
+ Thread t = new Thread() {
+
+ @Override
+ public void run() {
+ try {
+ Thread.sleep(100);
+ future.completed(result);
+ } catch (InterruptedException boom) {
+ }
+ }
+
+ };
+ t.setDaemon(true);
+ t.start();
+ Assert.assertSame(result, future.get(60, TimeUnit.SECONDS));
+ Assert.assertTrue(future.isDone());
+ Assert.assertFalse(future.isCancelled());
+ }
+
+ @Test
+ public void testAsyncFailed() throws Exception {
+ final BasicFuture<Object> future = new BasicFuture<Object>(null);
+ final Exception boom = new Exception();
+
+ Thread t = new Thread() {
+
+ @Override
+ public void run() {
+ try {
+ Thread.sleep(100);
+ future.failed(boom);
+ } catch (InterruptedException ex) {
+ }
+ }
+
+ };
+ t.setDaemon(true);
+ t.start();
+ try {
+ future.get(60, TimeUnit.SECONDS);
+ } catch (ExecutionException ex) {
+ Assert.assertSame(boom, ex.getCause());
+ }
+ Assert.assertTrue(future.isDone());
+ Assert.assertFalse(future.isCancelled());
+ }
+
+ @Test
+ public void testAsyncCancelled() throws Exception {
+ final BasicFuture<Object> future = new BasicFuture<Object>(null);
+
+ Thread t = new Thread() {
+
+ @Override
+ public void run() {
+ try {
+ Thread.sleep(100);
+ future.cancel(true);
+ } catch (InterruptedException ex) {
+ }
+ }
+
+ };
+ t.setDaemon(true);
+ t.start();
+ Assert.assertNull(future.get(60, TimeUnit.SECONDS));
+ Assert.assertTrue(future.isDone());
+ Assert.assertTrue(future.isCancelled());
+ }
+
+ @Test(expected=TimeoutException.class)
+ public void testAsyncTimeout() throws Exception {
+ final BasicFuture<Object> future = new BasicFuture<Object>(null);
+ final Object result = new Object();
+
+ Thread t = new Thread() {
+
+ @Override
+ public void run() {
+ try {
+ Thread.sleep(200);
+ future.completed(result);
+ } catch (InterruptedException ex) {
+ }
+ }
+
+ };
+ t.setDaemon(true);
+ t.start();
+ future.get(1, TimeUnit.MILLISECONDS);
+ }
+
+ @Test(expected=TimeoutException.class)
+ public void testAsyncNegativeTimeout() throws Exception {
+ final BasicFuture<Object> future = new BasicFuture<Object>(null);
+ future.get(-1, TimeUnit.MILLISECONDS);
+ }
+
+}
Propchange: httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/concurrent/TestBasicFuture.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/concurrent/TestBasicFuture.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/concurrent/TestBasicFuture.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/pool/BasicPoolEntryCallback.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/pool/BasicPoolEntryCallback.java?rev=1099559&view=auto
==============================================================================
--- httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/pool/BasicPoolEntryCallback.java (added)
+++ httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/pool/BasicPoolEntryCallback.java Wed May 4 19:02:55 2011
@@ -0,0 +1,71 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.http.impl.nio.pool;
+
+class BasicPoolEntryCallback implements PoolEntryCallback<String, PoolEntry<String>> {
+
+ private PoolEntry<String> entry;
+ private Exception ex;
+ private boolean completed;
+ private boolean failed;
+ private boolean cancelled;
+
+ public void completed(final PoolEntry<String> entry) {
+ this.entry = entry;
+ this.completed = true;
+ }
+
+ public PoolEntry<String> getEntry() {
+ return this.entry;
+ }
+
+ public Exception getException() {
+ return this.ex;
+ }
+
+ public void failed(final Exception ex) {
+ this.ex = ex;
+ this.failed = true;
+ }
+
+ public void cancelled() {
+ this.cancelled = true;
+ }
+
+ public boolean isCompleted() {
+ return this.completed;
+ }
+
+ public boolean isFailed() {
+ return this.failed;
+ }
+
+ public boolean isCancelled() {
+ return this.cancelled;
+ }
+
+}
\ No newline at end of file
Propchange: httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/pool/BasicPoolEntryCallback.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/pool/BasicPoolEntryCallback.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/pool/BasicPoolEntryCallback.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/pool/TestPoolEntry.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/pool/TestPoolEntry.java?rev=1099559&view=auto
==============================================================================
--- httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/pool/TestPoolEntry.java (added)
+++ httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/pool/TestPoolEntry.java Wed May 4 19:02:55 2011
@@ -0,0 +1,112 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.http.impl.nio.pool;
+
+import java.util.concurrent.TimeUnit;
+
+import junit.framework.Assert;
+
+import org.apache.http.nio.reactor.IOSession;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+public class TestPoolEntry {
+
+ static class MockPoolEntry extends PoolEntry<String> {
+
+ public MockPoolEntry(final String route,
+ long timeToLive, final TimeUnit tunit) {
+ super(route, Mockito.mock(IOSession.class), timeToLive, tunit);
+ }
+
+ public MockPoolEntry(final String route, final IOSession iosession,
+ long timeToLive, final TimeUnit tunit) {
+ super(route, iosession, timeToLive, tunit);
+ }
+
+ }
+
+ @Test
+ public void testBasics() throws Exception {
+ MockPoolEntry entry1 = new MockPoolEntry("route1", 10L, TimeUnit.MILLISECONDS);
+ long now = System.currentTimeMillis();
+ Assert.assertEquals("route1", entry1.getRoute());
+ Assert.assertTrue(now >= entry1.getCreated());
+ Assert.assertEquals(entry1.getValidUnit(), entry1.getExpiry());
+ Assert.assertEquals(entry1.getCreated() + 10L, entry1.getValidUnit());
+ }
+
+ @Test
+ public void testInvalidConstruction() throws Exception {
+ try {
+ new MockPoolEntry(null, Mockito.mock(IOSession.class), 0L, TimeUnit.MILLISECONDS);
+ Assert.fail("IllegalArgumentException should have been thrown");
+ } catch (IllegalArgumentException expected) {
+ }
+ try {
+ new MockPoolEntry("stuff", null, 0L, TimeUnit.MILLISECONDS);
+ Assert.fail("IllegalArgumentException should have been thrown");
+ } catch (IllegalArgumentException expected) {
+ }
+ try {
+ new MockPoolEntry("stuff", Mockito.mock(IOSession.class), 0L, null);
+ Assert.fail("IllegalArgumentException should have been thrown");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ @Test
+ public void testValidInfinitely() throws Exception {
+ MockPoolEntry entry1 = new MockPoolEntry("route1", 0L, TimeUnit.MILLISECONDS);
+ Assert.assertEquals(Long.MAX_VALUE, entry1.getValidUnit());
+ Assert.assertEquals(entry1.getValidUnit(), entry1.getExpiry());
+ }
+
+ @Test
+ public void testExpiry() throws Exception {
+ MockPoolEntry entry1 = new MockPoolEntry("route1", 0L, TimeUnit.MILLISECONDS);
+ Assert.assertEquals(Long.MAX_VALUE, entry1.getExpiry());
+ entry1.updateExpiry(50L, TimeUnit.MILLISECONDS);
+ Assert.assertEquals(entry1.getUpdated() + 50L, entry1.getExpiry());
+ entry1.updateExpiry(0L, TimeUnit.MILLISECONDS);
+ Assert.assertEquals(Long.MAX_VALUE, entry1.getExpiry());
+
+ MockPoolEntry entry2 = new MockPoolEntry("route1", 100L, TimeUnit.MILLISECONDS);
+ Assert.assertEquals(entry2.getCreated() + 100L, entry2.getExpiry());
+ entry2.updateExpiry(150L, TimeUnit.MILLISECONDS);
+ Assert.assertEquals(entry2.getCreated() + 100L, entry2.getExpiry());
+ entry2.updateExpiry(50L, TimeUnit.MILLISECONDS);
+ Assert.assertEquals(entry2.getUpdated() + 50L, entry2.getExpiry());
+ }
+
+ @Test(expected=IllegalArgumentException.class)
+ public void testInvalidExpiry() throws Exception {
+ MockPoolEntry entry1 = new MockPoolEntry("route1", 0L, TimeUnit.MILLISECONDS);
+ entry1.updateExpiry(50L, null);
+ }
+
+}
Propchange: httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/pool/TestPoolEntry.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/pool/TestPoolEntry.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/pool/TestPoolEntry.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/pool/TestRouteSpecificPool.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/pool/TestRouteSpecificPool.java?rev=1099559&view=auto
==============================================================================
--- httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/pool/TestRouteSpecificPool.java (added)
+++ httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/pool/TestRouteSpecificPool.java Wed May 4 19:02:55 2011
@@ -0,0 +1,386 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.http.impl.nio.pool;
+
+import java.io.IOException;
+import java.net.SocketTimeoutException;
+import java.util.concurrent.TimeUnit;
+
+import junit.framework.Assert;
+
+import org.apache.http.nio.reactor.IOSession;
+import org.apache.http.nio.reactor.SessionRequest;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+public class TestRouteSpecificPool {
+
+ static class LocalPoolEntry extends PoolEntry<String> {
+
+ public LocalPoolEntry(final String route, final IOSession iosession,
+ long timeToLive, final TimeUnit tunit) {
+ super(route, iosession, timeToLive, tunit);
+ }
+
+ }
+
+ static class LocalPoolEntryFactory implements PoolEntryFactory<String, PoolEntry<String>> {
+
+ public PoolEntry<String> createEntry(final String route, final IOSession session) {
+ return new LocalPoolEntry(route, session, 0L, TimeUnit.MILLISECONDS);
+ }
+
+ };
+
+ static class LocalRoutePool extends RouteSpecificPool<String, PoolEntry<String>> {
+
+ public LocalRoutePool() {
+ super("whatever", new LocalPoolEntryFactory());
+ }
+
+ };
+
+ @Test
+ public void testEmptyPool() throws Exception {
+ LocalRoutePool pool = new LocalRoutePool();
+ Assert.assertEquals(0, pool.getAllocatedCount());
+ Assert.assertEquals(0, pool.getAvailableCount());
+ Assert.assertEquals(0, pool.getLeasedCount());
+ Assert.assertEquals(0, pool.getPendingCount());
+ Assert.assertEquals("[route: whatever][leased: 0][available: 0][pending: 0]", pool.toString());
+ }
+
+ @Test
+ public void testSuccessfulConnect() throws Exception {
+ LocalRoutePool pool = new LocalRoutePool();
+ IOSession session = Mockito.mock(IOSession.class);
+ SessionRequest sessionRequest = Mockito.mock(SessionRequest.class);
+ Mockito.when(sessionRequest.getSession()).thenReturn(session);
+ BasicPoolEntryCallback callback = new BasicPoolEntryCallback();
+ pool.addPending(sessionRequest, callback);
+ Assert.assertEquals(1, pool.getAllocatedCount());
+ Assert.assertEquals(0, pool.getAvailableCount());
+ Assert.assertEquals(0, pool.getLeasedCount());
+ Assert.assertEquals(1, pool.getPendingCount());
+ PoolEntry<String> entry = pool.completed(sessionRequest);
+ Assert.assertNotNull(entry);
+ Assert.assertSame(session, entry.getIOSession());
+ Assert.assertTrue(callback.isCompleted());
+ Assert.assertFalse(callback.isFailed());
+ Assert.assertFalse(callback.isCancelled());
+
+ Assert.assertEquals(1, pool.getAllocatedCount());
+ Assert.assertEquals(0, pool.getAvailableCount());
+ Assert.assertEquals(1, pool.getLeasedCount());
+ Assert.assertEquals(0, pool.getPendingCount());
+ }
+
+ @Test
+ public void testFailedConnect() throws Exception {
+ LocalRoutePool pool = new LocalRoutePool();
+ IOException ex = new IOException();
+ SessionRequest sessionRequest = Mockito.mock(SessionRequest.class);
+ Mockito.when(sessionRequest.getException()).thenReturn(ex);
+ BasicPoolEntryCallback callback = new BasicPoolEntryCallback();
+ pool.addPending(sessionRequest, callback);
+ Assert.assertEquals(1, pool.getAllocatedCount());
+ Assert.assertEquals(0, pool.getAvailableCount());
+ Assert.assertEquals(0, pool.getLeasedCount());
+ Assert.assertEquals(1, pool.getPendingCount());
+ pool.failed(sessionRequest);
+ Assert.assertFalse(callback.isCompleted());
+ Assert.assertTrue(callback.isFailed());
+ Assert.assertFalse(callback.isCancelled());
+
+ Assert.assertEquals(0, pool.getAllocatedCount());
+ Assert.assertEquals(0, pool.getAvailableCount());
+ Assert.assertEquals(0, pool.getLeasedCount());
+ Assert.assertEquals(0, pool.getPendingCount());
+ }
+
+ @Test
+ public void testCancelledConnect() throws Exception {
+ LocalRoutePool pool = new LocalRoutePool();
+ SessionRequest sessionRequest = Mockito.mock(SessionRequest.class);
+ BasicPoolEntryCallback callback = new BasicPoolEntryCallback();
+ pool.addPending(sessionRequest, callback);
+ Assert.assertEquals(1, pool.getAllocatedCount());
+ Assert.assertEquals(0, pool.getAvailableCount());
+ Assert.assertEquals(0, pool.getLeasedCount());
+ Assert.assertEquals(1, pool.getPendingCount());
+ pool.cancelled(sessionRequest);
+ Assert.assertFalse(callback.isCompleted());
+ Assert.assertFalse(callback.isFailed());
+ Assert.assertTrue(callback.isCancelled());
+
+ Assert.assertEquals(0, pool.getAllocatedCount());
+ Assert.assertEquals(0, pool.getAvailableCount());
+ Assert.assertEquals(0, pool.getLeasedCount());
+ Assert.assertEquals(0, pool.getPendingCount());
+ }
+
+ @Test
+ public void testConnectTimeout() throws Exception {
+ LocalRoutePool pool = new LocalRoutePool();
+ SessionRequest sessionRequest = Mockito.mock(SessionRequest.class);
+ BasicPoolEntryCallback callback = new BasicPoolEntryCallback();
+ pool.addPending(sessionRequest, callback);
+ Assert.assertEquals(1, pool.getAllocatedCount());
+ Assert.assertEquals(0, pool.getAvailableCount());
+ Assert.assertEquals(0, pool.getLeasedCount());
+ Assert.assertEquals(1, pool.getPendingCount());
+ pool.timeout(sessionRequest);
+ Assert.assertFalse(callback.isCompleted());
+ Assert.assertTrue(callback.isFailed());
+ Assert.assertFalse(callback.isCancelled());
+ Assert.assertTrue(callback.getException() instanceof SocketTimeoutException);
+
+ Assert.assertEquals(0, pool.getAllocatedCount());
+ Assert.assertEquals(0, pool.getAvailableCount());
+ Assert.assertEquals(0, pool.getLeasedCount());
+ Assert.assertEquals(0, pool.getPendingCount());
+ }
+
+ @Test
+ public void testLeaseRelease() throws Exception {
+ LocalRoutePool pool = new LocalRoutePool();
+ IOSession session1 = Mockito.mock(IOSession.class);
+ SessionRequest sessionRequest1 = Mockito.mock(SessionRequest.class);
+ Mockito.when(sessionRequest1.getSession()).thenReturn(session1);
+ pool.addPending(sessionRequest1, new BasicPoolEntryCallback());
+ IOSession session2 = Mockito.mock(IOSession.class);
+ SessionRequest sessionRequest2 = Mockito.mock(SessionRequest.class);
+ Mockito.when(sessionRequest2.getSession()).thenReturn(session2);
+ pool.addPending(sessionRequest2, new BasicPoolEntryCallback());
+ IOSession session3 = Mockito.mock(IOSession.class);
+ SessionRequest sessionRequest3 = Mockito.mock(SessionRequest.class);
+ Mockito.when(sessionRequest3.getSession()).thenReturn(session3);
+ pool.addPending(sessionRequest3, new BasicPoolEntryCallback());
+
+ Assert.assertEquals(3, pool.getAllocatedCount());
+ Assert.assertEquals(0, pool.getAvailableCount());
+ Assert.assertEquals(0, pool.getLeasedCount());
+ Assert.assertEquals(3, pool.getPendingCount());
+
+ PoolEntry<String> entry1 = pool.completed(sessionRequest1);
+ Assert.assertNotNull(entry1);
+ PoolEntry<String> entry2 = pool.completed(sessionRequest2);
+ Assert.assertNotNull(entry2);
+ PoolEntry<String> entry3 = pool.completed(sessionRequest3);
+ Assert.assertNotNull(entry3);
+
+ Assert.assertEquals(3, pool.getAllocatedCount());
+ Assert.assertEquals(0, pool.getAvailableCount());
+ Assert.assertEquals(3, pool.getLeasedCount());
+ Assert.assertEquals(0, pool.getPendingCount());
+
+ pool.freeEntry(entry1, true);
+ pool.freeEntry(entry2, false);
+ pool.freeEntry(entry3, true);
+
+ Assert.assertEquals(2, pool.getAllocatedCount());
+ Assert.assertEquals(2, pool.getAvailableCount());
+ Assert.assertEquals(0, pool.getLeasedCount());
+ Assert.assertEquals(0, pool.getPendingCount());
+
+ Assert.assertNotNull(pool.getFreeEntry(null));
+ Assert.assertNotNull(pool.getFreeEntry(null));
+ Assert.assertNull(pool.getFreeEntry(null));
+
+ Assert.assertEquals(2, pool.getAllocatedCount());
+ Assert.assertEquals(0, pool.getAvailableCount());
+ Assert.assertEquals(2, pool.getLeasedCount());
+ Assert.assertEquals(0, pool.getPendingCount());
+ }
+
+ @Test
+ public void testLeaseReleaseStateful() throws Exception {
+ LocalRoutePool pool = new LocalRoutePool();
+ IOSession session1 = Mockito.mock(IOSession.class);
+ SessionRequest sessionRequest1 = Mockito.mock(SessionRequest.class);
+ Mockito.when(sessionRequest1.getSession()).thenReturn(session1);
+ pool.addPending(sessionRequest1, new BasicPoolEntryCallback());
+ IOSession session2 = Mockito.mock(IOSession.class);
+ SessionRequest sessionRequest2 = Mockito.mock(SessionRequest.class);
+ Mockito.when(sessionRequest2.getSession()).thenReturn(session2);
+ pool.addPending(sessionRequest2, new BasicPoolEntryCallback());
+ IOSession session3 = Mockito.mock(IOSession.class);
+ SessionRequest sessionRequest3 = Mockito.mock(SessionRequest.class);
+ Mockito.when(sessionRequest3.getSession()).thenReturn(session3);
+ pool.addPending(sessionRequest3, new BasicPoolEntryCallback());
+
+ PoolEntry<String> entry1 = pool.completed(sessionRequest1);
+ Assert.assertNotNull(entry1);
+ PoolEntry<String> entry2 = pool.completed(sessionRequest2);
+ Assert.assertNotNull(entry2);
+ PoolEntry<String> entry3 = pool.completed(sessionRequest3);
+ Assert.assertNotNull(entry3);
+
+ entry2.setState(Boolean.FALSE);
+ pool.freeEntry(entry1, true);
+ pool.freeEntry(entry2, true);
+ pool.freeEntry(entry3, true);
+
+ Assert.assertEquals(entry2, pool.getFreeEntry(Boolean.FALSE));
+ Assert.assertEquals(entry1, pool.getFreeEntry(Boolean.FALSE));
+ Assert.assertEquals(entry3, pool.getFreeEntry(null));
+ Assert.assertEquals(null, pool.getFreeEntry(null));
+
+ entry1.setState(Boolean.TRUE);
+ entry2.setState(Boolean.FALSE);
+ entry3.setState(Boolean.TRUE);
+ pool.freeEntry(entry1, true);
+ pool.freeEntry(entry2, true);
+ pool.freeEntry(entry3, true);
+
+ Assert.assertEquals(null, pool.getFreeEntry(null));
+ Assert.assertEquals(entry2, pool.getFreeEntry(Boolean.FALSE));
+ Assert.assertEquals(null, pool.getFreeEntry(Boolean.FALSE));
+ Assert.assertEquals(entry1, pool.getFreeEntry(Boolean.TRUE));
+ Assert.assertEquals(entry3, pool.getFreeEntry(Boolean.TRUE));
+ Assert.assertEquals(null, pool.getFreeEntry(Boolean.TRUE));
+ }
+
+ @Test(expected=IllegalStateException.class)
+ public void testReleaseInvalidEntry() throws Exception {
+ LocalRoutePool pool = new LocalRoutePool();
+ IOSession session = Mockito.mock(IOSession.class);
+ LocalPoolEntry entry = new LocalPoolEntry("whatever", session, 0L, TimeUnit.MILLISECONDS);
+ pool.freeEntry(entry, true);
+ }
+
+ @Test
+ public void testRemove() throws Exception {
+ LocalRoutePool pool = new LocalRoutePool();
+ IOSession session1 = Mockito.mock(IOSession.class);
+ SessionRequest sessionRequest1 = Mockito.mock(SessionRequest.class);
+ Mockito.when(sessionRequest1.getSession()).thenReturn(session1);
+ pool.addPending(sessionRequest1, new BasicPoolEntryCallback());
+ IOSession session2 = Mockito.mock(IOSession.class);
+ SessionRequest sessionRequest2 = Mockito.mock(SessionRequest.class);
+ Mockito.when(sessionRequest2.getSession()).thenReturn(session2);
+ pool.addPending(sessionRequest2, new BasicPoolEntryCallback());
+ IOSession session3 = Mockito.mock(IOSession.class);
+ SessionRequest sessionRequest3 = Mockito.mock(SessionRequest.class);
+ Mockito.when(sessionRequest3.getSession()).thenReturn(session3);
+ pool.addPending(sessionRequest3, new BasicPoolEntryCallback());
+
+ Assert.assertEquals(3, pool.getAllocatedCount());
+ Assert.assertEquals(0, pool.getAvailableCount());
+ Assert.assertEquals(0, pool.getLeasedCount());
+ Assert.assertEquals(3, pool.getPendingCount());
+
+ PoolEntry<String> entry1 = pool.completed(sessionRequest1);
+ Assert.assertNotNull(entry1);
+ PoolEntry<String> entry2 = pool.completed(sessionRequest2);
+ Assert.assertNotNull(entry2);
+ PoolEntry<String> entry3 = pool.completed(sessionRequest3);
+ Assert.assertNotNull(entry3);
+
+ Assert.assertEquals(3, pool.getAllocatedCount());
+ Assert.assertEquals(0, pool.getAvailableCount());
+ Assert.assertEquals(3, pool.getLeasedCount());
+ Assert.assertEquals(0, pool.getPendingCount());
+
+ Assert.assertTrue(pool.remove(entry2));
+ Assert.assertFalse(pool.remove(entry2));
+
+ Assert.assertEquals(2, pool.getAllocatedCount());
+ Assert.assertEquals(0, pool.getAvailableCount());
+ Assert.assertEquals(2, pool.getLeasedCount());
+ Assert.assertEquals(0, pool.getPendingCount());
+
+ pool.freeEntry(entry1, true);
+ pool.freeEntry(entry3, true);
+
+ Assert.assertEquals(2, pool.getAllocatedCount());
+ Assert.assertEquals(2, pool.getAvailableCount());
+ Assert.assertEquals(0, pool.getLeasedCount());
+ Assert.assertEquals(0, pool.getPendingCount());
+
+ Assert.assertTrue(pool.remove(entry1));
+ Assert.assertTrue(pool.remove(entry3));
+
+ Assert.assertEquals(0, pool.getAllocatedCount());
+ Assert.assertEquals(0, pool.getAvailableCount());
+ Assert.assertEquals(0, pool.getLeasedCount());
+ Assert.assertEquals(0, pool.getPendingCount());
+ }
+
+ @Test(expected=IllegalArgumentException.class)
+ public void testReleaseInvalid() throws Exception {
+ LocalRoutePool pool = new LocalRoutePool();
+ pool.freeEntry(null, true);
+ }
+
+ @Test(expected=IllegalArgumentException.class)
+ public void testRemoveInvalid() throws Exception {
+ LocalRoutePool pool = new LocalRoutePool();
+ pool.remove(null);
+ }
+
+ @Test
+ public void testShutdown() throws Exception {
+ LocalRoutePool pool = new LocalRoutePool();
+ IOSession session1 = Mockito.mock(IOSession.class);
+ SessionRequest sessionRequest1 = Mockito.mock(SessionRequest.class);
+ Mockito.when(sessionRequest1.getSession()).thenReturn(session1);
+ pool.addPending(sessionRequest1, new BasicPoolEntryCallback());
+ IOSession session2 = Mockito.mock(IOSession.class);
+ SessionRequest sessionRequest2 = Mockito.mock(SessionRequest.class);
+ Mockito.when(sessionRequest2.getSession()).thenReturn(session2);
+ pool.addPending(sessionRequest2, new BasicPoolEntryCallback());
+ IOSession session3 = Mockito.mock(IOSession.class);
+ SessionRequest sessionRequest3 = Mockito.mock(SessionRequest.class);
+ Mockito.when(sessionRequest3.getSession()).thenReturn(session3);
+ pool.addPending(sessionRequest3, new BasicPoolEntryCallback());
+
+ PoolEntry<String> entry1 = pool.completed(sessionRequest1);
+ Assert.assertNotNull(entry1);
+ PoolEntry<String> entry2 = pool.completed(sessionRequest2);
+ Assert.assertNotNull(entry2);
+
+ pool.freeEntry(entry1, true);
+
+ Assert.assertEquals(3, pool.getAllocatedCount());
+ Assert.assertEquals(1, pool.getAvailableCount());
+ Assert.assertEquals(1, pool.getLeasedCount());
+ Assert.assertEquals(1, pool.getPendingCount());
+
+ pool.shutdown();
+
+ Assert.assertEquals(0, pool.getAllocatedCount());
+ Assert.assertEquals(0, pool.getAvailableCount());
+ Assert.assertEquals(0, pool.getLeasedCount());
+ Assert.assertEquals(0, pool.getPendingCount());
+
+ Mockito.verify(sessionRequest3).cancel();
+ Mockito.verify(session2).close();
+ Mockito.verify(session1).close();
+ }
+
+}
Propchange: httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/pool/TestRouteSpecificPool.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/pool/TestRouteSpecificPool.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: httpcomponents/httpasyncclient/trunk/httpasyncclient/src/test/java/org/apache/http/impl/nio/pool/TestRouteSpecificPool.java
------------------------------------------------------------------------------
svn:mime-type = text/plain