/*
* ====================================================================
* 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
* .
*
*/
package org.apache.http.nio.protocol;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import org.apache.http.ConnectionClosedException;
import org.apache.http.ConnectionReuseStrategy;
import org.apache.http.HttpHost;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.impl.nio.pool.BasicNIOPoolEntry;
import org.apache.http.nio.NHttpClientConnection;
import org.apache.http.nio.protocol.HttpAsyncRequester.ConnRequestCallback;
import org.apache.http.pool.ConnPool;
import org.apache.http.pool.PoolEntry;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpProcessor;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
public class TestHttpAsyncRequester {
private HttpProcessor httpProcessor;
private ConnectionReuseStrategy reuseStrategy;
private HttpAsyncRequester requester;
private HttpContext exchangeContext;
private HttpContext connContext;
private HttpAsyncRequestProducer requestProducer;
private HttpAsyncResponseConsumer responseConsumer;
private NHttpClientConnection conn;
private FutureCallback callback;
private ConnPool> connPool;
@SuppressWarnings("unchecked")
@Before
public void setUp() throws Exception {
this.httpProcessor = Mockito.mock(HttpProcessor.class);
this.reuseStrategy = Mockito.mock(ConnectionReuseStrategy.class);
this.requester = new HttpAsyncRequester(this.httpProcessor, this.reuseStrategy);
this.exchangeContext = new BasicHttpContext();
this.requestProducer = Mockito.mock(HttpAsyncRequestProducer.class);
this.responseConsumer = Mockito.mock(HttpAsyncResponseConsumer.class);
this.conn = Mockito.mock(NHttpClientConnection.class);
this.callback = Mockito.mock(FutureCallback.class);
this.connContext = new BasicHttpContext();
this.connPool = Mockito.mock(ConnPool.class);
Mockito.when(this.conn.getContext()).thenReturn(this.connContext);
}
@After
public void tearDown() throws Exception {
}
@Test
public void testInvalidExecution() throws Exception {
try {
this.requester.execute(
null,
this.responseConsumer,
this.conn);
Assert.fail("IllegalArgumentException expected");
} catch (final IllegalArgumentException ex) {
}
try {
this.requester.execute(
this.requestProducer,
null,
this.conn);
Assert.fail("IllegalArgumentException expected");
} catch (final IllegalArgumentException ex) {
}
try {
this.requester.execute(
this.requestProducer,
this.responseConsumer,
(NHttpClientConnection) null);
Assert.fail("IllegalArgumentException expected");
} catch (final IllegalArgumentException ex) {
}
try {
this.requester.execute(
this.requestProducer,
this.responseConsumer,
this.conn,
null);
Assert.fail("IllegalArgumentException expected");
} catch (final IllegalArgumentException ex) {
}
try {
this.requester.execute(
null,
this.responseConsumer,
this.connPool);
Assert.fail("IllegalArgumentException expected");
} catch (final IllegalArgumentException ex) {
}
try {
this.requester.execute(
this.requestProducer,
null,
this.connPool);
Assert.fail("IllegalArgumentException expected");
} catch (final IllegalArgumentException ex) {
}
try {
this.requester.execute(
this.requestProducer,
this.responseConsumer,
(ConnPool>) null);
Assert.fail("IllegalArgumentException expected");
} catch (final IllegalArgumentException ex) {
}
try {
this.requester.execute(
this.requestProducer,
this.responseConsumer,
this.connPool,
null);
Assert.fail("IllegalArgumentException expected");
} catch (final IllegalArgumentException ex) {
}
}
@Test
public void testSimpleExecute() throws Exception {
Mockito.when(this.conn.isOpen()).thenReturn(Boolean.TRUE);
final Future future = this.requester.execute(
this.requestProducer,
this.responseConsumer,
this.conn, this.exchangeContext, null);
Assert.assertNotNull(future);
Assert.assertNotNull(this.connContext.getAttribute(HttpAsyncRequestExecutor.HTTP_HANDLER));
Mockito.verify(this.conn).requestOutput();
}
@Test
public void testExecuteConnectionClosedUnexpectedly() throws Exception {
Mockito.when(this.conn.isOpen()).thenReturn(false);
final Future future = this.requester.execute(
this.requestProducer,
this.responseConsumer,
this.conn, this.exchangeContext, null);
Assert.assertNotNull(future);
Mockito.verify(this.requestProducer).failed(Mockito.any(ConnectionClosedException.class));
Mockito.verify(this.responseConsumer).failed(Mockito.any(ConnectionClosedException.class));
Mockito.verify(this.requestProducer, Mockito.atLeastOnce()).close();
Mockito.verify(this.responseConsumer, Mockito.atLeastOnce()).close();
Assert.assertTrue(future.isDone());
Assert.assertNotNull(future.isDone());
try {
future.get();
} catch (final ExecutionException ex) {
final Throwable cause = ex.getCause();
Assert.assertNotNull(cause);
Assert.assertTrue(cause instanceof ConnectionClosedException);
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Test
public void testPooledConnectionRequestFailed() throws Exception {
final HttpHost host = new HttpHost("somehost");
Mockito.when(this.requestProducer.getTarget()).thenReturn(host);
final Future future = this.requester.execute(
this.requestProducer,
this.responseConsumer,
this.connPool, this.exchangeContext, this.callback);
Assert.assertNotNull(future);
final ArgumentCaptor argCaptor = ArgumentCaptor.forClass(FutureCallback.class);
Mockito.verify(this.connPool).lease(
Mockito.eq(host), Mockito.isNull(), argCaptor.capture());
final ConnRequestCallback connRequestCallback = (ConnRequestCallback) argCaptor.getValue();
final Exception oppsie = new Exception();
connRequestCallback.failed(oppsie);
Mockito.verify(this.responseConsumer).failed(oppsie);
Mockito.verify(this.callback).failed(oppsie);
Mockito.verify(this.responseConsumer).close();
Mockito.verify(this.requestProducer).close();
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Test
public void testPooledConnectionRequestCancelled() throws Exception {
final HttpHost host = new HttpHost("somehost");
Mockito.when(this.requestProducer.getTarget()).thenReturn(host);
final Future future = this.requester.execute(
this.requestProducer,
this.responseConsumer,
this.connPool, this.exchangeContext, this.callback);
Assert.assertNotNull(future);
final ArgumentCaptor argCaptor = ArgumentCaptor.forClass(FutureCallback.class);
Mockito.verify(this.connPool).lease(
Mockito.eq(host), Mockito.isNull(), argCaptor.capture());
final ConnRequestCallback connRequestCallback = (ConnRequestCallback) argCaptor.getValue();
connRequestCallback.cancelled();
Mockito.verify(this.responseConsumer).cancel();
Mockito.verify(this.callback).cancelled();
Mockito.verify(this.responseConsumer).close();
Mockito.verify(this.requestProducer).close();
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Test
public void testPooledConnectionAutoReleaseOnRequestCancel() throws Exception {
final HttpHost host = new HttpHost("somehost");
Mockito.when(this.requestProducer.getTarget()).thenReturn(host);
final Future future = this.requester.execute(
this.requestProducer,
this.responseConsumer,
this.connPool, this.exchangeContext, this.callback);
Assert.assertNotNull(future);
final ArgumentCaptor argCaptor = ArgumentCaptor.forClass(FutureCallback.class);
Mockito.verify(this.connPool).lease(
Mockito.eq(host), Mockito.isNull(), argCaptor.capture());
final ConnRequestCallback connRequestCallback = (ConnRequestCallback) argCaptor.getValue();
future.cancel(true);
final BasicNIOPoolEntry entry = new BasicNIOPoolEntry("id", host, this.conn);
connRequestCallback.completed(entry);
Mockito.verify(this.connPool).release(entry, true);
Mockito.verify(this.conn, Mockito.never()).requestOutput();
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Test
public void testPooledRequestExecutionSucceeded() throws Exception {
final HttpHost host = new HttpHost("somehost");
Mockito.when(this.requestProducer.getTarget()).thenReturn(host);
Mockito.when(this.conn.isOpen()).thenReturn(true);
final Future future = this.requester.execute(
this.requestProducer,
this.responseConsumer,
this.connPool, this.exchangeContext, this.callback);
Assert.assertNotNull(future);
final ArgumentCaptor argCaptor = ArgumentCaptor.forClass(FutureCallback.class);
Mockito.verify(this.connPool).lease(
Mockito.eq(host), Mockito.isNull(), argCaptor.capture());
final ConnRequestCallback connRequestCallback = (ConnRequestCallback) argCaptor.getValue();
final BasicNIOPoolEntry entry = new BasicNIOPoolEntry("id", host, this.conn);
connRequestCallback.completed(entry);
final BasicAsyncClientExchangeHandler exchangeHandler = (BasicAsyncClientExchangeHandler) this.connContext.getAttribute(
HttpAsyncRequestExecutor.HTTP_HANDLER);
Assert.assertNotNull(exchangeHandler);
Mockito.verify(this.conn).requestOutput();
final Object result = new Object();
Mockito.when(this.responseConsumer.getResult()).thenReturn(result);
exchangeHandler.responseCompleted();
Mockito.verify(this.callback).completed(result);
Mockito.verify(this.responseConsumer).close();
Mockito.verify(this.requestProducer).close();
Mockito.verify(this.connPool).release(entry, true);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Test
public void testPooledRequestExecutionFailed() throws Exception {
final HttpHost host = new HttpHost("somehost");
Mockito.when(this.requestProducer.getTarget()).thenReturn(host);
Mockito.when(this.conn.isOpen()).thenReturn(true);
final Future future = this.requester.execute(
this.requestProducer,
this.responseConsumer,
this.connPool, this.exchangeContext, this.callback);
Assert.assertNotNull(future);
final ArgumentCaptor argCaptor = ArgumentCaptor.forClass(FutureCallback.class);
Mockito.verify(this.connPool).lease(
Mockito.eq(host), Mockito.isNull(), argCaptor.capture());
final ConnRequestCallback connRequestCallback = (ConnRequestCallback) argCaptor.getValue();
final BasicNIOPoolEntry entry = new BasicNIOPoolEntry("id", host, this.conn);
connRequestCallback.completed(entry);
final BasicAsyncClientExchangeHandler exchangeHandler = (BasicAsyncClientExchangeHandler) this.connContext.getAttribute(
HttpAsyncRequestExecutor.HTTP_HANDLER);
Assert.assertNotNull(exchangeHandler);
Mockito.verify(this.conn).requestOutput();
final Exception oppsie = new Exception();
exchangeHandler.failed(oppsie);
Mockito.verify(this.responseConsumer).failed(oppsie);
Mockito.verify(this.callback).failed(oppsie);
Mockito.verify(this.responseConsumer).close();
Mockito.verify(this.requestProducer).close();
Mockito.verify(this.connPool).release(entry, false);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Test
public void testPooledRequestExecutionCancelled() throws Exception {
final HttpHost host = new HttpHost("somehost");
Mockito.when(this.requestProducer.getTarget()).thenReturn(host);
Mockito.when(this.conn.isOpen()).thenReturn(true);
final Future future = this.requester.execute(
this.requestProducer,
this.responseConsumer,
this.connPool, this.exchangeContext, this.callback);
Assert.assertNotNull(future);
final ArgumentCaptor argCaptor = ArgumentCaptor.forClass(FutureCallback.class);
Mockito.verify(this.connPool).lease(
Mockito.eq(host), Mockito.isNull(), argCaptor.capture());
final ConnRequestCallback connRequestCallback = (ConnRequestCallback) argCaptor.getValue();
final BasicNIOPoolEntry entry = new BasicNIOPoolEntry("id", host, this.conn);
connRequestCallback.completed(entry);
final BasicAsyncClientExchangeHandler exchangeHandler = (BasicAsyncClientExchangeHandler) this.connContext.getAttribute(
HttpAsyncRequestExecutor.HTTP_HANDLER);
Assert.assertNotNull(exchangeHandler);
Mockito.verify(this.conn).requestOutput();
exchangeHandler.cancel();
Mockito.verify(this.responseConsumer).cancel();
Mockito.verify(this.callback).cancelled();
Mockito.verify(this.responseConsumer).close();
Mockito.verify(this.requestProducer).close();
Mockito.verify(this.connPool).release(entry, false);
}
}