diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/BasicHttpCache.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/BasicHttpCache.java index a94fa782d..17fa46411 100644 --- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/BasicHttpCache.java +++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/BasicHttpCache.java @@ -83,6 +83,10 @@ class BasicHttpCache implements HttpCache { String uri = uriExtractor.getURI(host, request); storage.removeEntry(uri); } + + public void flushInvalidatedCacheEntriesFor(HttpHost host, HttpRequest request, HttpResponse response) { + cacheInvalidator.flushInvalidatedCacheEntries(host, request, response); + } void storeInCache( HttpHost target, HttpRequest request, HttpCacheEntry entry) throws IOException { diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheInvalidator.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheInvalidator.java index 0c080aa80..56de28e00 100644 --- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheInvalidator.java +++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheInvalidator.java @@ -189,6 +189,8 @@ class CacheInvalidator { */ public void flushInvalidatedCacheEntries(HttpHost host, HttpRequest request, HttpResponse response) { + int status = response.getStatusLine().getStatusCode(); + if (status < 200 || status > 299) return; URL reqURL = getAbsoluteURL(cacheKeyGenerator.getURI(host, request)); if (reqURL == null) return; URL canonURL = getContentLocationURL(reqURL, response); diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClient.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClient.java index 4230bc62d..6bdaa0bf2 100644 --- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClient.java +++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClient.java @@ -840,6 +840,7 @@ public class CachingHttpClient implements HttpClient { responseCompliance.ensureProtocolCompliance(request, backendResponse); boolean cacheable = responseCachingPolicy.isResponseCacheable(request, backendResponse); + responseCache.flushInvalidatedCacheEntriesFor(target, request, backendResponse); if (cacheable && !alreadyHaveNewerCacheEntry(target, request, backendResponse)) { try { diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/HttpCache.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/HttpCache.java index bdeea9a33..6d8a85932 100644 --- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/HttpCache.java +++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/HttpCache.java @@ -56,6 +56,15 @@ interface HttpCache { */ void flushInvalidatedCacheEntriesFor(HttpHost host, HttpRequest request) throws IOException; + + /** Clear any entries that may be invalidated by the given response to + * a particular request. + * @param host + * @param request + * @param response + */ + void flushInvalidatedCacheEntriesFor(HttpHost host, HttpRequest request, + HttpResponse response); /** * Retrieve matching {@link HttpCacheEntry} from the cache if it exists diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/AbstractProtocolTest.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/AbstractProtocolTest.java index 09f6f3944..cab7158d7 100644 --- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/AbstractProtocolTest.java +++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/AbstractProtocolTest.java @@ -113,6 +113,9 @@ public abstract class AbstractProtocolTest { mockCache.flushInvalidatedCacheEntriesFor(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class)); EasyMock.expectLastCall().anyTimes(); + + mockCache.flushInvalidatedCacheEntriesFor(EasyMock.isA(HttpHost.class), EasyMock.isA(HttpRequest.class), EasyMock.isA(HttpResponse.class)); + EasyMock.expectLastCall().anyTimes(); } protected void behaveAsNonSharedCache() { diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheInvalidator.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheInvalidator.java index 34c9bc59d..9d2cc2185 100644 --- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheInvalidator.java +++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheInvalidator.java @@ -36,6 +36,8 @@ import org.apache.http.HttpEntityEnclosingRequest; import org.apache.http.HttpHost; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.HttpVersion; import org.apache.http.ProtocolVersion; import org.apache.http.client.cache.HttpCacheEntry; import org.apache.http.client.cache.HttpCacheStorage; @@ -44,6 +46,8 @@ import static org.apache.http.impl.cookie.DateUtils.formatDate; import org.apache.http.message.BasicHeader; import org.apache.http.message.BasicHttpEntityEnclosingRequest; import org.apache.http.message.BasicHttpRequest; +import org.apache.http.message.BasicHttpResponse; + import static org.easymock.classextension.EasyMock.*; import org.junit.Before; import org.junit.Test; @@ -290,6 +294,27 @@ public class TestCacheInvalidator { impl.flushInvalidatedCacheEntries(host, request, response); verifyMocks(); } + + @Test + public void doesNotFlushEntryForUnsuccessfulResponse() + throws Exception { + response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_BAD_REQUEST, "Bad Request"); + response.setHeader("ETag","\"new-etag\""); + response.setHeader("Date", formatDate(now)); + String theURI = "http://foo.example.com:80/bar"; + response.setHeader("Content-Location", theURI); + + HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] { + new BasicHeader("Date", formatDate(tenSecondsAgo)), + new BasicHeader("ETag", "\"old-etag\"") + }); + + expect(mockStorage.getEntry(theURI)).andReturn(entry).anyTimes(); + + replayMocks(); + impl.flushInvalidatedCacheEntries(host, request, response); + verifyMocks(); + } @Test public void flushesEntryIfFresherAndSpecifiedByNonCanonicalContentLocation() diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachingHttpClient.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachingHttpClient.java index 09e0399ca..c0ebab7ea 100644 --- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachingHttpClient.java +++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCachingHttpClient.java @@ -47,6 +47,7 @@ import org.apache.http.client.ResponseHandler; import org.apache.http.client.cache.CacheResponseStatus; import org.apache.http.client.cache.HeaderConstants; import org.apache.http.client.cache.HttpCacheEntry; +import org.apache.http.client.cache.HttpCacheStorage; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.conn.ClientConnectionManager; @@ -59,7 +60,9 @@ import org.apache.http.params.HttpParams; import org.apache.http.protocol.BasicHttpContext; import org.apache.http.protocol.HttpContext; import org.easymock.Capture; -import org.easymock.classextension.EasyMock; +import static org.easymock.classextension.EasyMock.*; +import static org.junit.Assert.*; + import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -81,6 +84,7 @@ public class TestCachingHttpClient { private CacheableRequestPolicy mockRequestPolicy; private HttpClient mockBackend; private HttpCache mockCache; + private HttpCacheStorage mockStorage; private CachedResponseSuitabilityChecker mockSuitabilityChecker; private ResponseCachingPolicy mockResponsePolicy; private HttpResponse mockBackendResponse; @@ -107,24 +111,25 @@ public class TestCachingHttpClient { @SuppressWarnings("unchecked") @Before public void setUp() { - mockRequestPolicy = EasyMock.createMock(CacheableRequestPolicy.class); - mockValidityPolicy = EasyMock.createMock(CacheValidityPolicy.class); - mockBackend = EasyMock.createMock(HttpClient.class); - mockCache = EasyMock.createMock(HttpCache.class); - mockSuitabilityChecker = EasyMock.createMock(CachedResponseSuitabilityChecker.class); - mockResponsePolicy = EasyMock.createMock(ResponseCachingPolicy.class); - mockConnectionManager = EasyMock.createMock(ClientConnectionManager.class); - mockHandler = EasyMock.createMock(ResponseHandler.class); - mockBackendResponse = EasyMock.createMock(HttpResponse.class); - mockUriRequest = EasyMock.createMock(HttpUriRequest.class); - mockCacheEntry = EasyMock.createMock(HttpCacheEntry.class); - mockResponseGenerator = EasyMock.createMock(CachedHttpResponseGenerator.class); - mockCachedResponse = EasyMock.createMock(HttpResponse.class); - mockConditionalRequestBuilder = EasyMock.createMock(ConditionalRequestBuilder.class); - mockConditionalRequest = EasyMock.createMock(HttpRequest.class); - mockStatusLine = EasyMock.createMock(StatusLine.class); - mockResponseProtocolCompliance = EasyMock.createMock(ResponseProtocolCompliance.class); - mockRequestProtocolCompliance = EasyMock.createMock(RequestProtocolCompliance.class); + mockRequestPolicy = createMock(CacheableRequestPolicy.class); + mockValidityPolicy = createMock(CacheValidityPolicy.class); + mockBackend = createMock(HttpClient.class); + mockCache = createMock(HttpCache.class); + mockSuitabilityChecker = createMock(CachedResponseSuitabilityChecker.class); + mockResponsePolicy = createMock(ResponseCachingPolicy.class); + mockConnectionManager = createMock(ClientConnectionManager.class); + mockHandler = createMock(ResponseHandler.class); + mockBackendResponse = createMock(HttpResponse.class); + mockUriRequest = createMock(HttpUriRequest.class); + mockCacheEntry = createMock(HttpCacheEntry.class); + mockResponseGenerator = createMock(CachedHttpResponseGenerator.class); + mockCachedResponse = createMock(HttpResponse.class); + mockConditionalRequestBuilder = createMock(ConditionalRequestBuilder.class); + mockConditionalRequest = createMock(HttpRequest.class); + mockStatusLine = createMock(StatusLine.class); + mockResponseProtocolCompliance = createMock(ResponseProtocolCompliance.class); + mockRequestProtocolCompliance = createMock(RequestProtocolCompliance.class); + mockStorage = createMock(HttpCacheStorage.class); requestDate = new Date(System.currentTimeMillis() - 1000); responseDate = new Date(); @@ -147,123 +152,144 @@ public class TestCachingHttpClient { } private void replayMocks() { - EasyMock.replay(mockRequestPolicy); - EasyMock.replay(mockValidityPolicy); - EasyMock.replay(mockSuitabilityChecker); - EasyMock.replay(mockResponsePolicy); - EasyMock.replay(mockCacheEntry); - EasyMock.replay(mockResponseGenerator); - EasyMock.replay(mockBackend); - EasyMock.replay(mockCache); - EasyMock.replay(mockConnectionManager); - EasyMock.replay(mockHandler); - EasyMock.replay(mockBackendResponse); - EasyMock.replay(mockUriRequest); - EasyMock.replay(mockCachedResponse); - EasyMock.replay(mockConditionalRequestBuilder); - EasyMock.replay(mockConditionalRequest); - EasyMock.replay(mockStatusLine); - EasyMock.replay(mockResponseProtocolCompliance); - EasyMock.replay(mockRequestProtocolCompliance); + replay(mockRequestPolicy); + replay(mockValidityPolicy); + replay(mockSuitabilityChecker); + replay(mockResponsePolicy); + replay(mockCacheEntry); + replay(mockResponseGenerator); + replay(mockBackend); + replay(mockCache); + replay(mockConnectionManager); + replay(mockHandler); + replay(mockBackendResponse); + replay(mockUriRequest); + replay(mockCachedResponse); + replay(mockConditionalRequestBuilder); + replay(mockConditionalRequest); + replay(mockStatusLine); + replay(mockResponseProtocolCompliance); + replay(mockRequestProtocolCompliance); + replay(mockStorage); if (mockedImpl) { - EasyMock.replay(impl); + replay(impl); } } private void verifyMocks() { - EasyMock.verify(mockRequestPolicy); - EasyMock.verify(mockValidityPolicy); - EasyMock.verify(mockSuitabilityChecker); - EasyMock.verify(mockResponsePolicy); - EasyMock.verify(mockCacheEntry); - EasyMock.verify(mockResponseGenerator); - EasyMock.verify(mockBackend); - EasyMock.verify(mockCache); - EasyMock.verify(mockConnectionManager); - EasyMock.verify(mockHandler); - EasyMock.verify(mockBackendResponse); - EasyMock.verify(mockUriRequest); - EasyMock.verify(mockCachedResponse); - EasyMock.verify(mockConditionalRequestBuilder); - EasyMock.verify(mockConditionalRequest); - EasyMock.verify(mockStatusLine); - EasyMock.verify(mockResponseProtocolCompliance); - EasyMock.verify(mockRequestProtocolCompliance); + verify(mockRequestPolicy); + verify(mockValidityPolicy); + verify(mockSuitabilityChecker); + verify(mockResponsePolicy); + verify(mockCacheEntry); + verify(mockResponseGenerator); + verify(mockBackend); + verify(mockCache); + verify(mockConnectionManager); + verify(mockHandler); + verify(mockBackendResponse); + verify(mockUriRequest); + verify(mockCachedResponse); + verify(mockConditionalRequestBuilder); + verify(mockConditionalRequest); + verify(mockStatusLine); + verify(mockResponseProtocolCompliance); + verify(mockRequestProtocolCompliance); + verify(mockStorage); if (mockedImpl) { - EasyMock.verify(impl); + verify(impl); } } @Test public void testCacheableResponsesGoIntoCache() throws Exception { - responsePolicyAllowsCaching(true); - - responseProtocolValidationIsCalled(); - - EasyMock.expect(mockCache.getCacheEntry(host, request)) - .andReturn(null); - EasyMock.expect(mockCache.cacheAndReturnResponse(host, request, mockBackendResponse, requestDate, responseDate)) - .andReturn(mockCachedResponse); - + impl = new CachingHttpClient(mockBackend); + + HttpRequest req1 = HttpTestUtils.makeDefaultRequest(); + HttpResponse resp1 = HttpTestUtils.make200Response(); + resp1.setHeader("Cache-Control","max-age=3600"); + + expect(mockBackend.execute(isA(HttpHost.class), isA(HttpRequest.class), + (HttpContext)isNull())).andReturn(resp1); + + HttpRequest req2 = HttpTestUtils.makeDefaultRequest(); + replayMocks(); - HttpResponse result = impl.handleBackendResponse(host, request, requestDate, - responseDate, mockBackendResponse); + impl.execute(host, req1); + impl.execute(host, req2); verifyMocks(); - - Assert.assertSame(mockCachedResponse, result); } @Test public void testOlderCacheableResponsesDoNotGoIntoCache() throws Exception { - responsePolicyAllowsCaching(true); - responseProtocolValidationIsCalled(); - + impl = new CachingHttpClient(mockBackend); Date now = new Date(); Date fiveSecondsAgo = new Date(now.getTime() - 5 * 1000L); - Header entryDateHeader = new BasicHeader("Date", DateUtils.formatDate(now)); - Header[] headers = { entryDateHeader }; - entry = HttpTestUtils.makeCacheEntry(headers); - Header responseDateHeader = new BasicHeader("Date", DateUtils.formatDate(fiveSecondsAgo)); + + HttpRequest req1 = HttpTestUtils.makeDefaultRequest(); + HttpResponse resp1 = HttpTestUtils.make200Response(); + resp1.setHeader("Date", DateUtils.formatDate(now)); + resp1.setHeader("Cache-Control", "max-age=3600"); + resp1.setHeader("Etag", "\"new-etag\""); - EasyMock.expect(mockCache.getCacheEntry(host, request)) - .andReturn(entry); - EasyMock.expect(mockBackendResponse.getFirstHeader("Date")) - .andReturn(responseDateHeader).anyTimes(); + expect(mockBackend.execute(isA(HttpHost.class), isA(HttpRequest.class), + (HttpContext)isNull())).andReturn(resp1); + + HttpRequest req2 = HttpTestUtils.makeDefaultRequest(); + req2.setHeader("Cache-Control","no-cache"); + HttpResponse resp2 = HttpTestUtils.make200Response(); + resp2.setHeader("ETag", "\"old-etag\""); + resp2.setHeader("Date", DateUtils.formatDate(fiveSecondsAgo)); + resp2.setHeader("Cache-Control","max-age=3600"); + + expect(mockBackend.execute(isA(HttpHost.class), isA(HttpRequest.class), + (HttpContext)isNull())).andReturn(resp2); + + HttpRequest req3 = HttpTestUtils.makeDefaultRequest(); replayMocks(); - HttpResponse result = impl.handleBackendResponse(host, request, requestDate, - responseDate, mockBackendResponse); + impl.execute(host, req1); + impl.execute(host, req2); + HttpResponse result = impl.execute(host, req3); verifyMocks(); - Assert.assertSame(mockBackendResponse, result); + assertEquals("\"new-etag\"", result.getFirstHeader("ETag").getValue()); } @Test public void testNewerCacheableResponsesReplaceExistingCacheEntry() throws Exception { - responsePolicyAllowsCaching(true); - responseProtocolValidationIsCalled(); - + impl = new CachingHttpClient(mockBackend); Date now = new Date(); Date fiveSecondsAgo = new Date(now.getTime() - 5 * 1000L); - Header entryDateHeader = new BasicHeader("Date", DateUtils.formatDate(fiveSecondsAgo)); - Header[] headers = { entryDateHeader }; - entry = HttpTestUtils.makeCacheEntry(headers); - Header responseDateHeader = new BasicHeader("Date", DateUtils.formatDate(now)); + + HttpRequest req1 = HttpTestUtils.makeDefaultRequest(); + HttpResponse resp1 = HttpTestUtils.make200Response(); + resp1.setHeader("Date", DateUtils.formatDate(fiveSecondsAgo)); + resp1.setHeader("Cache-Control", "max-age=3600"); + resp1.setHeader("Etag", "\"old-etag\""); - EasyMock.expect(mockCache.getCacheEntry(host, request)) - .andReturn(entry); - EasyMock.expect(mockBackendResponse.getFirstHeader("Date")) - .andReturn(responseDateHeader).anyTimes(); - EasyMock.expect(mockCache.cacheAndReturnResponse(host, request, - mockBackendResponse, requestDate, responseDate)) - .andReturn(mockCachedResponse); + expect(mockBackend.execute(isA(HttpHost.class), isA(HttpRequest.class), + (HttpContext)isNull())).andReturn(resp1); + + HttpRequest req2 = HttpTestUtils.makeDefaultRequest(); + req2.setHeader("Cache-Control","max-age=0"); + HttpResponse resp2 = HttpTestUtils.make200Response(); + resp2.setHeader("ETag", "\"new-etag\""); + resp2.setHeader("Date", DateUtils.formatDate(now)); + resp2.setHeader("Cache-Control","max-age=3600"); + + expect(mockBackend.execute(isA(HttpHost.class), isA(HttpRequest.class), + (HttpContext)isNull())).andReturn(resp2); + + HttpRequest req3 = HttpTestUtils.makeDefaultRequest(); replayMocks(); - HttpResponse result = impl.handleBackendResponse(host, request, requestDate, - responseDate, mockBackendResponse); + impl.execute(host, req1); + impl.execute(host, req2); + HttpResponse result = impl.execute(host, req3); verifyMocks(); - Assert.assertSame(mockCachedResponse, result); + assertEquals("\"new-etag\"", result.getFirstHeader("ETag").getValue()); } @@ -289,7 +315,7 @@ public class TestCachingHttpClient { if (error != null) { errors.add(error); } - EasyMock.expect( + expect( mockRequestProtocolCompliance.requestIsFatallyNonCompliant(request)).andReturn( errors); } @@ -381,7 +407,7 @@ public class TestCachingHttpClient { getCurrentDateReturns(requestDate); backendCall(validate, originResponse); getCurrentDateReturns(responseDate); - EasyMock.expect(impl.handleBackendResponse(host, validate, + expect(impl.handleBackendResponse(host, validate, requestDate, responseDate, originResponse)) .andReturn(finalResponse); @@ -410,10 +436,10 @@ public class TestCachingHttpClient { getCurrentDateReturns(requestDate); backendCall(validate, originResponse); getCurrentDateReturns(responseDate); - EasyMock.expect(mockCache.updateCacheEntry(host, request, + expect(mockCache.updateCacheEntry(host, request, entry, originResponse, requestDate, responseDate)) .andReturn(updatedEntry); - EasyMock.expect(mockSuitabilityChecker.isConditional(request)).andReturn(false); + expect(mockSuitabilityChecker.isConditional(request)).andReturn(false); responseIsGeneratedFromCache(); replayMocks(); @@ -421,90 +447,6 @@ public class TestCachingHttpClient { verifyMocks(); } - @Test - public void testRevalidationUpdatesCacheEntryAndPutsItToCacheWhen200ReturningCachedResponse() - throws Exception { - - mockImplMethods(GET_CURRENT_DATE); - - HttpRequest validate = - new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1); - HttpResponse originResponse = HttpTestUtils.make200Response(); - HttpResponse finalResponse = HttpTestUtils.make200Response(); - - conditionalRequestBuilderReturns(validate); - getCurrentDateReturns(requestDate); - backendCall(validate, originResponse); - getCurrentDateReturns(responseDate); - responsePolicyAllowsCaching(true); - responseProtocolValidationIsCalled(); - EasyMock.expect(mockCache.getCacheEntry(host, validate)).andReturn(null); - EasyMock.expect(mockCache.cacheAndReturnResponse(host, validate, originResponse, requestDate, responseDate)) - .andReturn(finalResponse); - - replayMocks(); - HttpResponse result = - impl.revalidateCacheEntry(host, request, context, entry); - verifyMocks(); - - Assert.assertSame(finalResponse, result); - } - - @Test - public void testRevalidationRetriesUnconditionallyIfOlderResponseReceived() - throws Exception { - - mockImplMethods(GET_CURRENT_DATE); - - Date now = new Date(); - Date tenSecondsAgo = new Date(now.getTime() - 10 * 1000L); - Date elevenSecondsAgo = new Date(now.getTime() - 11 * 1000L); - - Header[] headers = { - new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)), - new BasicHeader("Cache-Control","max-age=5"), - new BasicHeader("ETag", "\"etag1\"") - }; - entry = HttpTestUtils.makeCacheEntry(headers); - - HttpRequest validate = - new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1); - HttpResponse originResponse1 = - new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_NOT_MODIFIED, - "Not Modified"); - originResponse1.setHeader("Date", DateUtils.formatDate(elevenSecondsAgo)); - HttpRequest unconditional = - new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1); - HttpResponse originResponse2 = HttpTestUtils.make200Response(); - HttpResponse finalResponse = HttpTestUtils.make200Response(); - - conditionalRequestBuilderReturns(validate); - getCurrentDateReturns(requestDate); - backendCall(validate, originResponse1); - getCurrentDateReturns(responseDate); - EasyMock.expect(mockConditionalRequestBuilder.buildUnconditionalRequest(request, entry)) - .andReturn(unconditional); - final Date requestDate2 = new Date(); - getCurrentDateReturns(requestDate2); - backendCall(unconditional, originResponse2); - final Date responseDate2 = new Date(); - getCurrentDateReturns(responseDate2); - - responsePolicyAllowsCaching(true); - responseProtocolValidationIsCalled(); - EasyMock.expect(mockCache.getCacheEntry(host, validate)).andReturn(null); - EasyMock.expect(mockCache.cacheAndReturnResponse(host, validate, originResponse2, requestDate2, responseDate2)) - .andReturn(finalResponse); - - replayMocks(); - HttpResponse result = - impl.revalidateCacheEntry(host, request, context, entry); - verifyMocks(); - - Assert.assertSame(finalResponse, result); - - } - @Test public void testSuitableCacheEntryDoesNotCauseBackendRequest() throws Exception { cacheInvalidatorWasCalled(); @@ -541,18 +483,26 @@ public class TestCachingHttpClient { @Test public void testNonCacheableResponseIsNotCachedAndIsReturnedAsIs() throws Exception { - Date currentDate = new Date(); - responsePolicyAllowsCaching(false); - responseProtocolValidationIsCalled(); + CacheConfig config = new CacheConfig(); + impl = new CachingHttpClient(mockBackend, + new BasicHttpCache(new HeapResourceFactory(), mockStorage, config), + config); + + HttpRequest req1 = HttpTestUtils.makeDefaultRequest(); + HttpResponse resp1 = HttpTestUtils.make200Response(); + resp1.setHeader("Cache-Control","no-cache"); - flushCache(); + expect(mockStorage.getEntry(isA(String.class))).andReturn(null).anyTimes(); + mockStorage.removeEntry(isA(String.class)); + expectLastCall().anyTimes(); + expect(mockBackend.execute(isA(HttpHost.class), isA(HttpRequest.class), + (HttpContext)isNull())).andReturn(resp1); replayMocks(); - HttpResponse result = impl.handleBackendResponse(host, request, currentDate, - currentDate, mockBackendResponse); + HttpResponse result = impl.execute(host, req1); verifyMocks(); - Assert.assertSame(mockBackendResponse, result); + assertTrue(HttpTestUtils.semanticallyTransparent(resp1, result)); } @@ -627,7 +577,7 @@ public class TestCachingHttpClient { } }; - EasyMock.expect(mockHandler.handleResponse(mockBackendResponse)).andReturn( + expect(mockHandler.handleResponse(mockBackendResponse)).andReturn( value); replayMocks(); @@ -669,7 +619,7 @@ public class TestCachingHttpClient { final Object theObject = new Object(); - EasyMock.expect(mockHandler.handleResponse(mockBackendResponse)).andReturn( + expect(mockHandler.handleResponse(mockBackendResponse)).andReturn( theObject); replayMocks(); @@ -743,7 +693,7 @@ public class TestCachingHttpClient { } }; - EasyMock.expect(mockUriRequest.getURI()).andReturn(uri); + expect(mockUriRequest.getURI()).andReturn(uri); replayMocks(); HttpResponse result = impl.execute(mockUriRequest, context); @@ -780,7 +730,7 @@ public class TestCachingHttpClient { } }; - EasyMock.expect(mockHandler.handleResponse(mockBackendResponse)).andReturn( + expect(mockHandler.handleResponse(mockBackendResponse)).andReturn( theValue); replayMocks(); @@ -821,7 +771,7 @@ public class TestCachingHttpClient { } }; - EasyMock.expect(mockHandler.handleResponse(mockBackendResponse)).andReturn( + expect(mockHandler.handleResponse(mockBackendResponse)).andReturn( theValue); replayMocks(); @@ -833,7 +783,7 @@ public class TestCachingHttpClient { @Test public void testUsesBackendsConnectionManager() { - EasyMock.expect(mockBackend.getConnectionManager()).andReturn( + expect(mockBackend.getConnectionManager()).andReturn( mockConnectionManager); replayMocks(); ClientConnectionManager result = impl.getConnectionManager(); @@ -843,7 +793,7 @@ public class TestCachingHttpClient { @Test public void testUsesBackendsHttpParams() { - EasyMock.expect(mockBackend.getParams()).andReturn(params); + expect(mockBackend.getParams()).andReturn(params); replayMocks(); HttpParams result = impl.getParams(); verifyMocks(); @@ -921,8 +871,8 @@ public class TestCachingHttpClient { HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_NO_CONTENT, "No Content"); Capture cap = new Capture(); - EasyMock.expect(mockBackend.execute(EasyMock.isA(HttpHost.class), - EasyMock.capture(cap), EasyMock.isA(HttpContext.class))) + expect(mockBackend.execute(isA(HttpHost.class), + capture(cap), isA(HttpContext.class))) .andReturn(resp); replayMocks(); @@ -944,8 +894,8 @@ public class TestCachingHttpClient { req.setHeader("Cache-Control","no-cache"); HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_NO_CONTENT, "No Content"); - EasyMock.expect(mockBackend.execute(EasyMock.isA(HttpHost.class), - EasyMock.isA(HttpRequest.class), EasyMock.isA(HttpContext.class))) + expect(mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), isA(HttpContext.class))) .andReturn(resp); replayMocks(); @@ -963,8 +913,8 @@ public class TestCachingHttpClient { req.setHeader("Cache-Control","no-cache"); HttpResponse resp = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_NO_CONTENT, "No Content"); - EasyMock.expect(mockBackend.execute(EasyMock.isA(HttpHost.class), - EasyMock.isA(HttpRequest.class), (HttpContext)EasyMock.isNull())) + expect(mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), (HttpContext)isNull())) .andReturn(resp); replayMocks(); @@ -985,8 +935,8 @@ public class TestCachingHttpClient { resp1.setHeader("Date", DateUtils.formatDate(new Date())); resp1.setHeader("Cache-Control","public, max-age=3600"); - EasyMock.expect(mockBackend.execute(EasyMock.isA(HttpHost.class), - EasyMock.isA(HttpRequest.class), EasyMock.isA(HttpContext.class))) + expect(mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), isA(HttpContext.class))) .andReturn(resp1); replayMocks(); @@ -1008,8 +958,8 @@ public class TestCachingHttpClient { resp1.setHeader("Date", DateUtils.formatDate(new Date())); resp1.setHeader("Cache-Control","public, max-age=3600"); - EasyMock.expect(mockBackend.execute(EasyMock.isA(HttpHost.class), - EasyMock.isA(HttpRequest.class), EasyMock.isA(HttpContext.class))) + expect(mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), isA(HttpContext.class))) .andReturn(resp1); replayMocks(); @@ -1033,8 +983,8 @@ public class TestCachingHttpClient { resp1.setHeader("Date", DateUtils.formatDate(new Date())); resp1.setHeader("Cache-Control","public, max-age=3600"); - EasyMock.expect(mockBackend.execute(EasyMock.isA(HttpHost.class), - EasyMock.isA(HttpRequest.class), (HttpContext)EasyMock.isNull())) + expect(mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), (HttpContext)isNull())) .andReturn(resp1); replayMocks(); @@ -1062,10 +1012,10 @@ public class TestCachingHttpClient { resp1.setHeader("Cache-Control", "public, max-age=3600"); resp1.setHeader("Last-Modified", DateUtils.formatDate(tenSecondsAgo)); - EasyMock.expect( - mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock - .isA(HttpRequest.class), (HttpContext) EasyMock - .isNull())).andReturn(resp1); + expect( + mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), (HttpContext) + isNull())).andReturn(resp1); replayMocks(); impl.execute(host, req1); @@ -1098,14 +1048,14 @@ public class TestCachingHttpClient { HttpResponse resp2 = HttpTestUtils.make200Response(); - EasyMock.expect( - mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock - .isA(HttpRequest.class), (HttpContext) EasyMock - .isNull())).andReturn(resp1); - EasyMock.expect( - mockBackend.execute(EasyMock.isA(HttpHost.class), - EasyMock.isA(HttpRequest.class), - (HttpContext) EasyMock.isNull())) + expect( + mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), (HttpContext) + isNull())).andReturn(resp1); + expect( + mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), + (HttpContext) isNull())) .andReturn(resp2); replayMocks(); @@ -1138,10 +1088,10 @@ public class TestCachingHttpClient { req2.addHeader("If-Modified-Since", DateUtils .formatDate(tenSecondsAfter)); - EasyMock.expect( - mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock - .isA(HttpRequest.class), (HttpContext) EasyMock - .isNull())).andReturn(resp1).times(2); + expect( + mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), (HttpContext) + isNull())).andReturn(resp1).times(2); replayMocks(); impl.execute(host, req1); @@ -1166,10 +1116,10 @@ public class TestCachingHttpClient { resp1.setHeader("Date", DateUtils.formatDate(new Date())); resp1.setHeader("Cache-Control", "public, max-age=3600"); - EasyMock.expect( - mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock - .isA(HttpRequest.class), (HttpContext) EasyMock - .isNull())).andReturn(resp1); + expect( + mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), (HttpContext) + isNull())).andReturn(resp1); replayMocks(); impl.execute(host, req1); @@ -1197,14 +1147,14 @@ public class TestCachingHttpClient { HttpResponse resp2 = HttpTestUtils.make200Response(); - EasyMock.expect( - mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock - .isA(HttpRequest.class), (HttpContext) EasyMock - .isNull())).andReturn(resp1); - EasyMock.expect( - mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock - .isA(HttpRequest.class), (HttpContext) EasyMock - .isNull())).andReturn(resp2); + expect( + mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), (HttpContext) + isNull())).andReturn(resp1); + expect( + mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), (HttpContext) + isNull())).andReturn(resp2); replayMocks(); impl.execute(host, req1); @@ -1235,10 +1185,10 @@ public class TestCachingHttpClient { req2.addHeader("If-None-Match", "*"); req2.addHeader("If-Modified-Since", DateUtils.formatDate(now)); - EasyMock.expect( - mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock - .isA(HttpRequest.class), (HttpContext) EasyMock - .isNull())).andReturn(resp1); + expect( + mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), (HttpContext) + isNull())).andReturn(resp1); replayMocks(); impl.execute(host, req1); @@ -1267,14 +1217,14 @@ public class TestCachingHttpClient { resp1.setHeader("Cache-Control", "public, max-age=3600"); resp1.setHeader("Last-Modified", DateUtils.formatDate(tenSecondsAgo)); - EasyMock.expect( - mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock - .isA(HttpRequest.class), (HttpContext) EasyMock - .isNull())).andReturn(resp1); - EasyMock.expect( - mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock - .isA(HttpRequest.class), (HttpContext) EasyMock - .isNull())).andReturn(resp1); + expect( + mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), (HttpContext) + isNull())).andReturn(resp1); + expect( + mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), (HttpContext) + isNull())).andReturn(resp1); replayMocks(); impl.execute(host, req1); @@ -1308,11 +1258,11 @@ public class TestCachingHttpClient { resp2.setHeader("Date", DateUtils.formatDate(tenSecondsAgo)); resp2.setHeader("Cache-Control","public, max-age=5"); - EasyMock.expect(mockBackend.execute(EasyMock.isA(HttpHost.class), - EasyMock.isA(HttpRequest.class), EasyMock.isA(HttpContext.class))) + expect(mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), isA(HttpContext.class))) .andReturn(resp1); - EasyMock.expect(mockBackend.execute(EasyMock.isA(HttpHost.class), - EasyMock.isA(HttpRequest.class), EasyMock.isA(HttpContext.class))) + expect(mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), isA(HttpContext.class))) .andReturn(resp2); replayMocks(); @@ -1347,11 +1297,11 @@ public class TestCachingHttpClient { resp2.setHeader("Date", DateUtils.formatDate(tenSecondsAgo)); resp2.setHeader("Cache-Control","public, max-age=5"); - EasyMock.expect(mockBackend.execute(EasyMock.isA(HttpHost.class), - EasyMock.isA(HttpRequest.class), EasyMock.isA(HttpContext.class))) + expect(mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), isA(HttpContext.class))) .andReturn(resp1); - EasyMock.expect(mockBackend.execute(EasyMock.isA(HttpHost.class), - EasyMock.isA(HttpRequest.class), EasyMock.isA(HttpContext.class))) + expect(mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), isA(HttpContext.class))) .andReturn(resp2); replayMocks(); @@ -1379,11 +1329,11 @@ public class TestCachingHttpClient { resp1.setHeader("Date", DateUtils.formatDate(tenSecondsAgo)); resp1.setHeader("Cache-Control","public, max-age=5, must-revalidate"); - EasyMock.expect(mockBackend.execute(EasyMock.isA(HttpHost.class), - EasyMock.isA(HttpRequest.class), EasyMock.isA(HttpContext.class))) + expect(mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), isA(HttpContext.class))) .andReturn(resp1); - EasyMock.expect(mockBackend.execute(EasyMock.isA(HttpHost.class), - EasyMock.isA(HttpRequest.class), EasyMock.isA(HttpContext.class))) + expect(mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), isA(HttpContext.class))) .andThrow(new IOException()); replayMocks(); @@ -1411,11 +1361,11 @@ public class TestCachingHttpClient { resp1.setHeader("Date", DateUtils.formatDate(tenSecondsAgo)); resp1.setHeader("Cache-Control","public, max-age=5"); - EasyMock.expect(mockBackend.execute(EasyMock.isA(HttpHost.class), - EasyMock.isA(HttpRequest.class), EasyMock.isA(HttpContext.class))) + expect(mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), isA(HttpContext.class))) .andReturn(resp1); - EasyMock.expect(mockBackend.execute(EasyMock.isA(HttpHost.class), - EasyMock.isA(HttpRequest.class), EasyMock.isA(HttpContext.class))) + expect(mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), isA(HttpContext.class))) .andThrow(new IOException()); replayMocks(); @@ -1443,11 +1393,11 @@ public class TestCachingHttpClient { resp1.setHeader("Date", DateUtils.formatDate(tenSecondsAgo)); resp1.setHeader("Cache-Control","public, max-age=5"); - EasyMock.expect(mockBackend.execute(EasyMock.isA(HttpHost.class), - EasyMock.isA(HttpRequest.class), EasyMock.isA(HttpContext.class))) + expect(mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), isA(HttpContext.class))) .andReturn(resp1); - EasyMock.expect(mockBackend.execute(EasyMock.isA(HttpHost.class), - EasyMock.isA(HttpRequest.class), EasyMock.isA(HttpContext.class))) + expect(mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), isA(HttpContext.class))) .andThrow(new IOException()); replayMocks(); @@ -1482,15 +1432,15 @@ public class TestCachingHttpClient { resp2.setHeader("ETag", "\"etag\""); resp2.setHeader("Date", DateUtils.formatDate(now)); resp2.setHeader("Cache-Control", "public, max-age=5"); - EasyMock.expect( - mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock - .isA(HttpRequest.class), (HttpContext) EasyMock - .isNull())).andReturn(resp1); + expect( + mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), (HttpContext) + isNull())).andReturn(resp1); - EasyMock.expect( - mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock - .isA(HttpRequest.class), (HttpContext) EasyMock - .isNull())).andReturn(resp2); + expect( + mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), (HttpContext) + isNull())).andReturn(resp2); replayMocks(); impl.execute(host, req1); HttpResponse result = impl.execute(host, req2); @@ -1526,15 +1476,15 @@ public class TestCachingHttpClient { resp2.setHeader("ETag", "\"newetag\""); resp2.setHeader("Date", DateUtils.formatDate(tenSecondsAgo)); resp2.setHeader("Cache-Control", "public, max-age=5"); - EasyMock.expect( - mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock - .isA(HttpRequest.class), (HttpContext) EasyMock - .isNull())).andReturn(resp1); + expect( + mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), (HttpContext) + isNull())).andReturn(resp1); - EasyMock.expect( - mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock - .isA(HttpRequest.class), (HttpContext) EasyMock - .isNull())).andReturn(resp2); + expect( + mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), (HttpContext) + isNull())).andReturn(resp2); replayMocks(); impl.execute(host, req1); HttpResponse result = impl.execute(host, req2); @@ -1570,15 +1520,15 @@ public class TestCachingHttpClient { resp2.setHeader("Date", DateUtils.formatDate(tenSecondsAgo)); resp1.setHeader("Last-Modified", DateUtils.formatDate(tenSecondsAgo)); resp2.setHeader("Cache-Control", "public, max-age=5"); - EasyMock.expect( - mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock - .isA(HttpRequest.class), (HttpContext) EasyMock - .isNull())).andReturn(resp1); + expect( + mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), (HttpContext) + isNull())).andReturn(resp1); - EasyMock.expect( - mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock - .isA(HttpRequest.class), (HttpContext) EasyMock - .isNull())).andReturn(resp2); + expect( + mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), (HttpContext) + isNull())).andReturn(resp2); replayMocks(); impl.execute(host, req1); HttpResponse result = impl.execute(host, req2); @@ -1587,49 +1537,6 @@ public class TestCachingHttpClient { Assert.assertEquals(HttpStatus.SC_NOT_MODIFIED, result.getStatusLine().getStatusCode()); } - @Test - public void testNegotiateResponseFromVariantsReturns200OnBackend200() throws Exception { - HttpCacheEntry variant1 = HttpTestUtils - .makeCacheEntry(new Header[] {new BasicHeader(HeaderConstants.ETAG, "\"etag1\"") }); - HttpCacheEntry variant2 = HttpTestUtils - .makeCacheEntry(new Header[] {new BasicHeader(HeaderConstants.ETAG, "\"etag2\"") }); - HttpCacheEntry variant3 = HttpTestUtils - .makeCacheEntry(new Header[] {new BasicHeader(HeaderConstants.ETAG, "\"etag3\"") }); - - HttpCacheEntry cacheEntry = null; - - Map variants = new HashMap(); - variants.put("\"etag1\"", new Variant("A","B",variant1)); - variants.put("\"etag2\"", new Variant("C","D",variant2)); - variants.put("\"etag3\"", new Variant("E","F",variant3)); - - HttpRequest variantConditionalRequest = new BasicHttpRequest("GET", "http://foo.com/bar", HttpVersion.HTTP_1_1); - variantConditionalRequest.addHeader(new BasicHeader(HeaderConstants.IF_NONE_MATCH, "etag1, etag2, etag3")); - - HttpResponse originResponse = HttpTestUtils.make200Response(); - originResponse.addHeader(HeaderConstants.ETAG, "etag4"); - - HttpResponse response = HttpTestUtils.make200Response(); - - conditionalVariantRequestBuilderReturns(variants, variantConditionalRequest); - - backendCall(variantConditionalRequest, originResponse); - - responseProtocolValidationIsCalled(); - - responsePolicyAllowsCaching(true); - - EasyMock.expect(mockCache.getCacheEntry(host, request)).andReturn(cacheEntry); - EasyMock.expect(mockCache.cacheAndReturnResponse(EasyMock.same(host), EasyMock.same(request), EasyMock.same(originResponse), EasyMock.isA(Date.class), EasyMock.isA(Date.class))).andReturn(response); - - replayMocks(); - HttpResponse resp = impl.negotiateResponseFromVariants(host, request, context, variants); - verifyMocks(); - - Assert.assertEquals(HttpStatus.SC_OK,resp.getStatusLine().getStatusCode()); - - } - @Test public void testReturns200ForIfModifiedSinceFailsIfRequestServedFromOrigin() throws Exception { @@ -1658,15 +1565,15 @@ public class TestCachingHttpClient { resp2.setHeader("Date", DateUtils.formatDate(now)); resp1.setHeader("Last-Modified", DateUtils.formatDate(now)); resp2.setHeader("Cache-Control", "public, max-age=5"); - EasyMock.expect( - mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock - .isA(HttpRequest.class), (HttpContext) EasyMock - .isNull())).andReturn(resp1); + expect( + mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), (HttpContext) + isNull())).andReturn(resp1); - EasyMock.expect( - mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock - .isA(HttpRequest.class), (HttpContext) EasyMock - .isNull())).andReturn(resp2); + expect( + mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), (HttpContext) + isNull())).andReturn(resp2); replayMocks(); impl.execute(host, req1); HttpResponse result = impl.execute(host, req2); @@ -1721,20 +1628,20 @@ public class TestCachingHttpClient { resp3.setHeader("Vary", "Accept-Encoding"); resp3.setHeader("Cache-Control", "public, max-age=3600"); - EasyMock.expect( - mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock - .isA(HttpRequest.class), (HttpContext) EasyMock - .isNull())).andReturn(resp1); + expect( + mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), (HttpContext) + isNull())).andReturn(resp1); - EasyMock.expect( - mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock - .isA(HttpRequest.class), (HttpContext) EasyMock - .isNull())).andReturn(resp2); + expect( + mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), (HttpContext) + isNull())).andReturn(resp2); - EasyMock.expect( - mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock - .isA(HttpRequest.class), (HttpContext) EasyMock - .isNull())).andReturn(resp3); + expect( + mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), (HttpContext) + isNull())).andReturn(resp3); replayMocks(); @@ -1795,20 +1702,20 @@ public class TestCachingHttpClient { resp4.setHeader("Vary", "Accept-Encoding"); resp4.setHeader("Cache-Control", "public, max-age=3600"); - EasyMock.expect( - mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock - .isA(HttpRequest.class), (HttpContext) EasyMock - .isNull())).andReturn(resp1); + expect( + mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), (HttpContext) + isNull())).andReturn(resp1); - EasyMock.expect( - mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock - .isA(HttpRequest.class), (HttpContext) EasyMock - .isNull())).andReturn(resp2); + expect( + mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), (HttpContext) + isNull())).andReturn(resp2); - EasyMock.expect( - mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock - .isA(HttpRequest.class), (HttpContext) EasyMock - .isNull())).andReturn(resp4); + expect( + mockBackend.execute(isA(HttpHost.class), + isA(HttpRequest.class), (HttpContext) + isNull())).andReturn(resp4); replayMocks(); HttpResponse result1 = impl.execute(host, req1); @@ -1836,19 +1743,21 @@ public class TestCachingHttpClient { HttpResponse resp = HttpTestUtils.make200Response(); mockCache.flushInvalidatedCacheEntriesFor(host, request); - EasyMock.expectLastCall().andThrow(new IOException()).anyTimes(); - EasyMock.expect(mockCache.getCacheEntry(EasyMock.same(host), - EasyMock.isA(HttpRequest.class))) + expectLastCall().andThrow(new IOException()).anyTimes(); + mockCache.flushInvalidatedCacheEntriesFor(isA(HttpHost.class), isA(HttpRequest.class), isA(HttpResponse.class)); + expectLastCall().anyTimes(); + expect(mockCache.getCacheEntry(same(host), + isA(HttpRequest.class))) .andThrow(new IOException()).anyTimes(); - EasyMock.expect(mockCache.getVariantCacheEntriesWithEtags(EasyMock.same(host), - EasyMock.isA(HttpRequest.class))) + expect(mockCache.getVariantCacheEntriesWithEtags(same(host), + isA(HttpRequest.class))) .andThrow(new IOException()).anyTimes(); - EasyMock.expect(mockCache.cacheAndReturnResponse(EasyMock.same(host), - EasyMock.isA(HttpRequest.class), EasyMock.isA(HttpResponse.class), - EasyMock.isA(Date.class), EasyMock.isA(Date.class))) + expect(mockCache.cacheAndReturnResponse(same(host), + isA(HttpRequest.class), isA(HttpResponse.class), + isA(Date.class), isA(Date.class))) .andThrow(new IOException()).anyTimes(); - EasyMock.expect(mockBackend.execute(EasyMock.same(host), - EasyMock.isA(HttpRequest.class), (HttpContext)EasyMock.isNull())) + expect(mockBackend.execute(same(host), + isA(HttpRequest.class), (HttpContext)isNull())) .andReturn(resp); replayMocks(); @@ -1911,117 +1820,117 @@ public class TestCachingHttpClient { } private void getCacheEntryReturns(HttpCacheEntry result) throws IOException { - EasyMock.expect(mockCache.getCacheEntry(host, request)).andReturn(result); + expect(mockCache.getCacheEntry(host, request)).andReturn(result); } private void getVariantCacheEntriesReturns(Map result) throws IOException { - EasyMock.expect(mockCache.getVariantCacheEntriesWithEtags(host, request)).andReturn(result); + expect(mockCache.getVariantCacheEntriesWithEtags(host, request)).andReturn(result); } private void cacheInvalidatorWasCalled() throws IOException { mockCache.flushInvalidatedCacheEntriesFor( - EasyMock.anyObject(), - EasyMock.anyObject()); + (HttpHost)anyObject(), + (HttpRequest)anyObject()); } private void callBackendReturnsResponse(HttpResponse response) throws IOException { - EasyMock.expect(impl.callBackend( - EasyMock.anyObject(), - EasyMock.anyObject(), - EasyMock.anyObject())).andReturn(response); + expect(impl.callBackend( + (HttpHost)anyObject(), + (HttpRequest)anyObject(), + (HttpContext)anyObject())).andReturn(response); } private void revalidateCacheEntryReturns(HttpResponse response) throws IOException, ProtocolException { - EasyMock.expect( + expect( impl.revalidateCacheEntry( - EasyMock.anyObject(), - EasyMock.anyObject(), - EasyMock.anyObject(), - EasyMock.anyObject())).andReturn(response); + (HttpHost)anyObject(), + (HttpRequest)anyObject(), + (HttpContext)anyObject(), + (HttpCacheEntry)anyObject())).andReturn(response); } private void cacheEntryValidatable(boolean b) { - EasyMock.expect(mockValidityPolicy.isRevalidatable( - EasyMock.anyObject())).andReturn(b); + expect(mockValidityPolicy.isRevalidatable( + (HttpCacheEntry)anyObject())).andReturn(b); } private void cacheEntryMustRevalidate(boolean b) { - EasyMock.expect(mockValidityPolicy.mustRevalidate(mockCacheEntry)) + expect(mockValidityPolicy.mustRevalidate(mockCacheEntry)) .andReturn(b); } private void cacheEntryProxyRevalidate(boolean b) { - EasyMock.expect(mockValidityPolicy.proxyRevalidate(mockCacheEntry)) + expect(mockValidityPolicy.proxyRevalidate(mockCacheEntry)) .andReturn(b); } private void mayReturnStaleWhileRevalidating(boolean b) { - EasyMock.expect(mockValidityPolicy.mayReturnStaleWhileRevalidating( - EasyMock.anyObject(), EasyMock.anyObject())).andReturn(b); + expect(mockValidityPolicy.mayReturnStaleWhileRevalidating( + (HttpCacheEntry)anyObject(), (Date)anyObject())).andReturn(b); } private void conditionalVariantRequestBuilderReturns(Map variantEntries, HttpRequest validate) throws Exception { - EasyMock.expect(mockConditionalRequestBuilder.buildConditionalRequestFromVariants(request, variantEntries)) + expect(mockConditionalRequestBuilder.buildConditionalRequestFromVariants(request, variantEntries)) .andReturn(validate); } private void conditionalRequestBuilderReturns(HttpRequest validate) throws Exception { - EasyMock.expect(mockConditionalRequestBuilder + expect(mockConditionalRequestBuilder .buildConditionalRequest(request, entry)) .andReturn(validate); } private void getCurrentDateReturns(Date date) { - EasyMock.expect(impl.getCurrentDate()).andReturn(date); + expect(impl.getCurrentDate()).andReturn(date); } private void requestPolicyAllowsCaching(boolean allow) { - EasyMock.expect(mockRequestPolicy.isServableFromCache( - EasyMock.anyObject())).andReturn(allow); + expect(mockRequestPolicy.isServableFromCache( + (HttpRequest)anyObject())).andReturn(allow); } private void backendCall(HttpRequest req, HttpResponse resp) throws Exception { - EasyMock.expect(mockBackend.execute(host, req, context)) + expect(mockBackend.execute(host, req, context)) .andReturn(resp); } private void backendCallWasMade(HttpRequest request, HttpResponse response) throws IOException { - EasyMock.expect(mockBackend.execute( - EasyMock.anyObject(), - EasyMock.same(request), - EasyMock.anyObject())).andReturn(response); + expect(mockBackend.execute( + (HttpHost)anyObject(), + same(request), + (HttpContext)anyObject())).andReturn(response); } private void responsePolicyAllowsCaching(boolean allow) { - EasyMock.expect( + expect( mockResponsePolicy.isResponseCacheable( - EasyMock.anyObject(), - EasyMock.anyObject())).andReturn(allow); + (HttpRequest)anyObject(), + (HttpResponse)anyObject())).andReturn(allow); } private void cacheEntrySuitable(boolean suitable) { - EasyMock.expect( + expect( mockSuitabilityChecker.canCachedResponseBeUsed( - EasyMock.anyObject(), - EasyMock.anyObject(), - EasyMock.anyObject(), - EasyMock.anyObject())).andReturn(suitable); + (HttpHost)anyObject(), + (HttpRequest)anyObject(), + (HttpCacheEntry)anyObject(), + (Date)anyObject())).andReturn(suitable); } private void entryHasStaleness(long staleness) { - EasyMock.expect(mockValidityPolicy.getStalenessSecs( - EasyMock.anyObject(), - EasyMock.anyObject() + expect(mockValidityPolicy.getStalenessSecs( + (HttpCacheEntry)anyObject(), + (Date)anyObject() )).andReturn(staleness); } private void responseIsGeneratedFromCache() { - EasyMock.expect(mockResponseGenerator.generateResponse( - EasyMock.anyObject())).andReturn(mockCachedResponse); + expect(mockResponseGenerator.generateResponse( + (HttpCacheEntry)anyObject())).andReturn(mockCachedResponse); } private void flushCache() throws IOException { @@ -2030,36 +1939,36 @@ public class TestCachingHttpClient { private void handleBackendResponseReturnsResponse(HttpRequest request, HttpResponse response) throws IOException { - EasyMock.expect( + expect( impl.handleBackendResponse( - EasyMock.anyObject(), - EasyMock.same(request), - EasyMock.anyObject(), - EasyMock.anyObject(), - EasyMock.anyObject())).andReturn(response); + (HttpHost)anyObject(), + same(request), + (Date)anyObject(), + (Date)anyObject(), + (HttpResponse)anyObject())).andReturn(response); } private void responseProtocolValidationIsCalled() throws ClientProtocolException { mockResponseProtocolCompliance.ensureProtocolCompliance( - EasyMock.anyObject(), - EasyMock.anyObject()); + (HttpRequest)anyObject(), + (HttpResponse)anyObject()); } private void requestProtocolValidationIsCalled() throws Exception { - EasyMock.expect( + expect( mockRequestProtocolCompliance.makeRequestCompliant( - EasyMock.anyObject())).andReturn(request); + (HttpRequest)anyObject())).andReturn(request); } private void requestCannotBeMadeCompliantThrows(ClientProtocolException exception) throws Exception { - EasyMock.expect( + expect( mockRequestProtocolCompliance.makeRequestCompliant( - EasyMock.anyObject())).andThrow(exception); + (HttpRequest)anyObject())).andThrow(exception); } private void mockImplMethods(String... methods) { mockedImpl = true; - impl = EasyMock.createMockBuilder(CachingHttpClient.class).withConstructor( + impl = createMockBuilder(CachingHttpClient.class).withConstructor( mockBackend, mockValidityPolicy, mockResponsePolicy, diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRecommendations.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRecommendations.java index edb95de7c..35e14fab2 100644 --- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRecommendations.java +++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRecommendations.java @@ -40,13 +40,16 @@ import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.HttpVersion; -import org.apache.http.impl.cookie.DateUtils; +import static org.apache.http.impl.cookie.DateUtils.formatDate; + +import org.apache.http.client.methods.HttpGet; import org.apache.http.message.BasicHttpEntityEnclosingRequest; import org.apache.http.message.BasicHttpRequest; import org.apache.http.message.BasicHttpResponse; import org.apache.http.protocol.HttpContext; import org.easymock.Capture; import org.easymock.EasyMock; +import org.junit.Before; import org.junit.Test; /* @@ -56,6 +59,17 @@ import org.junit.Test; */ public class TestProtocolRecommendations extends AbstractProtocolTest { + private Date now; + private Date tenSecondsAgo; + + @Override + @Before + public void setUp() { + super.setUp(); + now = new Date(); + tenSecondsAgo = new Date(now.getTime() - 10 * 1000L); + } + /* "identity: The default (identity) encoding; the use of no * transformation whatsoever. This content-coding is used only in the * Accept-Encoding header, and SHOULD NOT be used in the @@ -92,7 +106,7 @@ public class TestProtocolRecommendations extends AbstractProtocolTest { HttpResponse resp1 = HttpTestUtils.make200Response(); Date now = new Date(); Date tenSecondsAgo = new Date(now.getTime() - 10 * 1000L); - resp1.setHeader("Date", DateUtils.formatDate(tenSecondsAgo)); + resp1.setHeader("Date", formatDate(tenSecondsAgo)); resp1.setHeader("Cache-Control","public,max-age=5"); resp1.setHeader("Etag","\"etag\""); @@ -231,7 +245,7 @@ public class TestProtocolRecommendations extends AbstractProtocolTest { Date tenSecondsAgo = new Date(now.getTime() - 10 * 1000L); resp1.setHeader("Cache-Control", "public, max-age=5"); resp1.setHeader("ETag","\"etag\""); - resp1.setHeader("Date", DateUtils.formatDate(tenSecondsAgo)); + resp1.setHeader("Date", formatDate(tenSecondsAgo)); backendExpectsAnyRequest().andReturn(resp1); @@ -274,7 +288,7 @@ public class TestProtocolRecommendations extends AbstractProtocolTest { throws Exception { Date now = new Date(); Date tenSecondsAgo = new Date(now.getTime() - 10 * 1000L); - originResponse.setHeader("Date", DateUtils.formatDate(tenSecondsAgo)); + originResponse.setHeader("Date", formatDate(tenSecondsAgo)); originResponse.setHeader("Cache-Control","public, max-age=5"); originResponse.setHeader("ETag","\"etag\""); @@ -292,7 +306,7 @@ public class TestProtocolRecommendations extends AbstractProtocolTest { throws Exception { Date now = new Date(); Date tenSecondsAgo = new Date(now.getTime() - 10 * 1000L); - originResponse.setHeader("Date", DateUtils.formatDate(tenSecondsAgo)); + originResponse.setHeader("Date", formatDate(tenSecondsAgo)); originResponse.setHeader("Cache-Control","public, max-age=5"); originResponse.setHeader("ETag","\"etag\""); originResponse.addHeader("Age","10"); @@ -440,14 +454,14 @@ public class TestProtocolRecommendations extends AbstractProtocolTest { @Test public void testDoesNotModifyDateOnRequests() throws Exception { - request.setHeader("Date", DateUtils.formatDate(new Date())); + request.setHeader("Date", formatDate(new Date())); testDoesNotModifyHeaderOnRequests("Date"); } @Test public void testDoesNotModifyDateOnResponses() throws Exception { - originResponse.setHeader("Date", DateUtils.formatDate(new Date())); + originResponse.setHeader("Date", formatDate(new Date())); testDoesNotModifyHeaderOnResponses("Date"); } @@ -461,7 +475,7 @@ public class TestProtocolRecommendations extends AbstractProtocolTest { @Test public void testDoesNotModifyExpiresOnResponses() throws Exception { - originResponse.setHeader("Expires", DateUtils.formatDate(new Date())); + originResponse.setHeader("Expires", formatDate(new Date())); testDoesNotModifyHeaderOnResponses("Expires"); } @@ -483,7 +497,7 @@ public class TestProtocolRecommendations extends AbstractProtocolTest { @Test public void testDoesNotModifyIfModifiedSinceOnRequests() throws Exception { - request.setHeader("If-Modified-Since", DateUtils.formatDate(new Date())); + request.setHeader("If-Modified-Since", formatDate(new Date())); testDoesNotModifyHeaderOnRequests("If-Modified-Since"); } @@ -506,14 +520,14 @@ public class TestProtocolRecommendations extends AbstractProtocolTest { public void testDoesNotModifyIfUnmodifiedSinceOnRequests() throws Exception { request = new BasicHttpRequest("DELETE", "/", HttpVersion.HTTP_1_1); - request.setHeader("If-Unmodified-Since", DateUtils.formatDate(new Date())); + request.setHeader("If-Unmodified-Since", formatDate(new Date())); testDoesNotModifyHeaderOnRequests("If-Unmodified-Since"); } @Test public void testDoesNotModifyLastModifiedOnResponses() throws Exception { - originResponse.setHeader("Last-Modified", DateUtils.formatDate(new Date())); + originResponse.setHeader("Last-Modified", formatDate(new Date())); testDoesNotModifyHeaderOnResponses("Last-Modified"); } @@ -599,12 +613,12 @@ public class TestProtocolRecommendations extends AbstractProtocolTest { Date now = new Date(); Date tenSecondsAgo = new Date(now.getTime() - 10 * 1000L); Date twentySecondsAgo = new Date(now.getTime() - 20 * 1000L); - final String lmDate = DateUtils.formatDate(twentySecondsAgo); + final String lmDate = formatDate(twentySecondsAgo); HttpRequest req1 = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1); HttpResponse resp1 = HttpTestUtils.make200Response(); - resp1.setHeader("Date", DateUtils.formatDate(tenSecondsAgo)); + resp1.setHeader("Date", formatDate(tenSecondsAgo)); resp1.setHeader("Last-Modified", lmDate); resp1.setHeader("Cache-Control","max-age=5"); @@ -644,13 +658,13 @@ public class TestProtocolRecommendations extends AbstractProtocolTest { Date now = new Date(); Date tenSecondsAgo = new Date(now.getTime() - 10 * 1000L); Date twentySecondsAgo = new Date(now.getTime() - 20 * 1000L); - final String lmDate = DateUtils.formatDate(twentySecondsAgo); + final String lmDate = formatDate(twentySecondsAgo); final String etag = "\"etag\""; HttpRequest req1 = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1); HttpResponse resp1 = HttpTestUtils.make200Response(); - resp1.setHeader("Date", DateUtils.formatDate(tenSecondsAgo)); + resp1.setHeader("Date", formatDate(tenSecondsAgo)); resp1.setHeader("Last-Modified", lmDate); resp1.setHeader("Cache-Control","max-age=5"); resp1.setHeader("ETag", etag); @@ -699,8 +713,8 @@ public class TestProtocolRecommendations extends AbstractProtocolTest { new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1); HttpResponse resp1 = HttpTestUtils.make200Response(); resp1.setHeader("ETag","\"etag\""); - resp1.setHeader("Date", DateUtils.formatDate(now)); - resp1.setHeader("Expires",DateUtils.formatDate(oneSecondAgo)); + resp1.setHeader("Date", formatDate(now)); + resp1.setHeader("Expires",formatDate(oneSecondAgo)); backendExpectsAnyRequest().andReturn(resp1); @@ -712,8 +726,8 @@ public class TestProtocolRecommendations extends AbstractProtocolTest { HttpResponse resp2 = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_NOT_MODIFIED, "Not Modified"); - resp2.setHeader("Date", DateUtils.formatDate(twoSecondsFromNow)); - resp2.setHeader("Expires", DateUtils.formatDate(oneSecondFromNow)); + resp2.setHeader("Date", formatDate(twoSecondsFromNow)); + resp2.setHeader("Expires", formatDate(oneSecondFromNow)); resp2.setHeader("ETag","\"etag\""); expect(mockBackend.execute(isA(HttpHost.class), @@ -752,7 +766,7 @@ public class TestProtocolRecommendations extends AbstractProtocolTest { new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1); HttpResponse resp1 = HttpTestUtils.make200Response(); resp1.setHeader("ETag","\"etag\""); - resp1.setHeader("Date", DateUtils.formatDate(tenSecondsAgo)); + resp1.setHeader("Date", formatDate(tenSecondsAgo)); resp1.setHeader("Cache-Control","max-age=5"); backendExpectsAnyRequest().andReturn(resp1); @@ -761,14 +775,14 @@ public class TestProtocolRecommendations extends AbstractProtocolTest { HttpResponse resp2 = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_NOT_MODIFIED, "Not Modified"); resp2.setHeader("ETag","\"etag\""); - resp2.setHeader("Date", DateUtils.formatDate(elevenSecondsAgo)); + resp2.setHeader("Date", formatDate(elevenSecondsAgo)); backendExpectsAnyRequest().andReturn(resp2); Capture cap = new Capture(); HttpResponse resp3 = HttpTestUtils.make200Response(); resp3.setHeader("ETag","\"etag2\""); - resp3.setHeader("Date", DateUtils.formatDate(now)); + resp3.setHeader("Date", formatDate(now)); resp3.setHeader("Cache-Control","max-age=5"); expect(mockBackend.execute(isA(HttpHost.class), capture(cap), @@ -884,7 +898,7 @@ public class TestProtocolRecommendations extends AbstractProtocolTest { req1.setHeader("User-Agent", "agent1"); HttpResponse resp1 = HttpTestUtils.make200Response(); - resp1.setHeader("Date", DateUtils.formatDate(tenSecondsAgo)); + resp1.setHeader("Date", formatDate(tenSecondsAgo)); resp1.setHeader("Vary", "User-Agent"); resp1.setHeader("Cache-Control", "max-age=3600"); resp1.setHeader("ETag", "\"etag1\""); @@ -896,7 +910,7 @@ public class TestProtocolRecommendations extends AbstractProtocolTest { req2.setHeader("User-Agent", "agent2"); HttpResponse resp2 = HttpTestUtils.make200Response(); - resp2.setHeader("Date", DateUtils.formatDate(tenSecondsAgo)); + resp2.setHeader("Date", formatDate(tenSecondsAgo)); resp2.setHeader("Vary", "User-Agent"); resp2.setHeader("Cache-Control", "max-age=3600"); resp2.setHeader("ETag", "\"etag2\""); @@ -907,7 +921,7 @@ public class TestProtocolRecommendations extends AbstractProtocolTest { req3.setHeader("User-Agent", "agent3"); HttpResponse resp3 = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_NOT_MODIFIED, "Not Modified"); - resp3.setHeader("Date", DateUtils.formatDate(now)); + resp3.setHeader("Date", formatDate(now)); resp3.setHeader("ETag", "\"etag1\""); backendExpectsAnyRequest().andReturn(resp3); @@ -924,8 +938,8 @@ public class TestProtocolRecommendations extends AbstractProtocolTest { assertEquals(HttpStatus.SC_OK, result1.getStatusLine().getStatusCode()); assertEquals("\"etag1\"", result1.getFirstHeader("ETag").getValue()); - assertEquals(DateUtils.formatDate(now), result1.getFirstHeader("Date").getValue()); - assertEquals(DateUtils.formatDate(now), result2.getFirstHeader("Date").getValue()); + assertEquals(formatDate(now), result1.getFirstHeader("Date").getValue()); + assertEquals(formatDate(now), result2.getFirstHeader("Date").getValue()); } @Test @@ -939,7 +953,7 @@ public class TestProtocolRecommendations extends AbstractProtocolTest { req1.setHeader("User-Agent", "agent1"); HttpResponse resp1 = HttpTestUtils.make200Response(); - resp1.setHeader("Date", DateUtils.formatDate(tenSecondsAgo)); + resp1.setHeader("Date", formatDate(tenSecondsAgo)); resp1.setHeader("Vary", "User-Agent"); resp1.setHeader("Cache-Control", "max-age=3600"); resp1.setHeader("ETag", "\"etag1\""); @@ -950,7 +964,7 @@ public class TestProtocolRecommendations extends AbstractProtocolTest { req2.setHeader("User-Agent", "agent2"); HttpResponse resp2 = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_NOT_MODIFIED, "Not Modified"); - resp2.setHeader("Date", DateUtils.formatDate(now)); + resp2.setHeader("Date", formatDate(now)); resp2.setHeader("ETag", "\"etag1\""); backendExpectsAnyRequest().andReturn(resp2); @@ -995,7 +1009,7 @@ public class TestProtocolRecommendations extends AbstractProtocolTest { resp2.setHeader("Vary","User-Agent"); resp2.setHeader("ETag", "\"etag2\""); resp2.setHeader("Cache-Control","max-age=3600"); - resp2.setHeader("Date", DateUtils.formatDate(new Date())); + resp2.setHeader("Date", formatDate(new Date())); backendExpectsAnyRequest().andReturn(resp2); @@ -1024,4 +1038,44 @@ public class TestProtocolRecommendations extends AbstractProtocolTest { } } } + + /* "If a cache receives a successful response whose Content-Location + * field matches that of an existing cache entry for the same Request- + * URI, whose entity-tag differs from that of the existing entry, and + * whose Date is more recent than that of the existing entry, the + * existing entry SHOULD NOT be returned in response to future requests + * and SHOULD be deleted from the cache. + * + * http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.6 + */ + @Test + public void cachedEntryShouldNotBeUsedIfMoreRecentMentionInContentLocation() + throws Exception { + HttpRequest req1 = new HttpGet("http://foo.example.com/"); + HttpResponse resp1 = HttpTestUtils.make200Response(); + resp1.setHeader("Cache-Control","max-age=3600"); + resp1.setHeader("ETag", "\"old-etag\""); + resp1.setHeader("Date", formatDate(tenSecondsAgo)); + + backendExpectsAnyRequest().andReturn(resp1); + + HttpRequest req2 = new HttpGet("http://foo.example.com/bar"); + HttpResponse resp2 = HttpTestUtils.make200Response(); + resp2.setHeader("ETag", "\"new-etag\""); + resp2.setHeader("Date", formatDate(now)); + resp2.setHeader("Content-Location", "http://foo.example.com/"); + + backendExpectsAnyRequest().andReturn(resp2); + + HttpRequest req3 = new HttpGet("http://foo.example.com"); + HttpResponse resp3 = HttpTestUtils.make200Response(); + + backendExpectsAnyRequest().andReturn(resp3); + + replayMocks(); + impl.execute(host, req1); + impl.execute(host, req2); + impl.execute(host, req3); + verifyMocks(); + } } diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRequirements.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRequirements.java index 125deffe3..24b5f38d8 100644 --- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRequirements.java +++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRequirements.java @@ -2584,6 +2584,8 @@ public class TestProtocolRequirements extends AbstractProtocolTest { Capture cap = new Capture(); mockCache.flushInvalidatedCacheEntriesFor(host, request); + mockCache.flushInvalidatedCacheEntriesFor(EasyMock.isA(HttpHost.class), + EasyMock.isA(HttpRequest.class), EasyMock.isA(HttpResponse.class)); EasyMock.expect(mockCache.getCacheEntry(host, request)).andReturn(entry); EasyMock.expect( mockBackend.execute(EasyMock.isA(HttpHost.class), EasyMock.capture(cap),