Added test cases for EofSensorInputStream, ConnectionReleaseTriggerImpl, RequestEntityWrapper, ResponseEntityWrapper
git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@1405557 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
87a46db5c2
commit
d550a62fe3
|
@ -33,14 +33,8 @@ import org.apache.http.annotation.NotThreadSafe;
|
|||
|
||||
/**
|
||||
* A stream wrapper that triggers actions on {@link #close close()} and EOF.
|
||||
* Primarily used to auto-release an underlying
|
||||
* {@link ManagedClientConnection connection}
|
||||
* when the response body is consumed or no longer needed.
|
||||
* <p>
|
||||
* This class is based on <code>AutoCloseInputStream</code> in HttpClient 3.1,
|
||||
* but has notable differences. It does not allow mark/reset, distinguishes
|
||||
* different kinds of event, and does not always close the underlying stream
|
||||
* on EOF. That decision is left to the {@link EofSensorWatcher watcher}.
|
||||
* Primarily used to auto-release an underlying managed connection when the response
|
||||
* body is consumed or no longer needed.
|
||||
*
|
||||
* @see EofSensorWatcher
|
||||
*
|
||||
|
@ -87,15 +81,21 @@ public class EofSensorInputStream extends InputStream implements ConnectionRelea
|
|||
public EofSensorInputStream(final InputStream in,
|
||||
final EofSensorWatcher watcher) {
|
||||
if (in == null) {
|
||||
throw new IllegalArgumentException
|
||||
("Wrapped stream may not be null.");
|
||||
throw new IllegalArgumentException("Wrapped stream may not be null");
|
||||
}
|
||||
|
||||
wrappedStream = in;
|
||||
selfClosed = false;
|
||||
eofWatcher = watcher;
|
||||
}
|
||||
|
||||
boolean isSelfClosed() {
|
||||
return selfClosed;
|
||||
}
|
||||
|
||||
InputStream getWrappedStream() {
|
||||
return wrappedStream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the underlying stream can be read from.
|
||||
*
|
||||
|
@ -148,18 +148,7 @@ public class EofSensorInputStream extends InputStream implements ConnectionRelea
|
|||
|
||||
@Override
|
||||
public int read(byte[] b) throws IOException {
|
||||
int l = -1;
|
||||
|
||||
if (isReadAllowed()) {
|
||||
try {
|
||||
l = wrappedStream.read(b);
|
||||
checkEOF(l);
|
||||
} catch (IOException ex) {
|
||||
checkAbort();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
return l;
|
||||
return read(b, 0, b.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -95,8 +95,22 @@ class ConnectionReleaseTriggerImpl implements ConnectionReleaseTrigger, Cancella
|
|||
return;
|
||||
}
|
||||
this.released = true;
|
||||
this.manager.releaseConnection(this.managedConn,
|
||||
this.state, this.validDuration, this.tunit);
|
||||
if (this.reusable) {
|
||||
this.manager.releaseConnection(this.managedConn,
|
||||
this.state, this.validDuration, this.tunit);
|
||||
} else {
|
||||
try {
|
||||
this.managedConn.close();
|
||||
log.debug("Connection discarded");
|
||||
} catch (IOException ex) {
|
||||
if (this.log.isDebugEnabled()) {
|
||||
this.log.debug(ex.getMessage(), ex);
|
||||
}
|
||||
} finally {
|
||||
this.manager.releaseConnection(
|
||||
this.managedConn, null, 0, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,11 +27,7 @@
|
|||
|
||||
package org.apache.http.impl.client.builder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import org.apache.http.annotation.NotThreadSafe;
|
||||
|
||||
|
@ -44,10 +40,8 @@ import org.apache.http.ProtocolException;
|
|||
import org.apache.http.ProtocolVersion;
|
||||
import org.apache.http.RequestLine;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.entity.HttpEntityWrapper;
|
||||
import org.apache.http.message.AbstractHttpMessage;
|
||||
import org.apache.http.message.BasicRequestLine;
|
||||
import org.apache.http.params.HttpProtocolParams;
|
||||
import org.apache.http.protocol.HTTP;
|
||||
|
||||
/**
|
||||
|
@ -62,34 +56,22 @@ class HttpRequestWrapper extends AbstractHttpMessage implements HttpRequest {
|
|||
private final HttpRequest original;
|
||||
|
||||
private URI uri;
|
||||
private String method;
|
||||
private ProtocolVersion version;
|
||||
private HttpHost virtualHost;
|
||||
|
||||
private HttpRequestWrapper(
|
||||
final ProtocolVersion version,
|
||||
final URI uri,
|
||||
final String method,
|
||||
final HttpRequest request) {
|
||||
private HttpRequestWrapper(final HttpRequest request) {
|
||||
super();
|
||||
this.original = request;
|
||||
this.uri = uri;
|
||||
this.method = method;
|
||||
this.version = version;
|
||||
if (request instanceof HttpUriRequest) {
|
||||
this.uri = ((HttpUriRequest) request).getURI();
|
||||
} else {
|
||||
this.uri = null;
|
||||
}
|
||||
setParams(request.getParams());
|
||||
setHeaders(request.getAllHeaders());
|
||||
}
|
||||
|
||||
public ProtocolVersion getProtocolVersion() {
|
||||
if (this.version != null) {
|
||||
return this.version;
|
||||
} else {
|
||||
return HttpProtocolParams.getVersion(getParams());
|
||||
}
|
||||
}
|
||||
|
||||
public void setProtocolVersion(final ProtocolVersion version) {
|
||||
this.version = version;
|
||||
return this.original.getProtocolVersion();
|
||||
}
|
||||
|
||||
public URI getURI() {
|
||||
|
@ -101,18 +83,18 @@ class HttpRequestWrapper extends AbstractHttpMessage implements HttpRequest {
|
|||
}
|
||||
|
||||
public RequestLine getRequestLine() {
|
||||
ProtocolVersion version = this.original.getRequestLine().getProtocolVersion();
|
||||
String method = this.original.getRequestLine().getMethod();
|
||||
String uritext = null;
|
||||
if (this.uri != null) {
|
||||
uritext = uri.toASCIIString();
|
||||
uritext = this.uri.toASCIIString();
|
||||
} else {
|
||||
uritext = this.original.getRequestLine().getUri();
|
||||
}
|
||||
if (uritext == null || uritext.length() == 0) {
|
||||
uritext = "/";
|
||||
}
|
||||
return new BasicRequestLine(this.method, uritext, getProtocolVersion());
|
||||
}
|
||||
|
||||
public String getMethod() {
|
||||
return this.method;
|
||||
return new BasicRequestLine(method, uritext, version);
|
||||
}
|
||||
|
||||
public HttpRequest getOriginal() {
|
||||
|
@ -133,22 +115,17 @@ class HttpRequestWrapper extends AbstractHttpMessage implements HttpRequest {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.method + " " + this.uri + " " + this.headergroup;
|
||||
return getRequestLine() + " " + this.headergroup;
|
||||
}
|
||||
|
||||
static class HttpEntityEnclosingRequestWrapper extends HttpRequestWrapper
|
||||
implements HttpEntityEnclosingRequest {
|
||||
|
||||
private HttpEntity entity;
|
||||
private boolean consumed;
|
||||
|
||||
public HttpEntityEnclosingRequestWrapper(
|
||||
final ProtocolVersion version,
|
||||
final URI uri,
|
||||
final String method,
|
||||
final HttpEntityEnclosingRequest request)
|
||||
public HttpEntityEnclosingRequestWrapper(final HttpEntityEnclosingRequest request)
|
||||
throws ProtocolException {
|
||||
super(version, uri, method, request);
|
||||
super(request);
|
||||
setEntity(request.getEntity());
|
||||
}
|
||||
|
||||
|
@ -157,7 +134,7 @@ class HttpRequestWrapper extends AbstractHttpMessage implements HttpRequest {
|
|||
}
|
||||
|
||||
public void setEntity(final HttpEntity entity) {
|
||||
this.entity = entity != null ? new EntityWrapper(entity) : null;
|
||||
this.entity = entity != null ? new RequestEntityWrapper(entity) : null;
|
||||
}
|
||||
|
||||
public boolean expectContinue() {
|
||||
|
@ -167,32 +144,7 @@ class HttpRequestWrapper extends AbstractHttpMessage implements HttpRequest {
|
|||
|
||||
@Override
|
||||
public boolean isRepeatable() {
|
||||
return this.entity == null || this.entity.isRepeatable() || !this.consumed;
|
||||
}
|
||||
|
||||
class EntityWrapper extends HttpEntityWrapper {
|
||||
|
||||
EntityWrapper(final HttpEntity entity) {
|
||||
super(entity);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public void consumeContent() throws IOException {
|
||||
consumed = true;
|
||||
super.consumeContent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getContent() throws IOException {
|
||||
return super.getContent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(final OutputStream outstream) throws IOException {
|
||||
consumed = true;
|
||||
super.writeTo(outstream);
|
||||
}
|
||||
return this.entity == null || this.entity.isRepeatable();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -201,28 +153,10 @@ class HttpRequestWrapper extends AbstractHttpMessage implements HttpRequest {
|
|||
if (request == null) {
|
||||
return null;
|
||||
}
|
||||
ProtocolVersion version;
|
||||
URI uri;
|
||||
String method;
|
||||
if (request instanceof HttpUriRequest) {
|
||||
version = ((HttpUriRequest) request).getProtocolVersion();
|
||||
uri = ((HttpUriRequest) request).getURI();
|
||||
method = ((HttpUriRequest) request).getMethod();
|
||||
} else {
|
||||
RequestLine requestLine = request.getRequestLine();
|
||||
version = request.getProtocolVersion();
|
||||
try {
|
||||
uri = new URI(requestLine.getUri());
|
||||
} catch (URISyntaxException ex) {
|
||||
throw new ProtocolException("Invalid request URI: " + requestLine.getUri(), ex);
|
||||
}
|
||||
method = request.getRequestLine().getMethod();
|
||||
}
|
||||
if (request instanceof HttpEntityEnclosingRequest) {
|
||||
return new HttpEntityEnclosingRequestWrapper(version, uri, method,
|
||||
(HttpEntityEnclosingRequest) request);
|
||||
return new HttpEntityEnclosingRequestWrapper((HttpEntityEnclosingRequest) request);
|
||||
} else {
|
||||
return new HttpRequestWrapper(version, uri, method, request);
|
||||
return new HttpRequestWrapper(request);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -78,23 +78,25 @@ class ProtocolExec implements ClientExecChain {
|
|||
final HttpRoute route) throws ProtocolException {
|
||||
try {
|
||||
URI uri = request.getURI();
|
||||
if (route.getProxyHost() != null && !route.isTunnelled()) {
|
||||
// Make sure the request URI is absolute
|
||||
if (!uri.isAbsolute()) {
|
||||
HttpHost target = route.getTargetHost();
|
||||
uri = URIUtils.rewriteURI(uri, target, true);
|
||||
if (uri != null) {
|
||||
if (route.getProxyHost() != null && !route.isTunnelled()) {
|
||||
// Make sure the request URI is absolute
|
||||
if (!uri.isAbsolute()) {
|
||||
HttpHost target = route.getTargetHost();
|
||||
uri = URIUtils.rewriteURI(uri, target, true);
|
||||
} else {
|
||||
uri = URIUtils.rewriteURI(uri);
|
||||
}
|
||||
} else {
|
||||
uri = URIUtils.rewriteURI(uri);
|
||||
}
|
||||
} else {
|
||||
// Make sure the request URI is relative
|
||||
if (uri.isAbsolute()) {
|
||||
uri = URIUtils.rewriteURI(uri, null);
|
||||
} else {
|
||||
uri = URIUtils.rewriteURI(uri);
|
||||
// Make sure the request URI is relative
|
||||
if (uri.isAbsolute()) {
|
||||
uri = URIUtils.rewriteURI(uri, null);
|
||||
} else {
|
||||
uri = URIUtils.rewriteURI(uri);
|
||||
}
|
||||
}
|
||||
request.setURI(uri);
|
||||
}
|
||||
request.setURI(uri);
|
||||
} catch (URISyntaxException ex) {
|
||||
throw new ProtocolException("Invalid URI: " +
|
||||
request.getRequestLine().getUri(), ex);
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
package org.apache.http.impl.client.builder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.annotation.NotThreadSafe;
|
||||
import org.apache.http.entity.HttpEntityWrapper;
|
||||
|
||||
/**
|
||||
* A wrapper class for {@link HttpEntity} enclosed in a request message.
|
||||
*
|
||||
* @since 4.3
|
||||
*/
|
||||
@NotThreadSafe
|
||||
class RequestEntityWrapper extends HttpEntityWrapper {
|
||||
|
||||
private boolean consumed = false;
|
||||
|
||||
RequestEntityWrapper(final HttpEntity entity) {
|
||||
super(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRepeatable() {
|
||||
if (!this.consumed) {
|
||||
return true;
|
||||
} else {
|
||||
return super.isRepeatable();
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public void consumeContent() throws IOException {
|
||||
consumed = true;
|
||||
super.consumeContent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(final OutputStream outstream) throws IOException {
|
||||
consumed = true;
|
||||
super.writeTo(outstream);
|
||||
}
|
||||
|
||||
public boolean isConsumed() {
|
||||
return consumed;
|
||||
}
|
||||
|
||||
}
|
|
@ -37,10 +37,9 @@ import org.apache.http.annotation.NotThreadSafe;
|
|||
import org.apache.http.conn.EofSensorInputStream;
|
||||
import org.apache.http.conn.EofSensorWatcher;
|
||||
import org.apache.http.entity.HttpEntityWrapper;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
|
||||
/**
|
||||
* A wrapper class for {@link HttpEntity} encloded in a response message.
|
||||
* A wrapper class for {@link HttpEntity} enclosed in a response message.
|
||||
*
|
||||
* @since 4.3
|
||||
*/
|
||||
|
@ -66,7 +65,6 @@ class ResponseEntityWrapper extends HttpEntityWrapper implements EofSensorWatche
|
|||
if (this.connReleaseTrigger != null) {
|
||||
try {
|
||||
if (this.connReleaseTrigger.isReusable()) {
|
||||
EntityUtils.consume(this.wrappedEntity);
|
||||
this.connReleaseTrigger.releaseConnection();
|
||||
}
|
||||
} finally {
|
||||
|
@ -93,8 +91,12 @@ class ResponseEntityWrapper extends HttpEntityWrapper implements EofSensorWatche
|
|||
|
||||
@Override
|
||||
public void writeTo(final OutputStream outstream) throws IOException {
|
||||
this.wrappedEntity.writeTo(outstream);
|
||||
releaseConnection();
|
||||
try {
|
||||
this.wrappedEntity.writeTo(outstream);
|
||||
releaseConnection();
|
||||
} finally {
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean eofDetected(final InputStream wrapped) throws IOException {
|
||||
|
|
|
@ -0,0 +1,227 @@
|
|||
/*
|
||||
* ====================================================================
|
||||
*
|
||||
* 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.conn;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
public class TestEofSensorInputStream {
|
||||
|
||||
private InputStream instream;
|
||||
private EofSensorWatcher eofwatcher;
|
||||
private EofSensorInputStream eofstream;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
instream = Mockito.mock(InputStream.class);
|
||||
eofwatcher = Mockito.mock(EofSensorWatcher.class);
|
||||
eofstream = new EofSensorInputStream(instream, eofwatcher);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClose() throws Exception {
|
||||
Mockito.when(eofwatcher.streamClosed(Mockito.<InputStream>any())).thenReturn(true);
|
||||
|
||||
eofstream.close();
|
||||
|
||||
Assert.assertTrue(eofstream.isSelfClosed());
|
||||
Assert.assertNull(eofstream.getWrappedStream());
|
||||
|
||||
Mockito.verify(instream, Mockito.times(1)).close();
|
||||
Mockito.verify(eofwatcher).streamClosed(instream);
|
||||
|
||||
eofstream.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCloseIOError() throws Exception {
|
||||
Mockito.when(eofwatcher.streamClosed(Mockito.<InputStream>any())).thenThrow(new IOException());
|
||||
|
||||
try {
|
||||
eofstream.close();
|
||||
Assert.fail("IOException expected");
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
Assert.assertTrue(eofstream.isSelfClosed());
|
||||
Assert.assertNull(eofstream.getWrappedStream());
|
||||
|
||||
Mockito.verify(eofwatcher).streamClosed(instream);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReleaseConnection() throws Exception {
|
||||
Mockito.when(eofwatcher.streamClosed(Mockito.<InputStream>any())).thenReturn(true);
|
||||
|
||||
eofstream.releaseConnection();
|
||||
|
||||
Assert.assertTrue(eofstream.isSelfClosed());
|
||||
Assert.assertNull(eofstream.getWrappedStream());
|
||||
|
||||
Mockito.verify(instream, Mockito.times(1)).close();
|
||||
Mockito.verify(eofwatcher).streamClosed(instream);
|
||||
|
||||
eofstream.releaseConnection();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAbortConnection() throws Exception {
|
||||
Mockito.when(eofwatcher.streamAbort(Mockito.<InputStream>any())).thenReturn(true);
|
||||
|
||||
eofstream.abortConnection();
|
||||
|
||||
Assert.assertTrue(eofstream.isSelfClosed());
|
||||
Assert.assertNull(eofstream.getWrappedStream());
|
||||
|
||||
Mockito.verify(instream, Mockito.times(1)).close();
|
||||
Mockito.verify(eofwatcher).streamAbort(instream);
|
||||
|
||||
eofstream.abortConnection();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAbortConnectionIOError() throws Exception {
|
||||
Mockito.when(eofwatcher.streamAbort(Mockito.<InputStream>any())).thenThrow(new IOException());
|
||||
|
||||
try {
|
||||
eofstream.abortConnection();
|
||||
Assert.fail("IOException expected");
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
Assert.assertTrue(eofstream.isSelfClosed());
|
||||
Assert.assertNull(eofstream.getWrappedStream());
|
||||
|
||||
Mockito.verify(eofwatcher).streamAbort(instream);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRead() throws Exception {
|
||||
Mockito.when(eofwatcher.eofDetected(Mockito.<InputStream>any())).thenReturn(true);
|
||||
Mockito.when(instream.read()).thenReturn(0, -1);
|
||||
|
||||
Assert.assertEquals(0, eofstream.read());
|
||||
|
||||
Assert.assertFalse(eofstream.isSelfClosed());
|
||||
Assert.assertNotNull(eofstream.getWrappedStream());
|
||||
|
||||
Mockito.verify(eofwatcher, Mockito.never()).eofDetected(instream);
|
||||
|
||||
Assert.assertEquals(-1, eofstream.read());
|
||||
|
||||
Assert.assertFalse(eofstream.isSelfClosed());
|
||||
Assert.assertNull(eofstream.getWrappedStream());
|
||||
|
||||
Mockito.verify(instream, Mockito.times(1)).close();
|
||||
Mockito.verify(eofwatcher).eofDetected(instream);
|
||||
|
||||
Assert.assertEquals(-1, eofstream.read());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadIOError() throws Exception {
|
||||
Mockito.when(eofwatcher.eofDetected(Mockito.<InputStream>any())).thenReturn(true);
|
||||
Mockito.when(instream.read()).thenThrow(new IOException());
|
||||
|
||||
try {
|
||||
eofstream.read();
|
||||
Assert.fail("IOException expected");
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
Assert.assertFalse(eofstream.isSelfClosed());
|
||||
Assert.assertNull(eofstream.getWrappedStream());
|
||||
|
||||
Mockito.verify(eofwatcher).streamAbort(instream);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadByteArray() throws Exception {
|
||||
Mockito.when(eofwatcher.eofDetected(Mockito.<InputStream>any())).thenReturn(true);
|
||||
Mockito.when(instream.read(Mockito.<byte []>any(), Mockito.anyInt(), Mockito.anyInt()))
|
||||
.thenReturn(1, -1);
|
||||
|
||||
byte[] tmp = new byte[1];
|
||||
|
||||
Assert.assertEquals(1, eofstream.read(tmp));
|
||||
|
||||
Assert.assertFalse(eofstream.isSelfClosed());
|
||||
Assert.assertNotNull(eofstream.getWrappedStream());
|
||||
|
||||
Mockito.verify(eofwatcher, Mockito.never()).eofDetected(instream);
|
||||
|
||||
Assert.assertEquals(-1, eofstream.read(tmp));
|
||||
|
||||
Assert.assertFalse(eofstream.isSelfClosed());
|
||||
Assert.assertNull(eofstream.getWrappedStream());
|
||||
|
||||
Mockito.verify(instream, Mockito.times(1)).close();
|
||||
Mockito.verify(eofwatcher).eofDetected(instream);
|
||||
|
||||
Assert.assertEquals(-1, eofstream.read(tmp));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadByteArrayIOError() throws Exception {
|
||||
Mockito.when(eofwatcher.eofDetected(Mockito.<InputStream>any())).thenReturn(true);
|
||||
Mockito.when(instream.read(Mockito.<byte []>any(), Mockito.anyInt(), Mockito.anyInt()))
|
||||
.thenThrow(new IOException());
|
||||
|
||||
byte[] tmp = new byte[1];
|
||||
try {
|
||||
eofstream.read(tmp);
|
||||
Assert.fail("IOException expected");
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
Assert.assertFalse(eofstream.isSelfClosed());
|
||||
Assert.assertNull(eofstream.getWrappedStream());
|
||||
|
||||
Mockito.verify(eofwatcher).streamAbort(instream);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadAfterAbort() throws Exception {
|
||||
Mockito.when(eofwatcher.streamAbort(Mockito.<InputStream>any())).thenReturn(true);
|
||||
|
||||
eofstream.abortConnection();
|
||||
|
||||
try {
|
||||
eofstream.read();
|
||||
Assert.fail("IOException expected");
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
byte[] tmp = new byte[1];
|
||||
try {
|
||||
eofstream.read(tmp);
|
||||
Assert.fail("IOException expected");
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* ====================================================================
|
||||
*
|
||||
* 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.client.builder;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.http.HttpClientConnection;
|
||||
import org.apache.http.conn.HttpClientConnectionManager;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
public class TestConnectionReleaseTriggerImpl {
|
||||
|
||||
private Log log;
|
||||
private HttpClientConnectionManager mgr;
|
||||
private HttpClientConnection conn;
|
||||
private ConnectionReleaseTriggerImpl releaseTrigger;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
log = Mockito.mock(Log.class);
|
||||
mgr = Mockito.mock(HttpClientConnectionManager.class);
|
||||
conn = Mockito.mock(HttpClientConnection.class);
|
||||
releaseTrigger = new ConnectionReleaseTriggerImpl(log, mgr, conn);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAbortConnection() throws Exception {
|
||||
releaseTrigger.abortConnection();
|
||||
|
||||
Assert.assertTrue(releaseTrigger.isReleased());
|
||||
|
||||
Mockito.verify(conn).shutdown();
|
||||
Mockito.verify(mgr).releaseConnection(conn, null, 0, TimeUnit.MILLISECONDS);
|
||||
|
||||
releaseTrigger.abortConnection();
|
||||
|
||||
Mockito.verify(conn, Mockito.times(1)).shutdown();
|
||||
Mockito.verify(mgr, Mockito.times(1)).releaseConnection(
|
||||
Mockito.<HttpClientConnection>any(),
|
||||
Mockito.anyObject(),
|
||||
Mockito.anyLong(),
|
||||
Mockito.<TimeUnit>any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAbortConnectionIOError() throws Exception {
|
||||
Mockito.doThrow(new IOException()).when(conn).shutdown();
|
||||
|
||||
releaseTrigger.abortConnection();
|
||||
|
||||
Assert.assertTrue(releaseTrigger.isReleased());
|
||||
|
||||
Mockito.verify(conn).shutdown();
|
||||
Mockito.verify(mgr).releaseConnection(conn, null, 0, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCancell() throws Exception {
|
||||
Assert.assertTrue(releaseTrigger.cancel());
|
||||
|
||||
Assert.assertTrue(releaseTrigger.isReleased());
|
||||
|
||||
Mockito.verify(conn).shutdown();
|
||||
Mockito.verify(mgr).releaseConnection(conn, null, 0, TimeUnit.MILLISECONDS);
|
||||
|
||||
Assert.assertFalse(releaseTrigger.cancel());
|
||||
|
||||
Mockito.verify(conn, Mockito.times(1)).shutdown();
|
||||
Mockito.verify(mgr, Mockito.times(1)).releaseConnection(
|
||||
Mockito.<HttpClientConnection>any(),
|
||||
Mockito.anyObject(),
|
||||
Mockito.anyLong(),
|
||||
Mockito.<TimeUnit>any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReleaseConnectionReusable() throws Exception {
|
||||
releaseTrigger.setState("some state");
|
||||
releaseTrigger.setValidFor(100, TimeUnit.SECONDS);
|
||||
releaseTrigger.markReusable();
|
||||
|
||||
releaseTrigger.releaseConnection();
|
||||
|
||||
Assert.assertTrue(releaseTrigger.isReleased());
|
||||
|
||||
Mockito.verify(conn, Mockito.never()).close();
|
||||
Mockito.verify(mgr).releaseConnection(conn, "some state", 100, TimeUnit.SECONDS);
|
||||
|
||||
releaseTrigger.releaseConnection();
|
||||
|
||||
Mockito.verify(mgr, Mockito.times(1)).releaseConnection(
|
||||
Mockito.<HttpClientConnection>any(),
|
||||
Mockito.anyObject(),
|
||||
Mockito.anyLong(),
|
||||
Mockito.<TimeUnit>any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReleaseConnectionNonReusable() throws Exception {
|
||||
releaseTrigger.setState("some state");
|
||||
releaseTrigger.setValidFor(100, TimeUnit.SECONDS);
|
||||
releaseTrigger.markNonReusable();
|
||||
|
||||
releaseTrigger.releaseConnection();
|
||||
|
||||
Assert.assertTrue(releaseTrigger.isReleased());
|
||||
|
||||
Mockito.verify(conn, Mockito.times(1)).close();
|
||||
Mockito.verify(mgr).releaseConnection(conn, null, 0, TimeUnit.MILLISECONDS);
|
||||
|
||||
releaseTrigger.releaseConnection();
|
||||
|
||||
Mockito.verify(mgr, Mockito.times(1)).releaseConnection(
|
||||
Mockito.<HttpClientConnection>any(),
|
||||
Mockito.anyObject(),
|
||||
Mockito.anyLong(),
|
||||
Mockito.<TimeUnit>any());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* ====================================================================
|
||||
*
|
||||
* 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.client.builder;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
public class TestRequestEntityWrapper {
|
||||
|
||||
private HttpEntity entity;
|
||||
private RequestEntityWrapper wrapper;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
entity = Mockito.mock(HttpEntity.class);;
|
||||
wrapper = new RequestEntityWrapper(entity);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonRepeatableEntityWriteTo() throws Exception {
|
||||
Mockito.when(entity.isRepeatable()).thenReturn(false);
|
||||
|
||||
Assert.assertTrue(wrapper.isRepeatable());
|
||||
|
||||
OutputStream outstream = Mockito.mock(OutputStream.class);
|
||||
wrapper.writeTo(outstream);
|
||||
|
||||
Assert.assertTrue(wrapper.isConsumed());
|
||||
Assert.assertFalse(wrapper.isRepeatable());
|
||||
|
||||
Mockito.verify(entity).writeTo(outstream);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* ====================================================================
|
||||
*
|
||||
* 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.client.builder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.SocketException;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
public class TestResponseEntityWrapper {
|
||||
|
||||
private InputStream instream;
|
||||
private HttpEntity entity;
|
||||
private ConnectionReleaseTriggerImpl releaseTrigger;
|
||||
private ResponseEntityWrapper wrapper;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
instream = Mockito.mock(InputStream.class);
|
||||
entity = Mockito.mock(HttpEntity.class);;
|
||||
Mockito.when(entity.getContent()).thenReturn(instream);
|
||||
releaseTrigger = Mockito.mock(ConnectionReleaseTriggerImpl.class);
|
||||
wrapper = new ResponseEntityWrapper(entity, releaseTrigger);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReusableEntityStreamClosed() throws Exception {
|
||||
Mockito.when(entity.isStreaming()).thenReturn(true);
|
||||
Mockito.when(releaseTrigger.isReusable()).thenReturn(true);
|
||||
EntityUtils.consume(wrapper);
|
||||
|
||||
Mockito.verify(instream, Mockito.times(1)).close();
|
||||
Mockito.verify(releaseTrigger).releaseConnection();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReusableEntityStreamClosedIOError() throws Exception {
|
||||
Mockito.when(entity.isStreaming()).thenReturn(true);
|
||||
Mockito.when(releaseTrigger.isReusable()).thenReturn(true);
|
||||
Mockito.doThrow(new IOException()).when(instream).close();
|
||||
try {
|
||||
EntityUtils.consume(wrapper);
|
||||
Assert.fail("IOException expected");
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
Mockito.verify(releaseTrigger).abortConnection();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEntityStreamClosedIOErrorAlreadyReleased() throws Exception {
|
||||
Mockito.when(entity.isStreaming()).thenReturn(true);
|
||||
Mockito.when(releaseTrigger.isReusable()).thenReturn(true);
|
||||
Mockito.when(releaseTrigger.isReleased()).thenReturn(true);
|
||||
Mockito.doThrow(new SocketException()).when(instream).close();
|
||||
EntityUtils.consume(wrapper);
|
||||
Mockito.verify(releaseTrigger).abortConnection();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReusableEntityWriteTo() throws Exception {
|
||||
OutputStream outstream = Mockito.mock(OutputStream.class);
|
||||
Mockito.when(entity.isStreaming()).thenReturn(true);
|
||||
Mockito.when(releaseTrigger.isReusable()).thenReturn(true);
|
||||
wrapper.writeTo(outstream);
|
||||
Mockito.verify(releaseTrigger).releaseConnection();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReusableEntityWriteToIOError() throws Exception {
|
||||
OutputStream outstream = Mockito.mock(OutputStream.class);
|
||||
Mockito.when(entity.isStreaming()).thenReturn(true);
|
||||
Mockito.when(releaseTrigger.isReusable()).thenReturn(true);
|
||||
Mockito.doThrow(new IOException()).when(entity).writeTo(outstream);
|
||||
try {
|
||||
wrapper.writeTo(outstream);
|
||||
Assert.fail("IOException expected");
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
Mockito.verify(releaseTrigger, Mockito.never()).releaseConnection();
|
||||
Mockito.verify(releaseTrigger).abortConnection();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReusableEntityEndOfStream() throws Exception {
|
||||
Mockito.when(instream.read()).thenReturn(-1);
|
||||
Mockito.when(entity.isStreaming()).thenReturn(true);
|
||||
Mockito.when(releaseTrigger.isReusable()).thenReturn(true);
|
||||
InputStream content = wrapper.getContent();
|
||||
Assert.assertEquals(-1, content.read());
|
||||
Mockito.verify(instream).close();
|
||||
Mockito.verify(releaseTrigger).releaseConnection();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReusableEntityEndOfStreamIOError() throws Exception {
|
||||
Mockito.when(instream.read()).thenReturn(-1);
|
||||
Mockito.when(entity.isStreaming()).thenReturn(true);
|
||||
Mockito.when(releaseTrigger.isReusable()).thenReturn(true);
|
||||
Mockito.doThrow(new IOException()).when(instream).close();
|
||||
InputStream content = wrapper.getContent();
|
||||
try {
|
||||
content.read();
|
||||
Assert.fail("IOException expected");
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
Mockito.verify(releaseTrigger).abortConnection();
|
||||
}
|
||||
|
||||
}
|
|
@ -25,7 +25,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
package org.apache.http.conn;
|
||||
package org.apache.http.impl.client.integration;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
Loading…
Reference in New Issue