HTTPCLIENT-1244: Replaced EasyMock with Mockito in the HTTP cache unit tests
This commit is contained in:
parent
d77112f608
commit
760795b6df
|
@ -27,14 +27,10 @@ addons:
|
|||
- maven
|
||||
|
||||
jdk:
|
||||
- oraclejdk8
|
||||
- openjdk12
|
||||
- oraclejdk12
|
||||
- oraclejdk16
|
||||
- openjdk-ea
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- jdk: openjdk-ea
|
||||
|
||||
after_success:
|
||||
- mvn clean cobertura:cobertura coveralls:report
|
||||
|
|
|
@ -79,11 +79,6 @@
|
|||
<artifactId>mockito-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.easymock</groupId>
|
||||
<artifactId>easymock</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents.client5</groupId>
|
||||
<artifactId>httpclient5</artifactId>
|
||||
|
|
|
@ -1,186 +0,0 @@
|
|||
/*
|
||||
* ====================================================================
|
||||
* 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.hc.client5.http.impl.cache;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.apache.hc.client5.http.HttpRoute;
|
||||
import org.apache.hc.client5.http.classic.ExecChain;
|
||||
import org.apache.hc.client5.http.classic.ExecChainHandler;
|
||||
import org.apache.hc.client5.http.classic.ExecRuntime;
|
||||
import org.apache.hc.client5.http.protocol.HttpClientContext;
|
||||
import org.apache.hc.core5.http.ClassicHttpRequest;
|
||||
import org.apache.hc.core5.http.ClassicHttpResponse;
|
||||
import org.apache.hc.core5.http.HttpEntity;
|
||||
import org.apache.hc.core5.http.HttpException;
|
||||
import org.apache.hc.core5.http.HttpHost;
|
||||
import org.apache.hc.core5.http.HttpRequest;
|
||||
import org.apache.hc.core5.http.HttpResponse;
|
||||
import org.apache.hc.core5.http.io.support.ClassicRequestBuilder;
|
||||
import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
|
||||
import org.easymock.EasyMock;
|
||||
import org.easymock.IExpectationSetters;
|
||||
import org.junit.Before;
|
||||
|
||||
public abstract class AbstractProtocolTest {
|
||||
|
||||
protected static final int MAX_BYTES = 1024;
|
||||
protected static final int MAX_ENTRIES = 100;
|
||||
protected final int entityLength = 128;
|
||||
protected HttpHost host;
|
||||
protected HttpRoute route;
|
||||
protected HttpEntity body;
|
||||
protected HttpClientContext context;
|
||||
protected ExecChain mockExecChain;
|
||||
protected ExecRuntime mockExecRuntime;
|
||||
protected HttpCache mockCache;
|
||||
protected ClassicHttpRequest request;
|
||||
protected ClassicHttpResponse originResponse;
|
||||
protected CacheConfig config;
|
||||
protected ExecChainHandler impl;
|
||||
protected HttpCache cache;
|
||||
|
||||
public static ClassicHttpRequest eqRequest(final ClassicHttpRequest in) {
|
||||
EasyMock.reportMatcher(new RequestEquivalent(in));
|
||||
return null;
|
||||
}
|
||||
|
||||
public static HttpResponse eqResponse(final HttpResponse in) {
|
||||
EasyMock.reportMatcher(new ResponseEquivalent(in));
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ClassicHttpResponse eqCloseableResponse(final ClassicHttpResponse in) {
|
||||
EasyMock.reportMatcher(new ResponseEquivalent(in));
|
||||
return null;
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
host = new HttpHost("foo.example.com", 80);
|
||||
|
||||
route = new HttpRoute(host);
|
||||
|
||||
body = HttpTestUtils.makeBody(entityLength);
|
||||
|
||||
request = new BasicClassicHttpRequest("GET", "/foo");
|
||||
|
||||
context = HttpClientContext.create();
|
||||
|
||||
originResponse = HttpTestUtils.make200Response();
|
||||
|
||||
config = CacheConfig.custom()
|
||||
.setMaxCacheEntries(MAX_ENTRIES)
|
||||
.setMaxObjectSize(MAX_BYTES)
|
||||
.build();
|
||||
|
||||
cache = new BasicHttpCache(config);
|
||||
mockExecChain = EasyMock.createNiceMock(ExecChain.class);
|
||||
mockExecRuntime = EasyMock.createNiceMock(ExecRuntime.class);
|
||||
mockCache = EasyMock.createNiceMock(HttpCache.class);
|
||||
impl = createCachingExecChain(cache, config);
|
||||
}
|
||||
|
||||
public ClassicHttpResponse execute(final ClassicHttpRequest request) throws IOException, HttpException {
|
||||
return impl.execute(
|
||||
ClassicRequestBuilder.copy(request).build(),
|
||||
new ExecChain.Scope("test", route, request, mockExecRuntime, context),
|
||||
mockExecChain);
|
||||
}
|
||||
|
||||
protected ExecChainHandler createCachingExecChain(final HttpCache cache, final CacheConfig config) {
|
||||
return new CachingExec(cache, null, config);
|
||||
}
|
||||
|
||||
protected boolean supportsRangeAndContentRangeHeaders(final ExecChainHandler impl) {
|
||||
return impl instanceof CachingExec && ((CachingExec) impl).supportsRangeAndContentRangeHeaders();
|
||||
}
|
||||
|
||||
protected void replayMocks() {
|
||||
EasyMock.replay(mockExecChain);
|
||||
EasyMock.replay(mockCache);
|
||||
}
|
||||
|
||||
protected void verifyMocks() {
|
||||
EasyMock.verify(mockExecChain);
|
||||
EasyMock.verify(mockCache);
|
||||
}
|
||||
|
||||
protected IExpectationSetters<ClassicHttpResponse> backendExpectsAnyRequest() throws Exception {
|
||||
final ClassicHttpResponse resp = mockExecChain.proceed(
|
||||
EasyMock.isA(ClassicHttpRequest.class),
|
||||
EasyMock.isA(ExecChain.Scope.class));
|
||||
return EasyMock.expect(resp);
|
||||
}
|
||||
|
||||
protected IExpectationSetters<ClassicHttpResponse> backendExpectsAnyRequestAndReturn(
|
||||
final ClassicHttpResponse response) throws Exception {
|
||||
final ClassicHttpResponse resp = mockExecChain.proceed(
|
||||
EasyMock.isA(ClassicHttpRequest.class),
|
||||
EasyMock.isA(ExecChain.Scope.class));
|
||||
return EasyMock.expect(resp).andReturn(response);
|
||||
}
|
||||
|
||||
protected void emptyMockCacheExpectsNoPuts() throws Exception {
|
||||
mockExecChain = EasyMock.createNiceMock(ExecChain.class);
|
||||
mockCache = EasyMock.createNiceMock(HttpCache.class);
|
||||
|
||||
impl = new CachingExec(mockCache, null, config);
|
||||
|
||||
EasyMock.expect(mockCache.getCacheEntry(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class)))
|
||||
.andReturn(null).anyTimes();
|
||||
EasyMock.expect(mockCache.getVariantCacheEntriesWithEtags(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class)))
|
||||
.andReturn(new HashMap<>()).anyTimes();
|
||||
|
||||
mockCache.flushCacheEntriesFor(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class));
|
||||
EasyMock.expectLastCall().anyTimes();
|
||||
|
||||
mockCache.flushCacheEntriesFor(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class));
|
||||
EasyMock.expectLastCall().anyTimes();
|
||||
|
||||
mockCache.flushCacheEntriesInvalidatedByRequest(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class));
|
||||
EasyMock.expectLastCall().anyTimes();
|
||||
|
||||
mockCache.flushCacheEntriesInvalidatedByExchange(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class), EasyMock.isA(HttpResponse.class));
|
||||
EasyMock.expectLastCall().anyTimes();
|
||||
}
|
||||
|
||||
protected void behaveAsNonSharedCache() {
|
||||
config = CacheConfig.custom()
|
||||
.setMaxCacheEntries(MAX_ENTRIES)
|
||||
.setMaxObjectSize(MAX_BYTES)
|
||||
.setSharedCache(false)
|
||||
.build();
|
||||
impl = new CachingExec(cache, null, config);
|
||||
}
|
||||
|
||||
public AbstractProtocolTest() {
|
||||
super();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
* ====================================================================
|
||||
* 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.hc.client5.http.impl.cache;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.hc.client5.http.classic.ExecChain;
|
||||
import org.apache.hc.core5.http.ClassicHttpRequest;
|
||||
import org.apache.hc.core5.http.ClassicHttpResponse;
|
||||
import org.apache.hc.core5.http.HttpException;
|
||||
import org.apache.hc.core5.http.HttpRequest;
|
||||
import org.apache.hc.core5.http.HttpStatus;
|
||||
import org.apache.hc.core5.http.message.BasicClassicHttpResponse;
|
||||
|
||||
public class DummyBackend implements ExecChain {
|
||||
|
||||
private ClassicHttpRequest request;
|
||||
private ClassicHttpResponse response = new BasicClassicHttpResponse(HttpStatus.SC_OK, "OK");
|
||||
private int executions;
|
||||
|
||||
public void setResponse(final ClassicHttpResponse resp) {
|
||||
response = resp;
|
||||
}
|
||||
|
||||
public HttpRequest getCapturedRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassicHttpResponse proceed(
|
||||
final ClassicHttpRequest request,
|
||||
final Scope scope) throws IOException, HttpException {
|
||||
this.request = request;
|
||||
executions++;
|
||||
return response;
|
||||
}
|
||||
|
||||
public int getExecutions() {
|
||||
return executions;
|
||||
}
|
||||
}
|
|
@ -251,7 +251,7 @@ public class HttpTestUtils {
|
|||
}
|
||||
|
||||
public static HttpCacheEntry makeCacheEntry(final Date requestDate,
|
||||
final Date responseDate, final Header[] headers) {
|
||||
final Date responseDate, final Header... headers) {
|
||||
final byte[] bytes = getRandomBytes(128);
|
||||
return makeCacheEntry(requestDate, responseDate, headers, bytes);
|
||||
}
|
||||
|
@ -283,7 +283,7 @@ public class HttpTestUtils {
|
|||
return makeCacheEntry(getStockHeaders(new Date()), bytes);
|
||||
}
|
||||
|
||||
public static HttpCacheEntry makeCacheEntry(final Header[] headers) {
|
||||
public static HttpCacheEntry makeCacheEntry(final Header... headers) {
|
||||
return makeCacheEntry(headers, getRandomBytes(128));
|
||||
}
|
||||
|
||||
|
@ -292,27 +292,27 @@ public class HttpTestUtils {
|
|||
return makeCacheEntry(now, now);
|
||||
}
|
||||
|
||||
public static HttpCacheEntry makeCacheEntryWithNoRequestMethodOrEntity(final Header[] headers) {
|
||||
public static HttpCacheEntry makeCacheEntryWithNoRequestMethodOrEntity(final Header... headers) {
|
||||
final Date now = new Date();
|
||||
return new HttpCacheEntry(now, now, HttpStatus.SC_OK, headers, null, null);
|
||||
}
|
||||
|
||||
public static HttpCacheEntry makeCacheEntryWithNoRequestMethod(final Header[] headers) {
|
||||
public static HttpCacheEntry makeCacheEntryWithNoRequestMethod(final Header... headers) {
|
||||
final Date now = new Date();
|
||||
return new HttpCacheEntry(now, now, HttpStatus.SC_OK, headers, new HeapResource(getRandomBytes(128)), null);
|
||||
}
|
||||
|
||||
public static HttpCacheEntry make204CacheEntryWithNoRequestMethod(final Header[] headers) {
|
||||
public static HttpCacheEntry make204CacheEntryWithNoRequestMethod(final Header... headers) {
|
||||
final Date now = new Date();
|
||||
return new HttpCacheEntry(now, now, HttpStatus.SC_NO_CONTENT, headers, null, null);
|
||||
}
|
||||
|
||||
public static HttpCacheEntry makeHeadCacheEntry(final Header[] headers) {
|
||||
public static HttpCacheEntry makeHeadCacheEntry(final Header... headers) {
|
||||
final Date now = new Date();
|
||||
return new HttpCacheEntry(now, now, HttpStatus.SC_OK, headers, null, null);
|
||||
}
|
||||
|
||||
public static HttpCacheEntry makeHeadCacheEntryWithNoRequestMethod(final Header[] headers) {
|
||||
public static HttpCacheEntry makeHeadCacheEntryWithNoRequestMethod(final Header... headers) {
|
||||
final Date now = new Date();
|
||||
return new HttpCacheEntry(now, now, HttpStatus.SC_OK, headers, null, null);
|
||||
}
|
||||
|
|
|
@ -27,30 +27,27 @@
|
|||
package org.apache.hc.client5.http.impl.cache;
|
||||
|
||||
import org.apache.hc.core5.http.HttpRequest;
|
||||
import org.easymock.IArgumentMatcher;
|
||||
import org.mockito.ArgumentMatcher;
|
||||
import org.mockito.ArgumentMatchers;
|
||||
|
||||
public class RequestEquivalent implements IArgumentMatcher {
|
||||
public class RequestEquivalent<T extends HttpRequest> implements ArgumentMatcher<T> {
|
||||
|
||||
private final HttpRequest expected;
|
||||
private final T expected;
|
||||
|
||||
public RequestEquivalent(final HttpRequest expected) {
|
||||
public RequestEquivalent(final T expected) {
|
||||
this.expected = expected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(final Object actual) {
|
||||
if (!(actual instanceof HttpRequest)) {
|
||||
public boolean matches(final T argument) {
|
||||
if (argument == null) {
|
||||
return false;
|
||||
}
|
||||
final HttpRequest other = (HttpRequest) actual;
|
||||
return HttpTestUtils.equivalent(expected, other);
|
||||
return HttpTestUtils.equivalent(expected, argument);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendTo(final StringBuffer buf) {
|
||||
buf.append("eqRequest(");
|
||||
buf.append(expected);
|
||||
buf.append(")");
|
||||
public static <T extends HttpRequest> T eq(final T request) {
|
||||
return ArgumentMatchers.argThat(new RequestEquivalent<>(request));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,30 +27,27 @@
|
|||
package org.apache.hc.client5.http.impl.cache;
|
||||
|
||||
import org.apache.hc.core5.http.HttpResponse;
|
||||
import org.easymock.IArgumentMatcher;
|
||||
import org.mockito.ArgumentMatcher;
|
||||
import org.mockito.ArgumentMatchers;
|
||||
|
||||
public class ResponseEquivalent implements IArgumentMatcher {
|
||||
public class ResponseEquivalent<T extends HttpResponse> implements ArgumentMatcher<T> {
|
||||
|
||||
private final HttpResponse expected;
|
||||
private final T expected;
|
||||
|
||||
public ResponseEquivalent(final HttpResponse expected) {
|
||||
public ResponseEquivalent(final T expected) {
|
||||
this.expected = expected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(final Object actual) {
|
||||
if (!(actual instanceof HttpResponse)) {
|
||||
public boolean matches(final T argument) {
|
||||
if (argument == null) {
|
||||
return false;
|
||||
}
|
||||
final HttpResponse other = (HttpResponse) actual;
|
||||
return HttpTestUtils.equivalent(expected, other);
|
||||
return HttpTestUtils.equivalent(expected, argument);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendTo(final StringBuffer buf) {
|
||||
buf.append("eqRequest(");
|
||||
buf.append(expected);
|
||||
buf.append(")");
|
||||
public static <T extends HttpResponse> T eq(final T response) {
|
||||
return ArgumentMatchers.argThat(new ResponseEquivalent<>(response));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,458 +0,0 @@
|
|||
/*
|
||||
* ====================================================================
|
||||
* 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.hc.client5.http.impl.cache;
|
||||
|
||||
import static org.easymock.EasyMock.anyObject;
|
||||
import static org.easymock.EasyMock.eq;
|
||||
import static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.EasyMock.isA;
|
||||
import static org.easymock.EasyMock.same;
|
||||
import static org.easymock.EasyMock.createMockBuilder;
|
||||
import static org.easymock.EasyMock.createNiceMock;
|
||||
import static org.easymock.EasyMock.replay;
|
||||
import static org.easymock.EasyMock.verify;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
|
||||
import org.apache.hc.client5.http.cache.HttpCacheEntry;
|
||||
import org.apache.hc.client5.http.classic.ExecChain;
|
||||
import org.apache.hc.client5.http.classic.methods.HttpGet;
|
||||
import org.apache.hc.client5.http.utils.DateUtils;
|
||||
import org.apache.hc.core5.http.ClassicHttpRequest;
|
||||
import org.apache.hc.core5.http.ClassicHttpResponse;
|
||||
import org.apache.hc.core5.http.HeaderElements;
|
||||
import org.apache.hc.core5.http.HttpHeaders;
|
||||
import org.apache.hc.core5.http.HttpHost;
|
||||
import org.apache.hc.core5.http.HttpRequest;
|
||||
import org.apache.hc.core5.http.HttpResponse;
|
||||
import org.apache.hc.core5.http.HttpStatus;
|
||||
import org.apache.hc.core5.http.HttpVersion;
|
||||
import org.apache.hc.core5.http.io.entity.InputStreamEntity;
|
||||
import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
|
||||
import org.apache.hc.core5.http.message.BasicClassicHttpResponse;
|
||||
import org.easymock.EasyMock;
|
||||
import org.easymock.IExpectationSetters;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
@SuppressWarnings("boxing") // test code
|
||||
public class TestCachingExec extends TestCachingExecChain {
|
||||
|
||||
private static final String GET_CURRENT_DATE = "getCurrentDate";
|
||||
|
||||
private static final String HANDLE_BACKEND_RESPONSE = "handleBackendResponse";
|
||||
|
||||
private static final String CALL_BACKEND = "callBackend";
|
||||
|
||||
private static final String REVALIDATE_CACHE_ENTRY = "revalidateCacheEntry";
|
||||
|
||||
private CachingExec impl;
|
||||
private boolean mockedImpl;
|
||||
|
||||
private ExecChain.Scope scope;
|
||||
private ClassicHttpResponse mockBackendResponse;
|
||||
|
||||
private Date requestDate;
|
||||
private Date responseDate;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() {
|
||||
super.setUp();
|
||||
|
||||
scope = new ExecChain.Scope("test", route, request, mockEndpoint, context);
|
||||
mockBackendResponse = createNiceMock(ClassicHttpResponse.class);
|
||||
|
||||
requestDate = new Date(System.currentTimeMillis() - 1000);
|
||||
responseDate = new Date();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CachingExec createCachingExecChain(
|
||||
final HttpCache mockCache, final CacheValidityPolicy mockValidityPolicy,
|
||||
final ResponseCachingPolicy mockResponsePolicy,
|
||||
final CachedHttpResponseGenerator mockResponseGenerator,
|
||||
final CacheableRequestPolicy mockRequestPolicy,
|
||||
final CachedResponseSuitabilityChecker mockSuitabilityChecker,
|
||||
final ResponseProtocolCompliance mockResponseProtocolCompliance,
|
||||
final RequestProtocolCompliance mockRequestProtocolCompliance,
|
||||
final DefaultCacheRevalidator mockCacheRevalidator,
|
||||
final ConditionalRequestBuilder<ClassicHttpRequest> mockConditionalRequestBuilder,
|
||||
final CacheConfig config) {
|
||||
return impl = new CachingExec(
|
||||
mockCache,
|
||||
mockValidityPolicy,
|
||||
mockResponsePolicy,
|
||||
mockResponseGenerator,
|
||||
mockRequestPolicy,
|
||||
mockSuitabilityChecker,
|
||||
mockResponseProtocolCompliance,
|
||||
mockRequestProtocolCompliance,
|
||||
mockCacheRevalidator,
|
||||
mockConditionalRequestBuilder,
|
||||
config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CachingExec createCachingExecChain(final HttpCache cache, final CacheConfig config) {
|
||||
return impl = new CachingExec(cache, null, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void replayMocks() {
|
||||
super.replayMocks();
|
||||
replay(mockBackendResponse);
|
||||
if (mockedImpl) {
|
||||
replay(impl);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void verifyMocks() {
|
||||
super.verifyMocks();
|
||||
verify(mockBackendResponse);
|
||||
if (mockedImpl) {
|
||||
verify(impl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testRequestThatCannotBeServedFromCacheCausesBackendRequest() throws Exception {
|
||||
cacheInvalidatorWasCalled();
|
||||
requestPolicyAllowsCaching(false);
|
||||
mockImplMethods(CALL_BACKEND);
|
||||
|
||||
implExpectsAnyRequestAndReturn(mockBackendResponse);
|
||||
requestIsFatallyNonCompliant(null);
|
||||
|
||||
replayMocks();
|
||||
final HttpResponse result = impl.execute(request, scope, mockExecChain);
|
||||
verifyMocks();
|
||||
|
||||
Assert.assertSame(mockBackendResponse, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCacheMissCausesBackendRequest() throws Exception {
|
||||
mockImplMethods(CALL_BACKEND);
|
||||
requestPolicyAllowsCaching(true);
|
||||
getCacheEntryReturns(null);
|
||||
getVariantCacheEntriesReturns(new HashMap<>());
|
||||
|
||||
requestIsFatallyNonCompliant(null);
|
||||
|
||||
implExpectsAnyRequestAndReturn(mockBackendResponse);
|
||||
|
||||
replayMocks();
|
||||
final HttpResponse result = impl.execute(request, scope, mockExecChain);
|
||||
verifyMocks();
|
||||
|
||||
Assert.assertSame(mockBackendResponse, result);
|
||||
Assert.assertEquals(1, impl.getCacheMisses());
|
||||
Assert.assertEquals(0, impl.getCacheHits());
|
||||
Assert.assertEquals(0, impl.getCacheUpdates());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsuitableUnvalidatableCacheEntryCausesBackendRequest() throws Exception {
|
||||
mockImplMethods(CALL_BACKEND);
|
||||
requestPolicyAllowsCaching(true);
|
||||
requestIsFatallyNonCompliant(null);
|
||||
|
||||
getCacheEntryReturns(mockCacheEntry);
|
||||
cacheEntrySuitable(false);
|
||||
cacheEntryValidatable(false);
|
||||
expect(mockConditionalRequestBuilder.buildConditionalRequest(request, mockCacheEntry))
|
||||
.andReturn(request);
|
||||
backendExpectsRequestAndReturn(request, mockBackendResponse);
|
||||
expect(mockBackendResponse.getVersion()).andReturn(HttpVersion.HTTP_1_1).anyTimes();
|
||||
expect(mockBackendResponse.getCode()).andReturn(200);
|
||||
|
||||
replayMocks();
|
||||
final HttpResponse result = impl.execute(request, scope, mockExecChain);
|
||||
verifyMocks();
|
||||
|
||||
Assert.assertSame(mockBackendResponse, result);
|
||||
Assert.assertEquals(0, impl.getCacheMisses());
|
||||
Assert.assertEquals(1, impl.getCacheHits());
|
||||
Assert.assertEquals(1, impl.getCacheUpdates());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsuitableValidatableCacheEntryCausesRevalidation() throws Exception {
|
||||
mockImplMethods(REVALIDATE_CACHE_ENTRY);
|
||||
requestPolicyAllowsCaching(true);
|
||||
requestIsFatallyNonCompliant(null);
|
||||
|
||||
getCacheEntryReturns(mockCacheEntry);
|
||||
cacheEntrySuitable(false);
|
||||
cacheEntryValidatable(true);
|
||||
cacheEntryMustRevalidate(false);
|
||||
cacheEntryProxyRevalidate(false);
|
||||
mayReturnStaleWhileRevalidating(false);
|
||||
|
||||
expect(impl.revalidateCacheEntry(
|
||||
isA(HttpHost.class),
|
||||
isA(ClassicHttpRequest.class),
|
||||
isA(ExecChain.Scope.class),
|
||||
isA(ExecChain.class),
|
||||
isA(HttpCacheEntry.class))).andReturn(mockBackendResponse);
|
||||
|
||||
replayMocks();
|
||||
final HttpResponse result = impl.execute(request, scope, mockExecChain);
|
||||
verifyMocks();
|
||||
|
||||
Assert.assertSame(mockBackendResponse, result);
|
||||
Assert.assertEquals(0, impl.getCacheMisses());
|
||||
Assert.assertEquals(1, impl.getCacheHits());
|
||||
Assert.assertEquals(0, impl.getCacheUpdates());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRevalidationCallsHandleBackEndResponseWhenNot200Or304() throws Exception {
|
||||
mockImplMethods(GET_CURRENT_DATE, HANDLE_BACKEND_RESPONSE);
|
||||
|
||||
final ClassicHttpRequest validate = new BasicClassicHttpRequest("GET", "/");
|
||||
final ClassicHttpResponse originResponse = new BasicClassicHttpResponse(HttpStatus.SC_NOT_FOUND, "Not Found");
|
||||
final ClassicHttpResponse finalResponse = HttpTestUtils.make200Response();
|
||||
|
||||
conditionalRequestBuilderReturns(validate);
|
||||
getCurrentDateReturns(requestDate);
|
||||
backendExpectsRequestAndReturn(validate, originResponse);
|
||||
getCurrentDateReturns(responseDate);
|
||||
expect(impl.handleBackendResponse(
|
||||
same(host),
|
||||
same(validate),
|
||||
same(scope),
|
||||
eq(requestDate),
|
||||
eq(responseDate),
|
||||
same(originResponse))).andReturn(finalResponse);
|
||||
|
||||
replayMocks();
|
||||
final HttpResponse result =
|
||||
impl.revalidateCacheEntry(host, request, scope, mockExecChain, entry);
|
||||
verifyMocks();
|
||||
|
||||
Assert.assertSame(finalResponse, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRevalidationUpdatesCacheEntryAndPutsItToCacheWhen304ReturningCachedResponse()
|
||||
throws Exception {
|
||||
|
||||
mockImplMethods(GET_CURRENT_DATE);
|
||||
|
||||
final ClassicHttpRequest validate = new BasicClassicHttpRequest("GET", "/");
|
||||
final ClassicHttpResponse originResponse = HttpTestUtils.make304Response();
|
||||
final HttpCacheEntry updatedEntry = HttpTestUtils.makeCacheEntry();
|
||||
|
||||
conditionalRequestBuilderReturns(validate);
|
||||
getCurrentDateReturns(requestDate);
|
||||
backendExpectsRequestAndReturn(validate, originResponse);
|
||||
getCurrentDateReturns(responseDate);
|
||||
expect(mockCache.updateCacheEntry(
|
||||
eq(host),
|
||||
same(request),
|
||||
same(entry),
|
||||
same(originResponse),
|
||||
eq(requestDate),
|
||||
eq(responseDate)))
|
||||
.andReturn(updatedEntry);
|
||||
expect(mockSuitabilityChecker.isConditional(request)).andReturn(false);
|
||||
responseIsGeneratedFromCache(SimpleHttpResponse.create(HttpStatus.SC_OK));
|
||||
|
||||
replayMocks();
|
||||
impl.revalidateCacheEntry(host, request, scope, mockExecChain, entry);
|
||||
verifyMocks();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRevalidationRewritesAbsoluteUri() throws Exception {
|
||||
|
||||
mockImplMethods(GET_CURRENT_DATE);
|
||||
|
||||
// Fail on an unexpected request, rather than causing a later NPE
|
||||
EasyMock.resetToStrict(mockExecChain);
|
||||
|
||||
final ClassicHttpRequest validate = new HttpGet("http://foo.example.com/resource");
|
||||
final ClassicHttpRequest relativeValidate = new BasicClassicHttpRequest("GET", "/resource");
|
||||
final ClassicHttpResponse originResponse = new BasicClassicHttpResponse(HttpStatus.SC_OK, "Okay");
|
||||
|
||||
conditionalRequestBuilderReturns(validate);
|
||||
getCurrentDateReturns(requestDate);
|
||||
|
||||
final ClassicHttpResponse resp = mockExecChain.proceed(
|
||||
eqRequest(relativeValidate), isA(ExecChain.Scope.class));
|
||||
expect(resp).andReturn(originResponse);
|
||||
|
||||
getCurrentDateReturns(responseDate);
|
||||
|
||||
replayMocks();
|
||||
impl.revalidateCacheEntry(host, request, scope, mockExecChain, entry);
|
||||
verifyMocks();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEndlessResponsesArePassedThrough() throws Exception {
|
||||
impl = createCachingExecChain(new BasicHttpCache(), CacheConfig.DEFAULT);
|
||||
|
||||
final ClassicHttpResponse resp1 = new BasicClassicHttpResponse(HttpStatus.SC_OK, "OK");
|
||||
resp1.setHeader("Date", DateUtils.formatDate(new Date()));
|
||||
resp1.setHeader("Server", "MockOrigin/1.0");
|
||||
resp1.setHeader(HttpHeaders.TRANSFER_ENCODING, HeaderElements.CHUNKED_ENCODING);
|
||||
|
||||
final AtomicInteger size = new AtomicInteger();
|
||||
final AtomicInteger maxlength = new AtomicInteger(Integer.MAX_VALUE);
|
||||
resp1.setEntity(new InputStreamEntity(new InputStream() {
|
||||
private Throwable closed;
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
closed = new Throwable();
|
||||
super.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
Thread.yield();
|
||||
if (closed != null) {
|
||||
throw new IOException("Response has been closed");
|
||||
|
||||
}
|
||||
if (size.incrementAndGet() > maxlength.get()) {
|
||||
return -1;
|
||||
}
|
||||
return 'y';
|
||||
}
|
||||
}, -1, null));
|
||||
|
||||
final ClassicHttpResponse resp = mockExecChain.proceed(
|
||||
isA(ClassicHttpRequest.class), isA(ExecChain.Scope.class));
|
||||
EasyMock.expect(resp).andReturn(resp1);
|
||||
|
||||
final ClassicHttpRequest req1 = HttpTestUtils.makeDefaultRequest();
|
||||
|
||||
replayMocks();
|
||||
final ClassicHttpResponse resp2 = impl.execute(req1, scope, mockExecChain);
|
||||
maxlength.set(size.get() * 2);
|
||||
verifyMocks();
|
||||
assertTrue(HttpTestUtils.semanticallyTransparent(resp1, resp2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCallBackendMakesBackEndRequestAndHandlesResponse() throws Exception {
|
||||
mockImplMethods(GET_CURRENT_DATE, HANDLE_BACKEND_RESPONSE);
|
||||
final ClassicHttpResponse resp = new BasicClassicHttpResponse(HttpStatus.SC_OK, "OK");
|
||||
getCurrentDateReturns(requestDate);
|
||||
backendExpectsRequestAndReturn(request, resp);
|
||||
getCurrentDateReturns(responseDate);
|
||||
handleBackendResponseReturnsResponse(request, resp);
|
||||
|
||||
replayMocks();
|
||||
|
||||
impl.callBackend(host, request, scope, mockExecChain);
|
||||
|
||||
verifyMocks();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoesNotFlushCachesOnCacheHit() throws Exception {
|
||||
requestPolicyAllowsCaching(true);
|
||||
requestIsFatallyNonCompliant(null);
|
||||
|
||||
getCacheEntryReturns(mockCacheEntry);
|
||||
doesNotFlushCache();
|
||||
cacheEntrySuitable(true);
|
||||
cacheEntryValidatable(true);
|
||||
|
||||
responseIsGeneratedFromCache(SimpleHttpResponse.create(HttpStatus.SC_OK));
|
||||
|
||||
replayMocks();
|
||||
impl.execute(request, scope, mockExecChain);
|
||||
verifyMocks();
|
||||
}
|
||||
|
||||
private IExpectationSetters<ClassicHttpResponse> implExpectsAnyRequestAndReturn(
|
||||
final ClassicHttpResponse response) throws Exception {
|
||||
final ClassicHttpResponse resp = impl.callBackend(
|
||||
same(host),
|
||||
isA(ClassicHttpRequest.class),
|
||||
isA(ExecChain.Scope.class),
|
||||
isA(ExecChain.class));
|
||||
return EasyMock.expect(resp).andReturn(response);
|
||||
}
|
||||
|
||||
private void getVariantCacheEntriesReturns(final Map<String,Variant> result) {
|
||||
expect(mockCache.getVariantCacheEntriesWithEtags(host, request)).andReturn(result);
|
||||
}
|
||||
|
||||
private void cacheInvalidatorWasCalled() {
|
||||
mockCache.flushCacheEntriesInvalidatedByRequest((HttpHost)anyObject(), (HttpRequest)anyObject());
|
||||
}
|
||||
|
||||
private void getCurrentDateReturns(final Date date) {
|
||||
expect(impl.getCurrentDate()).andReturn(date);
|
||||
}
|
||||
|
||||
private void handleBackendResponseReturnsResponse(final ClassicHttpRequest request, final ClassicHttpResponse response)
|
||||
throws IOException {
|
||||
expect(
|
||||
impl.handleBackendResponse(
|
||||
same(host),
|
||||
same(request),
|
||||
same(scope),
|
||||
isA(Date.class),
|
||||
isA(Date.class),
|
||||
isA(ClassicHttpResponse.class))).andReturn(response);
|
||||
}
|
||||
|
||||
private void mockImplMethods(final String... methods) {
|
||||
mockedImpl = true;
|
||||
impl = createMockBuilder(CachingExec.class).withConstructor(
|
||||
mockCache,
|
||||
mockValidityPolicy,
|
||||
mockResponsePolicy,
|
||||
mockResponseGenerator,
|
||||
mockRequestPolicy,
|
||||
mockSuitabilityChecker,
|
||||
mockResponseProtocolCompliance,
|
||||
mockRequestProtocolCompliance,
|
||||
mockCacheRevalidator,
|
||||
mockConditionalRequestBuilder,
|
||||
config).addMockedMethods(methods).createNiceMock();
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -26,26 +26,90 @@
|
|||
*/
|
||||
package org.apache.hc.client5.http.impl.cache;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.util.Date;
|
||||
|
||||
import org.apache.hc.client5.http.HttpRoute;
|
||||
import org.apache.hc.client5.http.classic.ExecChain;
|
||||
import org.apache.hc.client5.http.classic.ExecRuntime;
|
||||
import org.apache.hc.client5.http.protocol.HttpClientContext;
|
||||
import org.apache.hc.client5.http.utils.DateUtils;
|
||||
import org.apache.hc.core5.http.ClassicHttpRequest;
|
||||
import org.apache.hc.core5.http.ClassicHttpResponse;
|
||||
import org.apache.hc.core5.http.HttpException;
|
||||
import org.apache.hc.core5.http.HttpHost;
|
||||
import org.apache.hc.core5.http.HttpResponse;
|
||||
import org.apache.hc.core5.http.HttpStatus;
|
||||
import org.apache.hc.core5.http.io.support.ClassicRequestBuilder;
|
||||
import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
/**
|
||||
* This class tests behavior that is allowed (MAY) by the HTTP/1.1 protocol
|
||||
* specification and for which we have implemented the behavior in HTTP cache.
|
||||
*/
|
||||
public class TestProtocolAllowedBehavior extends AbstractProtocolTest {
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class TestProtocolAllowedBehavior {
|
||||
|
||||
static final int MAX_BYTES = 1024;
|
||||
static final int MAX_ENTRIES = 100;
|
||||
static final int ENTITY_LENGTH = 128;
|
||||
|
||||
HttpHost host;
|
||||
HttpRoute route;
|
||||
HttpClientContext context;
|
||||
@Mock
|
||||
ExecChain mockExecChain;
|
||||
@Mock
|
||||
ExecRuntime mockExecRuntime;
|
||||
@Mock
|
||||
HttpCache mockCache;
|
||||
ClassicHttpRequest request;
|
||||
ClassicHttpResponse originResponse;
|
||||
CacheConfig config;
|
||||
CachingExec impl;
|
||||
HttpCache cache;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
host = new HttpHost("foo.example.com", 80);
|
||||
|
||||
route = new HttpRoute(host);
|
||||
|
||||
request = new BasicClassicHttpRequest("GET", "/foo");
|
||||
|
||||
context = HttpClientContext.create();
|
||||
|
||||
originResponse = HttpTestUtils.make200Response();
|
||||
|
||||
config = CacheConfig.custom()
|
||||
.setMaxCacheEntries(MAX_ENTRIES)
|
||||
.setMaxObjectSize(MAX_BYTES)
|
||||
.setSharedCache(false)
|
||||
.build();
|
||||
|
||||
cache = new BasicHttpCache(config);
|
||||
impl = new CachingExec(cache, null, config);
|
||||
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(originResponse);
|
||||
}
|
||||
|
||||
public ClassicHttpResponse execute(final ClassicHttpRequest request) throws IOException, HttpException {
|
||||
return impl.execute(
|
||||
ClassicRequestBuilder.copy(request).build(),
|
||||
new ExecChain.Scope("test", route, request, mockExecRuntime, context),
|
||||
mockExecChain);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonSharedCacheReturnsStaleResponseWhenRevalidationFailsForProxyRevalidate()
|
||||
throws Exception {
|
||||
public void testNonSharedCacheReturnsStaleResponseWhenRevalidationFailsForProxyRevalidate() throws Exception {
|
||||
final ClassicHttpRequest req1 = new BasicClassicHttpRequest("GET","/");
|
||||
final Date now = new Date();
|
||||
final Date tenSecondsAgo = new Date(now.getTime() - 10 * 1000L);
|
||||
|
@ -53,37 +117,33 @@ public class TestProtocolAllowedBehavior extends AbstractProtocolTest {
|
|||
originResponse.setHeader("Cache-Control","max-age=5,proxy-revalidate");
|
||||
originResponse.setHeader("Etag","\"etag\"");
|
||||
|
||||
backendExpectsAnyRequest().andReturn(originResponse);
|
||||
|
||||
final ClassicHttpRequest req2 = new BasicClassicHttpRequest("GET","/");
|
||||
|
||||
backendExpectsAnyRequest().andThrow(new SocketTimeoutException());
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(originResponse);
|
||||
|
||||
replayMocks();
|
||||
behaveAsNonSharedCache();
|
||||
execute(req1);
|
||||
final HttpResponse result = execute(req2);
|
||||
verifyMocks();
|
||||
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenThrow(new SocketTimeoutException());
|
||||
|
||||
final HttpResponse result = execute(req2);
|
||||
Assert.assertEquals(HttpStatus.SC_OK, result.getCode());
|
||||
|
||||
Mockito.verifyNoInteractions(mockCache);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonSharedCacheMayCacheResponsesWithCacheControlPrivate()
|
||||
throws Exception {
|
||||
public void testNonSharedCacheMayCacheResponsesWithCacheControlPrivate() throws Exception {
|
||||
final ClassicHttpRequest req1 = new BasicClassicHttpRequest("GET","/");
|
||||
originResponse.setHeader("Cache-Control","private,max-age=3600");
|
||||
|
||||
backendExpectsAnyRequest().andReturn(originResponse);
|
||||
|
||||
final ClassicHttpRequest req2 = new BasicClassicHttpRequest("GET","/");
|
||||
|
||||
replayMocks();
|
||||
behaveAsNonSharedCache();
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(originResponse);
|
||||
|
||||
execute(req1);
|
||||
final HttpResponse result = execute(req2);
|
||||
verifyMocks();
|
||||
|
||||
Assert.assertEquals(HttpStatus.SC_OK, result.getCode());
|
||||
|
||||
Mockito.verifyNoInteractions(mockCache);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,18 +42,18 @@ import org.apache.hc.core5.http.ClassicHttpResponse;
|
|||
import org.apache.hc.core5.http.HttpEntity;
|
||||
import org.apache.hc.core5.http.HttpException;
|
||||
import org.apache.hc.core5.http.HttpHost;
|
||||
import org.apache.hc.core5.http.HttpRequest;
|
||||
import org.apache.hc.core5.http.HttpResponse;
|
||||
import org.apache.hc.core5.http.HttpStatus;
|
||||
import org.apache.hc.core5.http.io.entity.ByteArrayEntity;
|
||||
import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
|
||||
import org.apache.hc.core5.http.message.BasicClassicHttpResponse;
|
||||
import org.easymock.Capture;
|
||||
import org.easymock.EasyMock;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
/**
|
||||
* We are a conditionally-compliant HTTP/1.1 client with a cache. However, a lot
|
||||
|
@ -70,22 +70,27 @@ import org.junit.Test;
|
|||
* document the places where we differ from the HTTP RFC.
|
||||
*/
|
||||
@SuppressWarnings("boxing") // test code
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class TestProtocolDeviations {
|
||||
|
||||
private static final int MAX_BYTES = 1024;
|
||||
private static final int MAX_ENTRIES = 100;
|
||||
|
||||
private HttpHost host;
|
||||
private HttpRoute route;
|
||||
private HttpEntity mockEntity;
|
||||
private ExecRuntime mockEndpoint;
|
||||
private ExecChain mockExecChain;
|
||||
private HttpCache mockCache;
|
||||
private ClassicHttpRequest request;
|
||||
private HttpCacheContext context;
|
||||
private ClassicHttpResponse originResponse;
|
||||
HttpHost host;
|
||||
HttpRoute route;
|
||||
@Mock
|
||||
HttpEntity mockEntity;
|
||||
@Mock
|
||||
ExecRuntime mockEndpoint;
|
||||
@Mock
|
||||
ExecChain mockExecChain;
|
||||
@Mock
|
||||
HttpCache mockCache;
|
||||
ClassicHttpRequest request;
|
||||
HttpCacheContext context;
|
||||
ClassicHttpResponse originResponse;
|
||||
|
||||
private ExecChainHandler impl;
|
||||
ExecChainHandler impl;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
@ -105,11 +110,6 @@ public class TestProtocolDeviations {
|
|||
.build();
|
||||
|
||||
final HttpCache cache = new BasicHttpCache(config);
|
||||
mockEndpoint = EasyMock.createNiceMock(ExecRuntime.class);
|
||||
mockExecChain = EasyMock.createNiceMock(ExecChain.class);
|
||||
mockEntity = EasyMock.createNiceMock(HttpEntity.class);
|
||||
mockCache = EasyMock.createNiceMock(HttpCache.class);
|
||||
|
||||
impl = createCachingExecChain(cache, config);
|
||||
}
|
||||
|
||||
|
@ -131,122 +131,12 @@ public class TestProtocolDeviations {
|
|||
return out;
|
||||
}
|
||||
|
||||
private void replayMocks() {
|
||||
EasyMock.replay(mockExecChain);
|
||||
EasyMock.replay(mockCache);
|
||||
EasyMock.replay(mockEntity);
|
||||
}
|
||||
|
||||
private void verifyMocks() {
|
||||
EasyMock.verify(mockExecChain);
|
||||
EasyMock.verify(mockCache);
|
||||
EasyMock.verify(mockEntity);
|
||||
}
|
||||
|
||||
private HttpEntity makeBody(final int nbytes) {
|
||||
final byte[] bytes = new byte[nbytes];
|
||||
new Random().nextBytes(bytes);
|
||||
return new ByteArrayEntity(bytes, null);
|
||||
}
|
||||
|
||||
public static HttpRequest eqRequest(final HttpRequest in) {
|
||||
org.easymock.EasyMock.reportMatcher(new RequestEquivalent(in));
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* "For compatibility with HTTP/1.0 applications, HTTP/1.1 requests
|
||||
* containing a message-body MUST include a valid Content-Length header
|
||||
* field unless the server is known to be HTTP/1.1 compliant. If a request
|
||||
* contains a message-body and a Content-Length is not given, the server
|
||||
* SHOULD respond with 400 (bad request) if it cannot determine the length
|
||||
* of the message, or with 411 (length required) if it wishes to insist on
|
||||
* receiving a valid Content-Length."
|
||||
*
|
||||
* http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.4
|
||||
*
|
||||
* 8/23/2010 JRC - This test has been moved to Ignore. The caching client
|
||||
* was set to return status code 411 on a missing content-length header when
|
||||
* a request had a body. It seems that somewhere deeper in the client stack
|
||||
* this header is added automatically for us - so the caching client shouldn't
|
||||
* specifically be worried about this requirement.
|
||||
*/
|
||||
@Ignore
|
||||
public void testHTTP1_1RequestsWithBodiesOfKnownLengthMustHaveContentLength() throws Exception {
|
||||
final ClassicHttpRequest post = new BasicClassicHttpRequest("POST", "/");
|
||||
post.setEntity(mockEntity);
|
||||
|
||||
replayMocks();
|
||||
|
||||
final HttpResponse response = execute(post);
|
||||
|
||||
verifyMocks();
|
||||
|
||||
Assert.assertEquals(HttpStatus.SC_LENGTH_REQUIRED, response.getCode());
|
||||
}
|
||||
|
||||
/*
|
||||
* Discussion: if an incoming request has a body, but the HttpEntity
|
||||
* attached has an unknown length (meaning entity.getContentLength() is
|
||||
* negative), we have two choices if we want to be conditionally compliant.
|
||||
* (1) we can slurp the whole body into a bytearray and compute its length
|
||||
* before sending; or (2) we can push responsibility for (1) back onto the
|
||||
* client by just generating a 411 response
|
||||
*
|
||||
* There is a third option, which is that we delegate responsibility for (1)
|
||||
* onto the backend HttpClient, but because that is an injected dependency,
|
||||
* we can't rely on it necessarily being conditionally compliant with
|
||||
* HTTP/1.1. Currently, option (2) seems like the safest bet, as this
|
||||
* exposes to the client application that the slurping required for (1)
|
||||
* needs to happen in order to compute the content length.
|
||||
*
|
||||
* In any event, this test just captures the behavior required.
|
||||
*
|
||||
* 8/23/2010 JRC - This test has been moved to Ignore. The caching client
|
||||
* was set to return status code 411 on a missing content-length header when
|
||||
* a request had a body. It seems that somewhere deeper in the client stack
|
||||
* this header is added automatically for us - so the caching client shouldn't
|
||||
* specifically be worried about this requirement.
|
||||
*/
|
||||
@Ignore
|
||||
public void testHTTP1_1RequestsWithUnknownBodyLengthAreRejectedOrHaveContentLengthAdded()
|
||||
throws Exception {
|
||||
final ClassicHttpRequest post = new BasicClassicHttpRequest("POST", "/");
|
||||
|
||||
final byte[] bytes = new byte[128];
|
||||
new Random().nextBytes(bytes);
|
||||
|
||||
final HttpEntity mockBody = EasyMock.createMockBuilder(ByteArrayEntity.class).withConstructor(
|
||||
new Object[] { bytes }).addMockedMethods("getContentLength").createNiceMock();
|
||||
org.easymock.EasyMock.expect(mockBody.getContentLength()).andReturn(-1L).anyTimes();
|
||||
post.setEntity(mockBody);
|
||||
|
||||
final Capture<ClassicHttpRequest> reqCap = EasyMock.newCapture();
|
||||
EasyMock.expect(
|
||||
mockExecChain.proceed(
|
||||
EasyMock.capture(reqCap),
|
||||
EasyMock.isA(ExecChain.Scope.class))).andReturn(
|
||||
originResponse).times(0, 1);
|
||||
|
||||
replayMocks();
|
||||
EasyMock.replay(mockBody);
|
||||
|
||||
final HttpResponse result = execute(post);
|
||||
|
||||
verifyMocks();
|
||||
EasyMock.verify(mockBody);
|
||||
|
||||
if (reqCap.hasCaptured()) {
|
||||
// backend request was made
|
||||
final HttpRequest forwarded = reqCap.getValue();
|
||||
Assert.assertNotNull(forwarded.getFirstHeader("Content-Length"));
|
||||
} else {
|
||||
final int status = result.getCode();
|
||||
Assert.assertTrue(HttpStatus.SC_LENGTH_REQUIRED == status
|
||||
|| HttpStatus.SC_BAD_REQUEST == status);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* "10.2.7 206 Partial Content ... The request MUST have included a Range
|
||||
* header field (section 14.35) indicating the desired range, and MAY have
|
||||
|
@ -266,12 +156,8 @@ public class TestProtocolDeviations {
|
|||
originResponse.setHeader("Content-Range", "bytes 0-499/1234");
|
||||
originResponse.setEntity(makeBody(500));
|
||||
|
||||
EasyMock.expect(
|
||||
mockExecChain.proceed(
|
||||
EasyMock.isA(ClassicHttpRequest.class),
|
||||
EasyMock.isA(ExecChain.Scope.class))).andReturn(originResponse);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(originResponse);
|
||||
|
||||
replayMocks();
|
||||
try {
|
||||
final HttpResponse result = execute(request);
|
||||
Assert.assertTrue(HttpStatus.SC_PARTIAL_CONTENT != result.getCode());
|
||||
|
@ -292,13 +178,9 @@ public class TestProtocolDeviations {
|
|||
|
||||
originResponse = new BasicClassicHttpResponse(401, "Unauthorized");
|
||||
|
||||
EasyMock.expect(
|
||||
mockExecChain.proceed(
|
||||
EasyMock.isA(ClassicHttpRequest.class),
|
||||
EasyMock.isA(ExecChain.Scope.class))).andReturn(originResponse);
|
||||
replayMocks();
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(originResponse);
|
||||
|
||||
final HttpResponse result = execute(request);
|
||||
verifyMocks();
|
||||
Assert.assertSame(originResponse, result);
|
||||
}
|
||||
|
||||
|
@ -312,13 +194,9 @@ public class TestProtocolDeviations {
|
|||
public void testPassesOnOrigin405WithoutAllowHeader() throws Exception {
|
||||
originResponse = new BasicClassicHttpResponse(405, "Method Not Allowed");
|
||||
|
||||
EasyMock.expect(
|
||||
mockExecChain.proceed(
|
||||
EasyMock.isA(ClassicHttpRequest.class),
|
||||
EasyMock.isA(ExecChain.Scope.class))).andReturn(originResponse);
|
||||
replayMocks();
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(originResponse);
|
||||
|
||||
final HttpResponse result = execute(request);
|
||||
verifyMocks();
|
||||
Assert.assertSame(originResponse, result);
|
||||
}
|
||||
|
||||
|
@ -333,13 +211,9 @@ public class TestProtocolDeviations {
|
|||
public void testPassesOnOrigin407WithoutAProxyAuthenticateHeader() throws Exception {
|
||||
originResponse = new BasicClassicHttpResponse(407, "Proxy Authentication Required");
|
||||
|
||||
EasyMock.expect(
|
||||
mockExecChain.proceed(
|
||||
EasyMock.isA(ClassicHttpRequest.class),
|
||||
EasyMock.isA(ExecChain.Scope.class))).andReturn(originResponse);
|
||||
replayMocks();
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(originResponse);
|
||||
|
||||
final HttpResponse result = execute(request);
|
||||
verifyMocks();
|
||||
Assert.assertSame(originResponse, result);
|
||||
}
|
||||
|
||||
|
|
|
@ -39,44 +39,101 @@ import java.util.Date;
|
|||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.hc.client5.http.HttpRoute;
|
||||
import org.apache.hc.client5.http.auth.StandardAuthScheme;
|
||||
import org.apache.hc.client5.http.classic.ExecChain;
|
||||
import org.apache.hc.client5.http.classic.ExecRuntime;
|
||||
import org.apache.hc.client5.http.classic.methods.HttpGet;
|
||||
import org.apache.hc.client5.http.classic.methods.HttpPost;
|
||||
import org.apache.hc.client5.http.protocol.HttpClientContext;
|
||||
import org.apache.hc.client5.http.utils.DateUtils;
|
||||
import org.apache.hc.core5.http.ClassicHttpRequest;
|
||||
import org.apache.hc.core5.http.ClassicHttpResponse;
|
||||
import org.apache.hc.core5.http.Header;
|
||||
import org.apache.hc.core5.http.HeaderElement;
|
||||
import org.apache.hc.core5.http.HttpEntity;
|
||||
import org.apache.hc.core5.http.HttpException;
|
||||
import org.apache.hc.core5.http.HttpHeaders;
|
||||
import org.apache.hc.core5.http.HttpHost;
|
||||
import org.apache.hc.core5.http.HttpStatus;
|
||||
import org.apache.hc.core5.http.HttpVersion;
|
||||
import org.apache.hc.core5.http.io.support.ClassicRequestBuilder;
|
||||
import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
|
||||
import org.apache.hc.core5.http.message.BasicClassicHttpResponse;
|
||||
import org.apache.hc.core5.http.message.MessageSupport;
|
||||
import org.easymock.Capture;
|
||||
import org.easymock.EasyMock;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
/*
|
||||
* This test class captures functionality required to achieve unconditional
|
||||
* compliance with the HTTP/1.1 spec, i.e. all the SHOULD, SHOULD NOT,
|
||||
* RECOMMENDED, and NOT RECOMMENDED behaviors.
|
||||
*/
|
||||
public class TestProtocolRecommendations extends AbstractProtocolTest {
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class TestProtocolRecommendations {
|
||||
|
||||
private Date now;
|
||||
private Date tenSecondsAgo;
|
||||
private Date twoMinutesAgo;
|
||||
static final int MAX_BYTES = 1024;
|
||||
static final int MAX_ENTRIES = 100;
|
||||
static final int ENTITY_LENGTH = 128;
|
||||
|
||||
HttpHost host;
|
||||
HttpRoute route;
|
||||
HttpEntity body;
|
||||
HttpClientContext context;
|
||||
@Mock
|
||||
ExecChain mockExecChain;
|
||||
@Mock
|
||||
ExecRuntime mockExecRuntime;
|
||||
@Mock
|
||||
HttpCache mockCache;
|
||||
ClassicHttpRequest request;
|
||||
ClassicHttpResponse originResponse;
|
||||
CacheConfig config;
|
||||
CachingExec impl;
|
||||
HttpCache cache;
|
||||
Date now;
|
||||
Date tenSecondsAgo;
|
||||
Date twoMinutesAgo;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() {
|
||||
super.setUp();
|
||||
public void setUp() throws Exception {
|
||||
host = new HttpHost("foo.example.com", 80);
|
||||
|
||||
route = new HttpRoute(host);
|
||||
|
||||
body = HttpTestUtils.makeBody(ENTITY_LENGTH);
|
||||
|
||||
request = new BasicClassicHttpRequest("GET", "/foo");
|
||||
|
||||
context = HttpClientContext.create();
|
||||
|
||||
originResponse = HttpTestUtils.make200Response();
|
||||
|
||||
config = CacheConfig.custom()
|
||||
.setMaxCacheEntries(MAX_ENTRIES)
|
||||
.setMaxObjectSize(MAX_BYTES)
|
||||
.build();
|
||||
|
||||
cache = new BasicHttpCache(config);
|
||||
impl = new CachingExec(cache, null, config);
|
||||
|
||||
now = new Date();
|
||||
tenSecondsAgo = new Date(now.getTime() - 10 * 1000L);
|
||||
twoMinutesAgo = new Date(now.getTime() - 2 * 60 * 1000L);
|
||||
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(originResponse);
|
||||
}
|
||||
|
||||
public ClassicHttpResponse execute(final ClassicHttpRequest request) throws IOException, HttpException {
|
||||
return impl.execute(
|
||||
ClassicRequestBuilder.copy(request).build(),
|
||||
new ExecChain.Scope("test", route, request, mockExecRuntime, context),
|
||||
mockExecChain);
|
||||
}
|
||||
|
||||
/* "identity: The default (identity) encoding; the use of no
|
||||
|
@ -89,10 +146,10 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
@Test
|
||||
public void testIdentityCodingIsNotUsedInContentEncodingHeader() throws Exception {
|
||||
originResponse.setHeader("Content-Encoding", "identity");
|
||||
backendExpectsAnyRequest().andReturn(originResponse);
|
||||
replayMocks();
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(originResponse);
|
||||
|
||||
final ClassicHttpResponse result = execute(request);
|
||||
verifyMocks();
|
||||
|
||||
boolean foundIdentity = false;
|
||||
final Iterator<HeaderElement> it = MessageSupport.iterate(result, HttpHeaders.CONTENT_ENCODING);
|
||||
while (it.hasNext()) {
|
||||
|
@ -120,15 +177,14 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
resp1.setHeader(validatorHeader, validator);
|
||||
resp1.setHeader(headerName, headerValue);
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
|
||||
final ClassicHttpRequest req2 = HttpTestUtils.makeDefaultRequest();
|
||||
req2.setHeader(conditionalHeader, validator);
|
||||
|
||||
replayMocks();
|
||||
execute(req1);
|
||||
final ClassicHttpResponse result = execute(req2);
|
||||
verifyMocks();
|
||||
|
||||
|
||||
if (HttpStatus.SC_NOT_MODIFIED == result.getCode()) {
|
||||
assertNull(result.getFirstHeader(headerName));
|
||||
|
@ -217,7 +273,7 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
resp1.setHeader(validatorHeader, validator);
|
||||
resp1.setHeader("Content-Range", "bytes 0-127/256");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
|
||||
final ClassicHttpRequest req2 = HttpTestUtils.makeDefaultRequest();
|
||||
req2.setHeader("If-Range", validator);
|
||||
|
@ -230,19 +286,15 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
|
||||
// cache module does not currently deal with byte ranges, but we want
|
||||
// this test to work even if it does some day
|
||||
final Capture<ClassicHttpRequest> cap = EasyMock.newCapture();
|
||||
EasyMock.expect(
|
||||
mockExecChain.proceed(
|
||||
EasyMock.capture(cap),
|
||||
EasyMock.isA(ExecChain.Scope.class))).andReturn(resp2).times(0,1);
|
||||
|
||||
replayMocks();
|
||||
execute(req1);
|
||||
final ClassicHttpResponse result = execute(req2);
|
||||
verifyMocks();
|
||||
|
||||
if (!cap.hasCaptured()
|
||||
&& HttpStatus.SC_NOT_MODIFIED == result.getCode()) {
|
||||
final ArgumentCaptor<ClassicHttpRequest> reqCapture = ArgumentCaptor.forClass(ClassicHttpRequest.class);
|
||||
Mockito.verify(mockExecChain, Mockito.atMost(2)).proceed(reqCapture.capture(), Mockito.any());
|
||||
|
||||
final List<ClassicHttpRequest> allRequests = reqCapture.getAllValues();
|
||||
if (allRequests.isEmpty() && HttpStatus.SC_NOT_MODIFIED == result.getCode()) {
|
||||
// cache generated a 304
|
||||
assertNull(result.getFirstHeader("Content-Range"));
|
||||
}
|
||||
|
@ -294,11 +346,9 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
resp.setHeader("Etag", "\"etag\"");
|
||||
resp.setHeader(entityHeader, entityHeaderValue);
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp);
|
||||
|
||||
replayMocks();
|
||||
final ClassicHttpResponse result = execute(req);
|
||||
verifyMocks();
|
||||
|
||||
assertNull(result.getFirstHeader(entityHeader));
|
||||
}
|
||||
|
@ -350,11 +400,9 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
resp.setHeader("ETag", "\"etag\"");
|
||||
resp.setHeader("Content-Range", "bytes 0-127/256");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp);
|
||||
|
||||
replayMocks();
|
||||
final ClassicHttpResponse result = execute(req);
|
||||
verifyMocks();
|
||||
|
||||
assertNull(result.getFirstHeader("Content-Range"));
|
||||
}
|
||||
|
@ -377,23 +425,22 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
resp1.setHeader("Cache-Control","public,max-age=5");
|
||||
resp1.setHeader("Etag","\"etag\"");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
return req1;
|
||||
}
|
||||
|
||||
private void testDoesNotReturnStaleResponseOnError(final ClassicHttpRequest req2) throws Exception {
|
||||
final ClassicHttpRequest req1 = requestToPopulateStaleCacheEntry();
|
||||
|
||||
backendExpectsAnyRequest().andThrow(new IOException());
|
||||
|
||||
replayMocks();
|
||||
execute(req1);
|
||||
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenThrow(new IOException());
|
||||
|
||||
ClassicHttpResponse result = null;
|
||||
try {
|
||||
result = execute(req2);
|
||||
} catch (final IOException acceptable) {
|
||||
}
|
||||
verifyMocks();
|
||||
|
||||
if (result != null) {
|
||||
assertNotEquals(HttpStatus.SC_OK, result.getCode());
|
||||
|
@ -451,15 +498,14 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
final ClassicHttpRequest req2 = new BasicClassicHttpRequest("GET", "/");
|
||||
req2.setHeader("Cache-Control","max-stale=20");
|
||||
|
||||
backendExpectsAnyRequest().andThrow(new IOException()).times(0,1);
|
||||
|
||||
replayMocks();
|
||||
execute(req1);
|
||||
|
||||
final ClassicHttpResponse result = execute(req2);
|
||||
verifyMocks();
|
||||
|
||||
assertEquals(HttpStatus.SC_OK, result.getCode());
|
||||
assertNotNull(result.getFirstHeader("Warning"));
|
||||
|
||||
Mockito.verify(mockExecChain, Mockito.atMost(1)).proceed(Mockito.any(), Mockito.any());
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -503,16 +549,17 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
resp1.setHeader("ETag","\"etag\"");
|
||||
resp1.setHeader("Date", DateUtils.formatDate(tenSecondsAgo));
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1);
|
||||
|
||||
final ClassicHttpRequest req2 = new BasicClassicHttpRequest("GET", "/");
|
||||
|
||||
backendExpectsAnyRequest().andThrow(new IOException()).anyTimes();
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
|
||||
replayMocks();
|
||||
execute(req1);
|
||||
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenThrow(new IOException());
|
||||
|
||||
final ClassicHttpResponse result = execute(req2);
|
||||
verifyMocks();
|
||||
|
||||
Mockito.verify(mockExecChain, Mockito.times(2)).proceed(Mockito.any(), Mockito.any());
|
||||
|
||||
assertEquals(HttpStatus.SC_OK, result.getCode());
|
||||
boolean warning111Found = false;
|
||||
|
@ -545,11 +592,9 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
originResponse.setHeader("Cache-Control","public, max-age=5");
|
||||
originResponse.setHeader("ETag","\"etag\"");
|
||||
|
||||
backendExpectsAnyRequest().andReturn(originResponse);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(originResponse);
|
||||
|
||||
replayMocks();
|
||||
final ClassicHttpResponse result = execute(request);
|
||||
verifyMocks();
|
||||
|
||||
assertNull(result.getFirstHeader("Warning"));
|
||||
}
|
||||
|
@ -563,11 +608,9 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
final String warning = "110 fred \"Response is stale\"";
|
||||
originResponse.addHeader("Warning",warning);
|
||||
|
||||
backendExpectsAnyRequest().andReturn(originResponse);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(originResponse);
|
||||
|
||||
replayMocks();
|
||||
final ClassicHttpResponse result = execute(request);
|
||||
verifyMocks();
|
||||
|
||||
assertEquals(warning, result.getFirstHeader("Warning").getValue());
|
||||
}
|
||||
|
@ -581,27 +624,23 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
private void testDoesNotModifyHeaderOnResponses(final String headerName) throws Exception {
|
||||
final String headerValue = HttpTestUtils
|
||||
.getCanonicalHeaderValue(originResponse, headerName);
|
||||
backendExpectsAnyRequest().andReturn(originResponse);
|
||||
replayMocks();
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(originResponse);
|
||||
|
||||
final ClassicHttpResponse result = execute(request);
|
||||
verifyMocks();
|
||||
assertEquals(headerValue,
|
||||
result.getFirstHeader(headerName).getValue());
|
||||
|
||||
assertEquals(headerValue, result.getFirstHeader(headerName).getValue());
|
||||
}
|
||||
|
||||
private void testDoesNotModifyHeaderOnRequests(final String headerName) throws Exception {
|
||||
final String headerValue = HttpTestUtils.getCanonicalHeaderValue(request, headerName);
|
||||
final Capture<ClassicHttpRequest> cap = EasyMock.newCapture();
|
||||
EasyMock.expect(
|
||||
mockExecChain.proceed(
|
||||
EasyMock.capture(cap),
|
||||
EasyMock.isA(ExecChain.Scope.class))).andReturn(originResponse);
|
||||
replayMocks();
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(originResponse);
|
||||
|
||||
execute(request);
|
||||
verifyMocks();
|
||||
assertEquals(headerValue,
|
||||
HttpTestUtils.getCanonicalHeaderValue(cap.getValue(),
|
||||
headerName));
|
||||
|
||||
final ArgumentCaptor<ClassicHttpRequest> reqCapture = ArgumentCaptor.forClass(ClassicHttpRequest.class);
|
||||
Mockito.verify(mockExecChain).proceed(reqCapture.capture(), Mockito.any());
|
||||
|
||||
assertEquals(headerValue, HttpTestUtils.getCanonicalHeaderValue(reqCapture.getValue(), headerName));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -834,25 +873,22 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
resp1.setHeader("Last-Modified", lmDate);
|
||||
resp1.setHeader("Cache-Control","max-age=5");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1);
|
||||
|
||||
final Capture<ClassicHttpRequest> cap = EasyMock.newCapture();
|
||||
final ClassicHttpRequest req2 = new BasicClassicHttpRequest("GET", "/");
|
||||
final ClassicHttpResponse resp2 = HttpTestUtils.make200Response();
|
||||
|
||||
EasyMock.expect(
|
||||
mockExecChain.proceed(
|
||||
EasyMock.capture(cap),
|
||||
EasyMock.isA(ExecChain.Scope.class))).andReturn(resp2);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
|
||||
replayMocks();
|
||||
execute(req1);
|
||||
execute(req2);
|
||||
verifyMocks();
|
||||
|
||||
final ClassicHttpRequest captured = cap.getValue();
|
||||
final Header ifModifiedSince =
|
||||
captured.getFirstHeader("If-Modified-Since");
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp2);
|
||||
|
||||
execute(req2);
|
||||
|
||||
final ArgumentCaptor<ClassicHttpRequest> reqCapture = ArgumentCaptor.forClass(ClassicHttpRequest.class);
|
||||
Mockito.verify(mockExecChain, Mockito.times(2)).proceed(reqCapture.capture(), Mockito.any());
|
||||
|
||||
final ClassicHttpRequest captured = reqCapture.getValue();
|
||||
final Header ifModifiedSince = captured.getFirstHeader("If-Modified-Since");
|
||||
assertEquals(lmDate, ifModifiedSince.getValue());
|
||||
}
|
||||
|
||||
|
@ -877,28 +913,24 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
resp1.setHeader("Cache-Control","max-age=5");
|
||||
resp1.setHeader("ETag", etag);
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1);
|
||||
|
||||
final Capture<ClassicHttpRequest> cap = EasyMock.newCapture();
|
||||
final ClassicHttpRequest req2 = new BasicClassicHttpRequest("GET", "/");
|
||||
final ClassicHttpResponse resp2 = HttpTestUtils.make200Response();
|
||||
|
||||
EasyMock.expect(
|
||||
mockExecChain.proceed(
|
||||
EasyMock.capture(cap),
|
||||
EasyMock.isA(ExecChain.Scope.class))).andReturn(resp2);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
|
||||
replayMocks();
|
||||
execute(req1);
|
||||
execute(req2);
|
||||
verifyMocks();
|
||||
|
||||
final ClassicHttpRequest captured = cap.getValue();
|
||||
final Header ifModifiedSince =
|
||||
captured.getFirstHeader("If-Modified-Since");
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp2);
|
||||
|
||||
execute(req2);
|
||||
|
||||
final ArgumentCaptor<ClassicHttpRequest> reqCapture = ArgumentCaptor.forClass(ClassicHttpRequest.class);
|
||||
Mockito.verify(mockExecChain, Mockito.times(2)).proceed(reqCapture.capture(), Mockito.any());
|
||||
|
||||
final ClassicHttpRequest captured = reqCapture.getValue();
|
||||
final Header ifModifiedSince = captured.getFirstHeader("If-Modified-Since");
|
||||
assertEquals(lmDate, ifModifiedSince.getValue());
|
||||
final Header ifNoneMatch =
|
||||
captured.getFirstHeader("If-None-Match");
|
||||
final Header ifNoneMatch = captured.getFirstHeader("If-None-Match");
|
||||
assertEquals(etag, ifNoneMatch.getValue());
|
||||
}
|
||||
|
||||
|
@ -922,7 +954,7 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
resp1.setHeader("Expires",DateUtils.formatDate(oneSecondAgo));
|
||||
resp1.setHeader("Cache-Control", "public");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
|
||||
final ClassicHttpRequest req2 = new BasicClassicHttpRequest("GET", "/");
|
||||
final ClassicHttpRequest revalidate = new BasicClassicHttpRequest("GET", "/");
|
||||
|
@ -933,18 +965,12 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
resp2.setHeader("Expires", DateUtils.formatDate(oneSecondFromNow));
|
||||
resp2.setHeader("ETag","\"etag\"");
|
||||
|
||||
EasyMock.expect(
|
||||
mockExecChain.proceed(
|
||||
eqRequest(revalidate),
|
||||
EasyMock.isA(ExecChain.Scope.class))).andReturn(resp2);
|
||||
Mockito.when(mockExecChain.proceed(RequestEquivalent.eq(revalidate), Mockito.any())).thenReturn(resp2);
|
||||
|
||||
replayMocks();
|
||||
execute(req1);
|
||||
final ClassicHttpResponse result = execute(req2);
|
||||
verifyMocks();
|
||||
|
||||
assertEquals(HttpStatus.SC_OK,
|
||||
result.getCode());
|
||||
assertEquals(HttpStatus.SC_OK, result.getCode());
|
||||
}
|
||||
|
||||
/* "When a client tries to revalidate a cache entry, and the response
|
||||
|
@ -969,32 +995,23 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
resp1.setHeader("Date", DateUtils.formatDate(tenSecondsAgo));
|
||||
resp1.setHeader("Cache-Control","max-age=5");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1);
|
||||
|
||||
final ClassicHttpRequest req2 = new BasicClassicHttpRequest("GET", "/");
|
||||
final ClassicHttpResponse resp2 = HttpTestUtils.make304Response();
|
||||
resp2.setHeader("ETag","\"etag\"");
|
||||
resp2.setHeader("Date", DateUtils.formatDate(elevenSecondsAgo));
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp2);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
|
||||
final Capture<ClassicHttpRequest> cap = EasyMock.newCapture();
|
||||
final ClassicHttpResponse resp3 = HttpTestUtils.make200Response();
|
||||
resp3.setHeader("ETag","\"etag2\"");
|
||||
resp3.setHeader("Date", DateUtils.formatDate(now));
|
||||
resp3.setHeader("Cache-Control","max-age=5");
|
||||
|
||||
EasyMock.expect(
|
||||
mockExecChain.proceed(
|
||||
EasyMock.capture(cap),
|
||||
EasyMock.isA(ExecChain.Scope.class))).andReturn(resp3);
|
||||
|
||||
replayMocks();
|
||||
execute(req1);
|
||||
execute(req2);
|
||||
verifyMocks();
|
||||
|
||||
final ClassicHttpRequest captured = cap.getValue();
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp2);
|
||||
|
||||
execute(req2);
|
||||
|
||||
final ArgumentCaptor<ClassicHttpRequest> reqCapture = ArgumentCaptor.forClass(ClassicHttpRequest.class);
|
||||
Mockito.verify(mockExecChain, Mockito.times(3)).proceed(reqCapture.capture(), Mockito.any());
|
||||
|
||||
final ClassicHttpRequest captured = reqCapture.getValue();
|
||||
boolean hasMaxAge0 = false;
|
||||
boolean hasNoCache = false;
|
||||
final Iterator<HeaderElement> it = MessageSupport.iterate(captured, HttpHeaders.CACHE_CONTROL);
|
||||
|
@ -1037,8 +1054,6 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
resp1.setHeader("Vary","User-Agent");
|
||||
resp1.setHeader("Etag","\"etag1\"");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1);
|
||||
|
||||
final ClassicHttpRequest req2 = new BasicClassicHttpRequest("GET","/");
|
||||
req2.setHeader("User-Agent","agent2");
|
||||
final ClassicHttpResponse resp2 = HttpTestUtils.make200Response();
|
||||
|
@ -1046,25 +1061,26 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
resp2.setHeader("Vary","User-Agent");
|
||||
resp2.setHeader("Etag","\"etag2\"");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp2);
|
||||
|
||||
final Capture<ClassicHttpRequest> cap = EasyMock.newCapture();
|
||||
final ClassicHttpRequest req3 = new BasicClassicHttpRequest("GET","/");
|
||||
req3.setHeader("User-Agent","agent3");
|
||||
final ClassicHttpResponse resp3 = HttpTestUtils.make200Response();
|
||||
|
||||
EasyMock.expect(
|
||||
mockExecChain.proceed(
|
||||
EasyMock.capture(cap),
|
||||
EasyMock.isA(ExecChain.Scope.class))).andReturn(resp3);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
|
||||
replayMocks();
|
||||
execute(req1);
|
||||
execute(req2);
|
||||
execute(req3);
|
||||
verifyMocks();
|
||||
|
||||
final ClassicHttpRequest captured = cap.getValue();
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp2);
|
||||
|
||||
execute(req2);
|
||||
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(),Mockito.any())).thenReturn(resp3);
|
||||
|
||||
execute(req3);
|
||||
|
||||
final ArgumentCaptor<ClassicHttpRequest> reqCapture = ArgumentCaptor.forClass(ClassicHttpRequest.class);
|
||||
Mockito.verify(mockExecChain, Mockito.times(3)).proceed(reqCapture.capture(), Mockito.any());
|
||||
|
||||
final ClassicHttpRequest captured = reqCapture.getValue();
|
||||
boolean foundEtag1 = false;
|
||||
boolean foundEtag2 = false;
|
||||
for(final Header h : captured.getHeaders("If-None-Match")) {
|
||||
|
@ -1099,9 +1115,6 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
resp1.setHeader("Cache-Control", "max-age=3600");
|
||||
resp1.setHeader("ETag", "\"etag1\"");
|
||||
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1);
|
||||
|
||||
final ClassicHttpRequest req2 = new BasicClassicHttpRequest("GET", "/");
|
||||
req2.setHeader("User-Agent", "agent2");
|
||||
|
||||
|
@ -1111,8 +1124,6 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
resp2.setHeader("Cache-Control", "max-age=3600");
|
||||
resp2.setHeader("ETag", "\"etag2\"");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp2);
|
||||
|
||||
final ClassicHttpRequest req3 = new BasicClassicHttpRequest("GET", "/");
|
||||
req3.setHeader("User-Agent", "agent3");
|
||||
|
||||
|
@ -1120,17 +1131,21 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
resp3.setHeader("Date", DateUtils.formatDate(now));
|
||||
resp3.setHeader("ETag", "\"etag1\"");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp3);
|
||||
|
||||
final ClassicHttpRequest req4 = new BasicClassicHttpRequest("GET", "/");
|
||||
req4.setHeader("User-Agent", "agent1");
|
||||
|
||||
replayMocks();
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
|
||||
execute(req1);
|
||||
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp2);
|
||||
|
||||
execute(req2);
|
||||
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp3);
|
||||
|
||||
final ClassicHttpResponse result1 = execute(req3);
|
||||
final ClassicHttpResponse result2 = execute(req4);
|
||||
verifyMocks();
|
||||
|
||||
assertEquals(HttpStatus.SC_OK, result1.getCode());
|
||||
assertEquals("\"etag1\"", result1.getFirstHeader("ETag").getValue());
|
||||
|
@ -1150,7 +1165,7 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
resp1.setHeader("Cache-Control", "max-age=3600");
|
||||
resp1.setHeader("ETag", "\"etag1\"");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
|
||||
final ClassicHttpRequest req2 = new BasicClassicHttpRequest("GET", "/");
|
||||
req2.setHeader("User-Agent", "agent2");
|
||||
|
@ -1159,16 +1174,14 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
resp2.setHeader("Date", DateUtils.formatDate(now));
|
||||
resp2.setHeader("ETag", "\"etag1\"");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp2);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp2);
|
||||
|
||||
final ClassicHttpRequest req3 = new BasicClassicHttpRequest("GET", "/");
|
||||
req3.setHeader("User-Agent", "agent2");
|
||||
|
||||
replayMocks();
|
||||
execute(req1);
|
||||
execute(req2);
|
||||
execute(req3);
|
||||
verifyMocks();
|
||||
}
|
||||
|
||||
/* "If any of the existing cache entries contains only partial content
|
||||
|
@ -1187,8 +1200,6 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
resp1.setHeader("Vary", "User-Agent");
|
||||
resp1.setHeader("ETag", "\"etag1\"");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1);
|
||||
|
||||
final ClassicHttpRequest req2 = HttpTestUtils.makeDefaultRequest();
|
||||
req2.setHeader("User-Agent", "agent2");
|
||||
req2.setHeader("Range", "bytes=0-49");
|
||||
|
@ -1201,8 +1212,6 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
resp2.setHeader("Cache-Control","max-age=3600");
|
||||
resp2.setHeader("Date", DateUtils.formatDate(new Date()));
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp2);
|
||||
|
||||
final ClassicHttpRequest req3 = HttpTestUtils.makeDefaultRequest();
|
||||
req3.setHeader("User-Agent", "agent3");
|
||||
|
||||
|
@ -1211,19 +1220,22 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
resp1.setHeader("Vary", "User-Agent");
|
||||
resp1.setHeader("ETag", "\"etag3\"");
|
||||
|
||||
final Capture<ClassicHttpRequest> cap = EasyMock.newCapture();
|
||||
EasyMock.expect(
|
||||
mockExecChain.proceed(
|
||||
EasyMock.capture(cap),
|
||||
EasyMock.isA(ExecChain.Scope.class))).andReturn(resp3);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
|
||||
replayMocks();
|
||||
execute(req1);
|
||||
execute(req2);
|
||||
execute(req3);
|
||||
verifyMocks();
|
||||
|
||||
final ClassicHttpRequest captured = cap.getValue();
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp2);
|
||||
|
||||
execute(req2);
|
||||
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp3);
|
||||
|
||||
execute(req3);
|
||||
|
||||
final ArgumentCaptor<ClassicHttpRequest> reqCapture = ArgumentCaptor.forClass(ClassicHttpRequest.class);
|
||||
Mockito.verify(mockExecChain, Mockito.times(3)).proceed(reqCapture.capture(), Mockito.any());
|
||||
|
||||
final ClassicHttpRequest captured = reqCapture.getValue();
|
||||
final Iterator<HeaderElement> it = MessageSupport.iterate(captured, HttpHeaders.IF_NONE_MATCH);
|
||||
while (it.hasNext()) {
|
||||
final HeaderElement elt = it.next();
|
||||
|
@ -1248,7 +1260,7 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
resp1.setHeader("ETag", "\"old-etag\"");
|
||||
resp1.setHeader("Date", DateUtils.formatDate(tenSecondsAgo));
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
|
||||
final ClassicHttpRequest req2 = new HttpPost("http://foo.example.com/bar");
|
||||
final ClassicHttpResponse resp2 = HttpTestUtils.make200Response();
|
||||
|
@ -1256,18 +1268,16 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
resp2.setHeader("Date", DateUtils.formatDate(now));
|
||||
resp2.setHeader("Content-Location", "http://foo.example.com/");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp2);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp2);
|
||||
|
||||
final ClassicHttpRequest req3 = new HttpGet("http://foo.example.com");
|
||||
final ClassicHttpResponse resp3 = HttpTestUtils.make200Response();
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp3);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp3);
|
||||
|
||||
replayMocks();
|
||||
execute(req1);
|
||||
execute(req2);
|
||||
execute(req3);
|
||||
verifyMocks();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1286,11 +1296,9 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
resp2.setHeader("Content-Length","200");
|
||||
resp2.setHeader("Date", DateUtils.formatDate(now));
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp2);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp2);
|
||||
|
||||
replayMocks();
|
||||
execute(req2);
|
||||
verifyMocks();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1303,11 +1311,9 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
resp2.setHeader("Date", DateUtils.formatDate(now));
|
||||
resp2.setHeader("Via","1.0 someproxy");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp2);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp2);
|
||||
|
||||
replayMocks();
|
||||
execute(req2);
|
||||
verifyMocks();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1323,25 +1329,23 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
final ClassicHttpResponse resp1 = HttpTestUtils.make200Response();
|
||||
resp1.setHeader("Cache-Control","max-age=3600");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
|
||||
final ClassicHttpRequest req2 = new BasicClassicHttpRequest("FROB", "/");
|
||||
final ClassicHttpResponse resp2 = HttpTestUtils.make200Response();
|
||||
resp2.setHeader("Cache-Control","max-age=3600");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp2);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp2);
|
||||
|
||||
final ClassicHttpRequest req3 = new BasicClassicHttpRequest("GET", "/");
|
||||
final ClassicHttpResponse resp3 = HttpTestUtils.make200Response();
|
||||
resp3.setHeader("ETag", "\"etag\"");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp3);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp3);
|
||||
|
||||
replayMocks();
|
||||
execute(req1);
|
||||
execute(req2);
|
||||
final ClassicHttpResponse result = execute(req3);
|
||||
verifyMocks();
|
||||
|
||||
assertTrue(HttpTestUtils.semanticallyTransparent(resp3, result));
|
||||
}
|
||||
|
@ -1354,44 +1358,46 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
resp1.setHeader("Cache-Control","max-age=3600");
|
||||
resp1.setHeader("Vary", "User-Agent");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1);
|
||||
|
||||
final ClassicHttpRequest req2 = new BasicClassicHttpRequest("GET", "/");
|
||||
req2.setHeader("User-Agent", "agent2");
|
||||
final ClassicHttpResponse resp2 = HttpTestUtils.make200Response();
|
||||
resp2.setHeader("Cache-Control","max-age=3600");
|
||||
resp2.setHeader("Vary", "User-Agent");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp2);
|
||||
|
||||
final ClassicHttpRequest req3 = new BasicClassicHttpRequest("FROB", "/");
|
||||
req3.setHeader("User-Agent", "agent3");
|
||||
final ClassicHttpResponse resp3 = HttpTestUtils.make200Response();
|
||||
resp3.setHeader("Cache-Control","max-age=3600");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp3);
|
||||
|
||||
final ClassicHttpRequest req4 = new BasicClassicHttpRequest("GET", "/");
|
||||
req4.setHeader("User-Agent", "agent1");
|
||||
final ClassicHttpResponse resp4 = HttpTestUtils.make200Response();
|
||||
resp4.setHeader("ETag", "\"etag1\"");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp4);
|
||||
|
||||
final ClassicHttpRequest req5 = new BasicClassicHttpRequest("GET", "/");
|
||||
req5.setHeader("User-Agent", "agent2");
|
||||
final ClassicHttpResponse resp5 = HttpTestUtils.make200Response();
|
||||
resp5.setHeader("ETag", "\"etag2\"");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp5);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
|
||||
replayMocks();
|
||||
execute(req1);
|
||||
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp2);
|
||||
|
||||
execute(req2);
|
||||
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp3);
|
||||
|
||||
execute(req3);
|
||||
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp4);
|
||||
|
||||
final ClassicHttpResponse result4 = execute(req4);
|
||||
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp5);
|
||||
|
||||
final ClassicHttpResponse result5 = execute(req5);
|
||||
verifyMocks();
|
||||
|
||||
assertTrue(HttpTestUtils.semanticallyTransparent(resp4, result4));
|
||||
assertTrue(HttpTestUtils.semanticallyTransparent(resp5, result5));
|
||||
|
@ -1412,7 +1418,7 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
resp1.setHeader("Cache-Control", "max-age=3600");
|
||||
resp1.setHeader("ETag", "\"etag1\"");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
|
||||
final ClassicHttpRequest req2 = HttpTestUtils.makeDefaultRequest();
|
||||
req2.setHeader("Cache-Control", "max-age=0");
|
||||
|
@ -1421,15 +1427,13 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
resp2.setHeader("Cache-Control", "max-age=3600");
|
||||
resp2.setHeader("ETag", "\"etag2\"");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp2);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp2);
|
||||
|
||||
final ClassicHttpRequest req3 = HttpTestUtils.makeDefaultRequest();
|
||||
|
||||
replayMocks();
|
||||
execute(req1);
|
||||
execute(req2);
|
||||
final ClassicHttpResponse result = execute(req3);
|
||||
verifyMocks();
|
||||
|
||||
assertTrue(HttpTestUtils.semanticallyTransparent(resp2, result));
|
||||
}
|
||||
|
@ -1453,19 +1457,17 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
resp1.setHeader("Expires", DateUtils.formatDate(now));
|
||||
resp1.removeHeaders("Cache-Control");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
|
||||
final ClassicHttpRequest req2 = HttpTestUtils.makeDefaultRequest();
|
||||
req2.setHeader("Cache-Control", "max-stale=1000");
|
||||
final ClassicHttpResponse resp2 = HttpTestUtils.make200Response();
|
||||
resp2.setHeader("ETag", "\"etag2\"");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp2);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp2);
|
||||
|
||||
replayMocks();
|
||||
execute(req1);
|
||||
final ClassicHttpResponse result = execute(req2);
|
||||
verifyMocks();
|
||||
|
||||
assertTrue(HttpTestUtils.semanticallyTransparent(resp2, result));
|
||||
}
|
||||
|
@ -1478,19 +1480,17 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
resp1.setHeader("Expires", DateUtils.formatDate(tenSecondsAgo));
|
||||
resp1.removeHeaders("Cache-Control");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
|
||||
final ClassicHttpRequest req2 = HttpTestUtils.makeDefaultRequest();
|
||||
req2.setHeader("Cache-Control", "max-stale=1000");
|
||||
final ClassicHttpResponse resp2 = HttpTestUtils.make200Response();
|
||||
resp2.setHeader("ETag", "\"etag2\"");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp2);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp2);
|
||||
|
||||
replayMocks();
|
||||
execute(req1);
|
||||
final ClassicHttpResponse result = execute(req2);
|
||||
verifyMocks();
|
||||
|
||||
assertTrue(HttpTestUtils.semanticallyTransparent(resp2, result));
|
||||
}
|
||||
|
@ -1507,18 +1507,12 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
req1.setHeader("Cache-Control", "min-fresh=10, no-cache");
|
||||
req1.addHeader("Cache-Control", "max-stale=0, max-age=0");
|
||||
|
||||
|
||||
final Capture<ClassicHttpRequest> cap = EasyMock.newCapture();
|
||||
EasyMock.expect(
|
||||
mockExecChain.proceed(
|
||||
EasyMock.capture(cap),
|
||||
EasyMock.isA(ExecChain.Scope.class))).andReturn(HttpTestUtils.make200Response());
|
||||
|
||||
replayMocks();
|
||||
execute(req1);
|
||||
verifyMocks();
|
||||
|
||||
final ClassicHttpRequest captured = cap.getValue();
|
||||
final ArgumentCaptor<ClassicHttpRequest> reqCapture = ArgumentCaptor.forClass(ClassicHttpRequest.class);
|
||||
Mockito.verify(mockExecChain).proceed(reqCapture.capture(), Mockito.any());
|
||||
|
||||
final ClassicHttpRequest captured = reqCapture.getValue();
|
||||
boolean foundNoCache = false;
|
||||
boolean foundDisallowedDirective = false;
|
||||
final List<String> disallowed =
|
||||
|
@ -1551,12 +1545,9 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
final ClassicHttpRequest req = HttpTestUtils.makeDefaultRequest();
|
||||
req.setHeader("Cache-Control", "only-if-cached");
|
||||
|
||||
replayMocks();
|
||||
final ClassicHttpResponse result = execute(req);
|
||||
verifyMocks();
|
||||
|
||||
assertEquals(HttpStatus.SC_GATEWAY_TIMEOUT,
|
||||
result.getCode());
|
||||
assertEquals(HttpStatus.SC_GATEWAY_TIMEOUT, result.getCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1565,15 +1556,13 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
final ClassicHttpResponse resp1 = HttpTestUtils.make200Response();
|
||||
resp1.setHeader("Cache-Control","max-age=3600");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
|
||||
final ClassicHttpRequest req2 = HttpTestUtils.makeDefaultRequest();
|
||||
req2.setHeader("Cache-Control", "only-if-cached");
|
||||
|
||||
replayMocks();
|
||||
execute(req1);
|
||||
final ClassicHttpResponse result = execute(req2);
|
||||
verifyMocks();
|
||||
|
||||
assertTrue(HttpTestUtils.semanticallyTransparent(resp1, result));
|
||||
}
|
||||
|
@ -1585,18 +1574,15 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
resp1.setHeader("Date", DateUtils.formatDate(tenSecondsAgo));
|
||||
resp1.setHeader("Cache-Control","max-age=5");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
|
||||
final ClassicHttpRequest req2 = HttpTestUtils.makeDefaultRequest();
|
||||
req2.setHeader("Cache-Control", "only-if-cached");
|
||||
|
||||
replayMocks();
|
||||
execute(req1);
|
||||
final ClassicHttpResponse result = execute(req2);
|
||||
verifyMocks();
|
||||
|
||||
assertEquals(HttpStatus.SC_GATEWAY_TIMEOUT,
|
||||
result.getCode());
|
||||
assertEquals(HttpStatus.SC_GATEWAY_TIMEOUT, result.getCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1607,15 +1593,13 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
resp1.setHeader("Date", DateUtils.formatDate(tenSecondsAgo));
|
||||
resp1.setHeader("Cache-Control","max-age=5");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
|
||||
final ClassicHttpRequest req2 = HttpTestUtils.makeDefaultRequest();
|
||||
req2.setHeader("Cache-Control", "max-stale=20, only-if-cached");
|
||||
|
||||
replayMocks();
|
||||
execute(req1);
|
||||
final ClassicHttpResponse result = execute(req2);
|
||||
verifyMocks();
|
||||
|
||||
assertTrue(HttpTestUtils.semanticallyTransparent(resp1, result));
|
||||
}
|
||||
|
@ -1628,18 +1612,15 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
|
|||
resp1.setHeader("Cache-Control", "max-age=300");
|
||||
resp1.setHeader("ETag","W/\"weak-sauce\"");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
|
||||
final ClassicHttpRequest req2 = HttpTestUtils.makeDefaultRequest();
|
||||
req2.setHeader("If-None-Match","W/\"weak-sauce\"");
|
||||
|
||||
replayMocks();
|
||||
execute(req1);
|
||||
final ClassicHttpResponse result = execute(req2);
|
||||
verifyMocks();
|
||||
|
||||
assertEquals(HttpStatus.SC_NOT_MODIFIED, result.getCode());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -31,37 +31,90 @@ import static org.junit.Assert.assertFalse;
|
|||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
|
||||
import org.apache.hc.client5.http.HttpRoute;
|
||||
import org.apache.hc.client5.http.classic.ExecChain;
|
||||
import org.apache.hc.client5.http.classic.ExecRuntime;
|
||||
import org.apache.hc.client5.http.impl.schedule.ImmediateSchedulingStrategy;
|
||||
import org.apache.hc.client5.http.protocol.HttpClientContext;
|
||||
import org.apache.hc.client5.http.utils.DateUtils;
|
||||
import org.apache.hc.core5.http.ClassicHttpRequest;
|
||||
import org.apache.hc.core5.http.ClassicHttpResponse;
|
||||
import org.apache.hc.core5.http.Header;
|
||||
import org.apache.hc.core5.http.HttpEntity;
|
||||
import org.apache.hc.core5.http.HttpException;
|
||||
import org.apache.hc.core5.http.HttpHost;
|
||||
import org.apache.hc.core5.http.HttpStatus;
|
||||
import org.apache.hc.core5.http.io.entity.InputStreamEntity;
|
||||
import org.apache.hc.core5.http.io.support.ClassicRequestBuilder;
|
||||
import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
|
||||
import org.easymock.EasyMock;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
/**
|
||||
* A suite of acceptance tests for compliance with RFC5861, which
|
||||
* describes the stale-if-error and stale-while-revalidate
|
||||
* Cache-Control extensions.
|
||||
*/
|
||||
public class TestRFC5861Compliance extends AbstractProtocolTest {
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class TestRFC5861Compliance {
|
||||
|
||||
private ScheduledExecutorService executorService;
|
||||
static final int MAX_BYTES = 1024;
|
||||
static final int MAX_ENTRIES = 100;
|
||||
static final int ENTITY_LENGTH = 128;
|
||||
|
||||
HttpHost host;
|
||||
HttpRoute route;
|
||||
HttpEntity body;
|
||||
HttpClientContext context;
|
||||
@Mock
|
||||
ExecChain mockExecChain;
|
||||
@Mock
|
||||
ExecRuntime mockExecRuntime;
|
||||
@Mock
|
||||
HttpCache mockCache;
|
||||
ClassicHttpRequest request;
|
||||
ClassicHttpResponse originResponse;
|
||||
CacheConfig config;
|
||||
CachingExec impl;
|
||||
HttpCache cache;
|
||||
ScheduledExecutorService executorService;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
public void setUp() throws Exception {
|
||||
host = new HttpHost("foo.example.com", 80);
|
||||
|
||||
route = new HttpRoute(host);
|
||||
|
||||
body = HttpTestUtils.makeBody(ENTITY_LENGTH);
|
||||
|
||||
request = new BasicClassicHttpRequest("GET", "/foo");
|
||||
|
||||
context = HttpClientContext.create();
|
||||
|
||||
originResponse = HttpTestUtils.make200Response();
|
||||
|
||||
config = CacheConfig.custom()
|
||||
.setMaxCacheEntries(MAX_ENTRIES)
|
||||
.setMaxObjectSize(MAX_BYTES)
|
||||
.build();
|
||||
|
||||
cache = new BasicHttpCache(config);
|
||||
impl = new CachingExec(cache, null, config);
|
||||
|
||||
executorService = new ScheduledThreadPoolExecutor(1);
|
||||
EasyMock.expect(mockExecRuntime.fork(null)).andReturn(mockExecRuntime).anyTimes();
|
||||
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(originResponse);
|
||||
Mockito.when(mockExecRuntime.fork(null)).thenReturn(mockExecRuntime);
|
||||
}
|
||||
|
||||
@After
|
||||
|
@ -69,16 +122,11 @@ public class TestRFC5861Compliance extends AbstractProtocolTest {
|
|||
executorService.shutdownNow();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void replayMocks() {
|
||||
super.replayMocks();
|
||||
EasyMock.replay(mockExecRuntime);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void verifyMocks() {
|
||||
super.verifyMocks();
|
||||
EasyMock.verify(mockExecRuntime);
|
||||
public ClassicHttpResponse execute(final ClassicHttpRequest request) throws IOException, HttpException {
|
||||
return impl.execute(
|
||||
ClassicRequestBuilder.copy(request).build(),
|
||||
new ExecChain.Scope("test", route, request, mockExecRuntime, context),
|
||||
mockExecChain);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -104,17 +152,16 @@ public class TestRFC5861Compliance extends AbstractProtocolTest {
|
|||
final ClassicHttpResponse resp1 = HttpTestUtils.make200Response(tenSecondsAgo,
|
||||
"public, max-age=5, stale-if-error=60");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1);
|
||||
|
||||
final ClassicHttpRequest req2 = HttpTestUtils.makeDefaultRequest();
|
||||
final ClassicHttpResponse resp2 = HttpTestUtils.make500Response();
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp2);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
|
||||
replayMocks();
|
||||
execute(req1);
|
||||
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp2);
|
||||
|
||||
final ClassicHttpResponse result = execute(req2);
|
||||
verifyMocks();
|
||||
|
||||
HttpTestUtils.assert110WarningFound(result);
|
||||
}
|
||||
|
@ -127,8 +174,6 @@ public class TestRFC5861Compliance extends AbstractProtocolTest {
|
|||
final ClassicHttpResponse resp1 = HttpTestUtils.make200Response(tenSecondsAgo,
|
||||
"public, max-age=5, stale-if-error=60");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1);
|
||||
|
||||
final ClassicHttpRequest req2 = HttpTestUtils.makeDefaultRequest();
|
||||
final ClassicHttpResponse resp2 = HttpTestUtils.make500Response();
|
||||
final byte[] body101 = HttpTestUtils.getRandomBytes(101);
|
||||
|
@ -137,12 +182,13 @@ public class TestRFC5861Compliance extends AbstractProtocolTest {
|
|||
final HttpEntity entity = new InputStreamEntity(cis, 101, null);
|
||||
resp2.setEntity(entity);
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp2);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
|
||||
replayMocks();
|
||||
execute(req1);
|
||||
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp2);
|
||||
|
||||
execute(req2);
|
||||
verifyMocks();
|
||||
|
||||
assertTrue(cis.wasClosed());
|
||||
}
|
||||
|
@ -155,17 +201,16 @@ public class TestRFC5861Compliance extends AbstractProtocolTest {
|
|||
final ClassicHttpResponse resp1 = HttpTestUtils.make200Response(tenSecondsAgo,
|
||||
"public, max-age=5, stale-if-error=60, must-revalidate");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1);
|
||||
|
||||
final ClassicHttpRequest req2 = HttpTestUtils.makeDefaultRequest();
|
||||
final ClassicHttpResponse resp2 = HttpTestUtils.make500Response();
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp2);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
|
||||
replayMocks();
|
||||
execute(req1);
|
||||
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp2);
|
||||
|
||||
final ClassicHttpResponse result = execute(req2);
|
||||
verifyMocks();
|
||||
|
||||
assertTrue(HttpStatus.SC_OK != result.getCode());
|
||||
}
|
||||
|
@ -179,17 +224,16 @@ public class TestRFC5861Compliance extends AbstractProtocolTest {
|
|||
final ClassicHttpResponse resp1 = HttpTestUtils.make200Response(tenSecondsAgo,
|
||||
"public, max-age=5, stale-if-error=60, proxy-revalidate");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1);
|
||||
|
||||
final ClassicHttpRequest req2 = HttpTestUtils.makeDefaultRequest();
|
||||
final ClassicHttpResponse resp2 = HttpTestUtils.make500Response();
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp2);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
|
||||
replayMocks();
|
||||
execute(req1);
|
||||
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp2);
|
||||
|
||||
final ClassicHttpResponse result = execute(req2);
|
||||
verifyMocks();
|
||||
|
||||
assertTrue(HttpStatus.SC_OK != result.getCode());
|
||||
}
|
||||
|
@ -206,17 +250,16 @@ public class TestRFC5861Compliance extends AbstractProtocolTest {
|
|||
final ClassicHttpResponse resp1 = HttpTestUtils.make200Response(tenSecondsAgo,
|
||||
"public, max-age=5, stale-if-error=60, proxy-revalidate");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1);
|
||||
|
||||
final ClassicHttpRequest req2 = HttpTestUtils.makeDefaultRequest();
|
||||
final ClassicHttpResponse resp2 = HttpTestUtils.make500Response();
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp2);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
|
||||
replayMocks();
|
||||
execute(req1);
|
||||
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp2);
|
||||
|
||||
final ClassicHttpResponse result = execute(req2);
|
||||
verifyMocks();
|
||||
|
||||
HttpTestUtils.assert110WarningFound(result);
|
||||
}
|
||||
|
@ -229,18 +272,17 @@ public class TestRFC5861Compliance extends AbstractProtocolTest {
|
|||
final ClassicHttpResponse resp1 = HttpTestUtils.make200Response(tenSecondsAgo,
|
||||
"public, max-age=5, stale-if-error=60");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1);
|
||||
|
||||
final ClassicHttpRequest req2 = HttpTestUtils.makeDefaultRequest();
|
||||
req2.setHeader("Cache-Control","min-fresh=2");
|
||||
final ClassicHttpResponse resp2 = HttpTestUtils.make500Response();
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp2);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
|
||||
replayMocks();
|
||||
execute(req1);
|
||||
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp2);
|
||||
|
||||
final ClassicHttpResponse result = execute(req2);
|
||||
verifyMocks();
|
||||
|
||||
assertTrue(HttpStatus.SC_OK != result.getCode());
|
||||
}
|
||||
|
@ -253,18 +295,17 @@ public class TestRFC5861Compliance extends AbstractProtocolTest {
|
|||
final ClassicHttpResponse resp1 = HttpTestUtils.make200Response(tenSecondsAgo,
|
||||
"public, max-age=5");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1);
|
||||
|
||||
final ClassicHttpRequest req2 = HttpTestUtils.makeDefaultRequest();
|
||||
req2.setHeader("Cache-Control","public, stale-if-error=60");
|
||||
final ClassicHttpResponse resp2 = HttpTestUtils.make500Response();
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp2);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
|
||||
replayMocks();
|
||||
execute(req1);
|
||||
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp2);
|
||||
|
||||
final ClassicHttpResponse result = execute(req2);
|
||||
verifyMocks();
|
||||
|
||||
HttpTestUtils.assert110WarningFound(result);
|
||||
}
|
||||
|
@ -278,18 +319,17 @@ public class TestRFC5861Compliance extends AbstractProtocolTest {
|
|||
resp1.setHeader("Date", DateUtils.formatDate(tenSecondsAgo));
|
||||
resp1.setHeader("Cache-Control", "public, max-age=5");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1);
|
||||
|
||||
final ClassicHttpRequest req2 = HttpTestUtils.makeDefaultRequest();
|
||||
req2.setHeader("Cache-Control", "public, stale-if-error=60");
|
||||
final ClassicHttpResponse resp2 = HttpTestUtils.make500Response();
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp2);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
|
||||
replayMocks();
|
||||
execute(req1);
|
||||
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp2);
|
||||
|
||||
final ClassicHttpResponse result = execute(req2);
|
||||
verifyMocks();
|
||||
|
||||
HttpTestUtils.assert110WarningFound(result);
|
||||
}
|
||||
|
@ -303,17 +343,16 @@ public class TestRFC5861Compliance extends AbstractProtocolTest {
|
|||
final ClassicHttpResponse resp1 = HttpTestUtils.make200Response(tenSecondsAgo,
|
||||
"public, max-age=5, stale-if-error=2");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1);
|
||||
|
||||
final ClassicHttpRequest req2 = HttpTestUtils.makeDefaultRequest();
|
||||
final ClassicHttpResponse resp2 = HttpTestUtils.make500Response();
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp2);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
|
||||
replayMocks();
|
||||
execute(req1);
|
||||
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp2);
|
||||
|
||||
final ClassicHttpResponse result = execute(req2);
|
||||
verifyMocks();
|
||||
|
||||
assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR,
|
||||
result.getCode());
|
||||
|
@ -328,21 +367,19 @@ public class TestRFC5861Compliance extends AbstractProtocolTest {
|
|||
final ClassicHttpResponse resp1 = HttpTestUtils.make200Response(tenSecondsAgo,
|
||||
"public, max-age=5");
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1);
|
||||
|
||||
final ClassicHttpRequest req2 = HttpTestUtils.makeDefaultRequest();
|
||||
req2.setHeader("Cache-Control","stale-if-error=2");
|
||||
final ClassicHttpResponse resp2 = HttpTestUtils.make500Response();
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp2);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
|
||||
replayMocks();
|
||||
execute(req1);
|
||||
final ClassicHttpResponse result = execute(req2);
|
||||
verifyMocks();
|
||||
|
||||
assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR,
|
||||
result.getCode());
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp2);
|
||||
|
||||
final ClassicHttpResponse result = execute(req2);
|
||||
|
||||
assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, result.getCode());
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -372,14 +409,12 @@ public class TestRFC5861Compliance extends AbstractProtocolTest {
|
|||
resp1.setHeader("ETag","\"etag\"");
|
||||
resp1.setHeader("Date", DateUtils.formatDate(tenSecondsAgo));
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1).times(1,2);
|
||||
|
||||
final ClassicHttpRequest req2 = new BasicClassicHttpRequest("GET", "/");
|
||||
|
||||
replayMocks();
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
|
||||
execute(req1);
|
||||
final ClassicHttpResponse result = execute(req2);
|
||||
verifyMocks();
|
||||
|
||||
assertEquals(HttpStatus.SC_OK, result.getCode());
|
||||
boolean warning110Found = false;
|
||||
|
@ -392,6 +427,9 @@ public class TestRFC5861Compliance extends AbstractProtocolTest {
|
|||
}
|
||||
}
|
||||
assertTrue(warning110Found);
|
||||
|
||||
Mockito.verify(mockExecChain, Mockito.atLeastOnce()).proceed(Mockito.any(), Mockito.any());
|
||||
Mockito.verify(mockExecChain, Mockito.atMost(2)).proceed(Mockito.any(), Mockito.any());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -409,14 +447,12 @@ public class TestRFC5861Compliance extends AbstractProtocolTest {
|
|||
resp1.setHeader("Cache-Control", "public, max-age=5, stale-while-revalidate=15");
|
||||
resp1.setHeader("Date", DateUtils.formatDate(tenSecondsAgo));
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1).times(1, 2);
|
||||
|
||||
final ClassicHttpRequest req2 = new BasicClassicHttpRequest("GET", "/");
|
||||
|
||||
replayMocks();
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
|
||||
execute(req1);
|
||||
final ClassicHttpResponse result = execute(req2);
|
||||
verifyMocks();
|
||||
|
||||
assertEquals(HttpStatus.SC_OK, result.getCode());
|
||||
boolean warning110Found = false;
|
||||
|
@ -429,6 +465,9 @@ public class TestRFC5861Compliance extends AbstractProtocolTest {
|
|||
}
|
||||
}
|
||||
assertTrue(warning110Found);
|
||||
|
||||
Mockito.verify(mockExecChain, Mockito.atLeastOnce()).proceed(Mockito.any(), Mockito.any());
|
||||
Mockito.verify(mockExecChain, Mockito.atMost(2)).proceed(Mockito.any(), Mockito.any());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -451,15 +490,13 @@ public class TestRFC5861Compliance extends AbstractProtocolTest {
|
|||
resp1.setHeader("ETag","\"etag\"");
|
||||
resp1.setHeader("Date", DateUtils.formatDate(tenSecondsAgo));
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1).times(1,2);
|
||||
|
||||
final ClassicHttpRequest req2 = new BasicClassicHttpRequest("GET", "/");
|
||||
req2.setHeader("If-None-Match","\"etag\"");
|
||||
|
||||
replayMocks();
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
|
||||
execute(req1);
|
||||
final ClassicHttpResponse result = execute(req2);
|
||||
verifyMocks();
|
||||
|
||||
assertEquals(HttpStatus.SC_NOT_MODIFIED, result.getCode());
|
||||
boolean warning110Found = false;
|
||||
|
@ -472,8 +509,10 @@ public class TestRFC5861Compliance extends AbstractProtocolTest {
|
|||
}
|
||||
}
|
||||
assertTrue(warning110Found);
|
||||
}
|
||||
|
||||
Mockito.verify(mockExecChain, Mockito.atLeastOnce()).proceed(Mockito.any(), Mockito.any());
|
||||
Mockito.verify(mockExecChain, Mockito.atMost(2)).proceed(Mockito.any(), Mockito.any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStaleWhileRevalidateYieldsToMustRevalidate()
|
||||
|
@ -495,20 +534,19 @@ public class TestRFC5861Compliance extends AbstractProtocolTest {
|
|||
resp1.setHeader("ETag","\"etag\"");
|
||||
resp1.setHeader("Date", DateUtils.formatDate(tenSecondsAgo));
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1);
|
||||
|
||||
final ClassicHttpRequest req2 = new BasicClassicHttpRequest("GET", "/");
|
||||
final ClassicHttpResponse resp2 = HttpTestUtils.make200Response();
|
||||
resp2.setHeader("Cache-Control", "public, max-age=5, stale-while-revalidate=15, must-revalidate");
|
||||
resp2.setHeader("ETag","\"etag\"");
|
||||
resp2.setHeader("Date", DateUtils.formatDate(now));
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp2);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
|
||||
replayMocks();
|
||||
execute(req1);
|
||||
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp2);
|
||||
|
||||
final ClassicHttpResponse result = execute(req2);
|
||||
verifyMocks();
|
||||
|
||||
assertEquals(HttpStatus.SC_OK, result.getCode());
|
||||
boolean warning110Found = false;
|
||||
|
@ -544,20 +582,19 @@ public class TestRFC5861Compliance extends AbstractProtocolTest {
|
|||
resp1.setHeader("ETag","\"etag\"");
|
||||
resp1.setHeader("Date", DateUtils.formatDate(tenSecondsAgo));
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1);
|
||||
|
||||
final ClassicHttpRequest req2 = new BasicClassicHttpRequest("GET", "/");
|
||||
final ClassicHttpResponse resp2 = HttpTestUtils.make200Response();
|
||||
resp2.setHeader("Cache-Control", "public, max-age=5, stale-while-revalidate=15, proxy-revalidate");
|
||||
resp2.setHeader("ETag","\"etag\"");
|
||||
resp2.setHeader("Date", DateUtils.formatDate(now));
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp2);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
|
||||
replayMocks();
|
||||
execute(req1);
|
||||
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp2);
|
||||
|
||||
final ClassicHttpResponse result = execute(req2);
|
||||
verifyMocks();
|
||||
|
||||
assertEquals(HttpStatus.SC_OK, result.getCode());
|
||||
boolean warning110Found = false;
|
||||
|
@ -593,8 +630,6 @@ public class TestRFC5861Compliance extends AbstractProtocolTest {
|
|||
resp1.setHeader("ETag","\"etag\"");
|
||||
resp1.setHeader("Date", DateUtils.formatDate(tenSecondsAgo));
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp1);
|
||||
|
||||
final ClassicHttpRequest req2 = new BasicClassicHttpRequest("GET", "/");
|
||||
req2.setHeader("Cache-Control","min-fresh=2");
|
||||
final ClassicHttpResponse resp2 = HttpTestUtils.make200Response();
|
||||
|
@ -602,12 +637,13 @@ public class TestRFC5861Compliance extends AbstractProtocolTest {
|
|||
resp2.setHeader("ETag","\"etag\"");
|
||||
resp2.setHeader("Date", DateUtils.formatDate(now));
|
||||
|
||||
backendExpectsAnyRequestAndReturn(resp2);
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);
|
||||
|
||||
replayMocks();
|
||||
execute(req1);
|
||||
|
||||
Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp2);
|
||||
|
||||
final ClassicHttpResponse result = execute(req2);
|
||||
verifyMocks();
|
||||
|
||||
assertEquals(HttpStatus.SC_OK, result.getCode());
|
||||
boolean warning110Found = false;
|
||||
|
|
7
pom.xml
7
pom.xml
|
@ -70,7 +70,6 @@
|
|||
<memcached.version>2.12.3</memcached.version>
|
||||
<slf4j.version>1.7.25</slf4j.version>
|
||||
<junit.version>4.13</junit.version>
|
||||
<easymock.version>3.6</easymock.version>
|
||||
<mockito.version>3.10.0</mockito.version>
|
||||
<jna.version>5.2.0</jna.version>
|
||||
<hc.stylecheck.version>1</hc.stylecheck.version>
|
||||
|
@ -189,12 +188,6 @@
|
|||
<version>${mockito.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.easymock</groupId>
|
||||
<artifactId>easymock</artifactId>
|
||||
<version>${easymock.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
|
Loading…
Reference in New Issue