blob: 359188273115fe1db50ac05753a197f038d99733 [file] [log] [blame]
/*
* ====================================================================
* 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.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import java.net.URI;
import java.time.Instant;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.hc.client5.http.HeadersMatcher;
import org.apache.hc.client5.http.cache.HttpCacheEntry;
import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.utils.DateUtils;
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.message.BasicHeader;
import org.apache.hc.core5.http.message.BasicHttpRequest;
import org.apache.hc.core5.http.message.BasicHttpResponse;
import org.apache.hc.core5.net.URIBuilder;
import org.apache.hc.core5.util.ByteArrayBuffer;
import org.hamcrest.MatcherAssert;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
public class TestBasicHttpCache {
private HttpHost host;
private Instant now;
private Instant tenSecondsAgo;
private SimpleHttpCacheStorage backing;
private BasicHttpCache impl;
@BeforeEach
public void setUp() throws Exception {
host = new HttpHost("foo.example.com");
now = Instant.now();
tenSecondsAgo = now.minusSeconds(10);
backing = Mockito.spy(new SimpleHttpCacheStorage());
impl = new BasicHttpCache(new HeapResourceFactory(), backing);
}
@Test
public void testGetCacheEntryReturnsNullOnCacheMiss() throws Exception {
final HttpHost host = new HttpHost("foo.example.com");
final HttpRequest request = new HttpGet("http://foo.example.com/bar");
final CacheMatch result = impl.match(host, request);
assertNull(result);
}
@Test
public void testGetCacheEntryFetchesFromCacheOnCacheHitIfNoVariants() throws Exception {
final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
assertFalse(entry.hasVariants());
final HttpHost host = new HttpHost("foo.example.com");
final HttpRequest request = new HttpGet("http://foo.example.com/bar");
final String key = CacheKeyGenerator.INSTANCE.generateKey(host, request);
backing.map.put(key,entry);
final CacheMatch result = impl.match(host, request);
assertNotNull(result);
assertNotNull(result.hit);
assertSame(entry, result.hit.entry);
}
@Test
public void testGetCacheEntryReturnsNullIfNoVariantInCache() throws Exception {
final HttpRequest origRequest = new HttpGet("http://foo.example.com/bar");
origRequest.setHeader("Accept-Encoding","gzip");
final ByteArrayBuffer buf = HttpTestUtils.makeRandomBuffer(128);
final HttpResponse origResponse = new BasicHttpResponse(HttpStatus.SC_OK, "OK");
origResponse.setHeader("Date", DateUtils.formatStandardDate(now));
origResponse.setHeader("Cache-Control", "max-age=3600, public");
origResponse.setHeader("ETag", "\"etag\"");
origResponse.setHeader("Vary", "Accept-Encoding");
origResponse.setHeader("Content-Encoding","gzip");
impl.store(host, origRequest, origResponse, buf, now, now);
final HttpRequest request = new HttpGet("http://foo.example.com/bar");
final CacheMatch result = impl.match(host, request);
assertNotNull(result);
assertNull(result.hit);
}
@Test
public void testGetCacheEntryReturnsVariantIfPresentInCache() throws Exception {
final HttpRequest origRequest = new HttpGet("http://foo.example.com/bar");
origRequest.setHeader("Accept-Encoding","gzip");
final ByteArrayBuffer buf = HttpTestUtils.makeRandomBuffer(128);
final HttpResponse origResponse = new BasicHttpResponse(HttpStatus.SC_OK, "OK");
origResponse.setHeader("Date", DateUtils.formatStandardDate(now));
origResponse.setHeader("Cache-Control", "max-age=3600, public");
origResponse.setHeader("ETag", "\"etag\"");
origResponse.setHeader("Vary", "Accept-Encoding");
origResponse.setHeader("Content-Encoding","gzip");
impl.store(host, origRequest, origResponse, buf, now, now);
final HttpRequest request = new HttpGet("http://foo.example.com/bar");
request.setHeader("Accept-Encoding","gzip");
final CacheMatch result = impl.match(host, request);
assertNotNull(result);
assertNotNull(result.hit);
}
@Test
public void testGetCacheEntryReturnsVariantWithMostRecentDateHeader() throws Exception {
final HttpRequest origRequest = new HttpGet("http://foo.example.com/bar");
origRequest.setHeader("Accept-Encoding", "gzip");
final ByteArrayBuffer buf = HttpTestUtils.makeRandomBuffer(128);
// Create two response variants with different Date headers
final HttpResponse origResponse1 = new BasicHttpResponse(HttpStatus.SC_OK, "OK");
origResponse1.setHeader(HttpHeaders.DATE, DateUtils.formatStandardDate(now.minusSeconds(3600)));
origResponse1.setHeader(HttpHeaders.CACHE_CONTROL, "max-age=3600, public");
origResponse1.setHeader(HttpHeaders.ETAG, "\"etag1\"");
origResponse1.setHeader(HttpHeaders.VARY, "Accept-Encoding");
final HttpResponse origResponse2 = new BasicHttpResponse(HttpStatus.SC_OK, "OK");
origResponse2.setHeader(HttpHeaders.DATE, DateUtils.formatStandardDate(now));
origResponse2.setHeader(HttpHeaders.CACHE_CONTROL, "max-age=3600, public");
origResponse2.setHeader(HttpHeaders.ETAG, "\"etag2\"");
origResponse2.setHeader(HttpHeaders.VARY, "Accept-Encoding");
// Store the two variants in cache
impl.store(host, origRequest, origResponse1, buf, now, now);
impl.store(host, origRequest, origResponse2, buf, now, now);
final HttpRequest request = new HttpGet("http://foo.example.com/bar");
request.setHeader("Accept-Encoding", "gzip");
final CacheMatch result = impl.match(host, request);
assertNotNull(result);
assertNotNull(result.hit);
final HttpCacheEntry entry = result.hit.entry;
assertNotNull(entry);
// Retrieve the ETag header value from the original response and assert that
// the returned cache entry has the same ETag value
final String expectedEtag = origResponse2.getFirstHeader(HttpHeaders.ETAG).getValue();
final String actualEtag = entry.getFirstHeader(HttpHeaders.ETAG).getValue();
assertEquals(expectedEtag, actualEtag);
}
@Test
public void testGetVariantsRootNoVariants() throws Exception {
final HttpCacheEntry root = HttpTestUtils.makeCacheEntry();
final List<CacheHit> variants = impl.getVariants(new CacheHit("root-key", root));
assertNotNull(variants);
assertEquals(0, variants.size());
}
@Test
public void testGetVariantsRootNonExistentVariants() throws Exception {
final Set<String> varinats = new HashSet<>();
varinats.add("variant1");
varinats.add("variant2");
final HttpCacheEntry root = HttpTestUtils.makeCacheEntry(varinats);
final List<CacheHit> variants = impl.getVariants(new CacheHit("root-key", root));
assertNotNull(variants);
assertEquals(0, variants.size());
}
@Test
public void testGetVariantCacheEntriesReturnsAllVariants() throws Exception {
final HttpHost host = new HttpHost("foo.example.com");
final URI uri = new URI("http://foo.example.com/bar");
final HttpRequest req1 = new HttpGet(uri);
req1.setHeader("Accept-Encoding", "gzip");
final String rootKey = CacheKeyGenerator.INSTANCE.generateKey(uri);
final HttpResponse resp1 = HttpTestUtils.make200Response();
resp1.setHeader("Date", DateUtils.formatStandardDate(now));
resp1.setHeader("Cache-Control", "max-age=3600, public");
resp1.setHeader("ETag", "\"etag1\"");
resp1.setHeader("Vary", "Accept-Encoding");
resp1.setHeader("Content-Encoding","gzip");
final HttpRequest req2 = new HttpGet(uri);
req2.setHeader("Accept-Encoding", "identity");
final HttpResponse resp2 = HttpTestUtils.make200Response();
resp2.setHeader("Date", DateUtils.formatStandardDate(now));
resp2.setHeader("Cache-Control", "max-age=3600, public");
resp2.setHeader("ETag", "\"etag2\"");
resp2.setHeader("Vary", "Accept-Encoding");
resp2.setHeader("Content-Encoding","gzip");
final CacheHit hit1 = impl.store(host, req1, resp1, null, now, now);
final CacheHit hit2 = impl.store(host, req2, resp2, null, now, now);
final Set<String> variants = new HashSet<>();
variants.add("{accept-encoding=gzip}");
variants.add("{accept-encoding=identity}");
final Map<String, HttpCacheEntry> variantMap = impl.getVariants(new CacheHit(hit1.rootKey,
HttpTestUtils.makeCacheEntry(variants))).stream()
.collect(Collectors.toMap(CacheHit::getEntryKey, e -> e.entry));
assertNotNull(variantMap);
assertEquals(2, variantMap.size());
MatcherAssert.assertThat(variantMap.get("{accept-encoding=gzip}" + rootKey),
HttpCacheEntryMatcher.equivalent(hit1.entry));
MatcherAssert.assertThat(variantMap.get("{accept-encoding=identity}" + rootKey),
HttpCacheEntryMatcher.equivalent(hit2.entry));
}
@Test
public void testUpdateCacheEntry() throws Exception {
final HttpHost host = new HttpHost("foo.example.com");
final URI uri = new URI("http://foo.example.com/bar");
final HttpRequest req1 = new HttpGet(uri);
final HttpResponse resp1 = HttpTestUtils.make200Response();
resp1.setHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo));
resp1.setHeader("Cache-Control", "max-age=3600, public");
resp1.setHeader("ETag", "\"etag1\"");
resp1.setHeader("Content-Encoding","gzip");
final HttpRequest revalidate = new HttpGet(uri);
revalidate.setHeader("If-None-Match","\"etag1\"");
final HttpResponse resp2 = HttpTestUtils.make304Response();
resp2.setHeader("Date", DateUtils.formatStandardDate(now));
resp2.setHeader("Cache-Control", "max-age=3600, public");
final CacheHit hit1 = impl.store(host, req1, resp1, null, now, now);
Assertions.assertNotNull(hit1);
Assertions.assertEquals(1, backing.map.size());
Assertions.assertSame(hit1.entry, backing.map.get(hit1.getEntryKey()));
final CacheHit updated = impl.update(hit1, host, req1, resp2, now, now);
Assertions.assertNotNull(updated);
Assertions.assertEquals(1, backing.map.size());
Assertions.assertSame(updated.entry, backing.map.get(hit1.getEntryKey()));
MatcherAssert.assertThat(
updated.entry.getHeaders(),
HeadersMatcher.same(
new BasicHeader("Server", "MockOrigin/1.0"),
new BasicHeader("ETag", "\"etag1\""),
new BasicHeader("Content-Encoding","gzip"),
new BasicHeader("Date", DateUtils.formatStandardDate(now)),
new BasicHeader("Cache-Control", "max-age=3600, public")
));
}
@Test
public void testUpdateVariantCacheEntry() throws Exception {
final HttpHost host = new HttpHost("foo.example.com");
final URI uri = new URI("http://foo.example.com/bar");
final HttpRequest req1 = new HttpGet(uri);
req1.setHeader("User-Agent", "agent1");
final HttpResponse resp1 = HttpTestUtils.make200Response();
resp1.setHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo));
resp1.setHeader("Cache-Control", "max-age=3600, public");
resp1.setHeader("ETag", "\"etag1\"");
resp1.setHeader("Content-Encoding","gzip");
resp1.setHeader("Vary", "User-Agent");
final HttpRequest revalidate = new HttpGet(uri);
revalidate.setHeader("If-None-Match","\"etag1\"");
final HttpResponse resp2 = HttpTestUtils.make304Response();
resp2.setHeader("Date", DateUtils.formatStandardDate(now));
resp2.setHeader("Cache-Control", "max-age=3600, public");
final CacheHit hit1 = impl.store(host, req1, resp1, null, now, now);
Assertions.assertNotNull(hit1);
Assertions.assertEquals(2, backing.map.size());
Assertions.assertSame(hit1.entry, backing.map.get(hit1.getEntryKey()));
final CacheHit updated = impl.update(hit1, host, req1, resp2, now, now);
Assertions.assertNotNull(updated);
Assertions.assertEquals(2, backing.map.size());
Assertions.assertSame(updated.entry, backing.map.get(hit1.getEntryKey()));
MatcherAssert.assertThat(
updated.entry.getHeaders(),
HeadersMatcher.same(
new BasicHeader("Server", "MockOrigin/1.0"),
new BasicHeader("ETag", "\"etag1\""),
new BasicHeader("Content-Encoding","gzip"),
new BasicHeader("Vary","User-Agent"),
new BasicHeader("Date", DateUtils.formatStandardDate(now)),
new BasicHeader("Cache-Control", "max-age=3600, public")
));
}
@Test
public void testUpdateCacheEntryTurnsVariant() throws Exception {
final HttpHost host = new HttpHost("foo.example.com");
final URI uri = new URI("http://foo.example.com/bar");
final HttpRequest req1 = new HttpGet(uri);
req1.setHeader("User-Agent", "agent1");
final HttpResponse resp1 = HttpTestUtils.make200Response();
resp1.setHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo));
resp1.setHeader("Cache-Control", "max-age=3600, public");
resp1.setHeader("ETag", "\"etag1\"");
resp1.setHeader("Content-Encoding","gzip");
final HttpRequest revalidate = new HttpGet(uri);
revalidate.setHeader("If-None-Match","\"etag1\"");
final HttpResponse resp2 = HttpTestUtils.make304Response();
resp2.setHeader("Date", DateUtils.formatStandardDate(now));
resp2.setHeader("Cache-Control", "max-age=3600, public");
resp2.setHeader("Vary", "User-Agent");
final CacheHit hit1 = impl.store(host, req1, resp1, null, now, now);
Assertions.assertNotNull(hit1);
Assertions.assertEquals(1, backing.map.size());
Assertions.assertSame(hit1.entry, backing.map.get(hit1.getEntryKey()));
final CacheHit updated = impl.update(hit1, host, req1, resp2, now, now);
Assertions.assertNotNull(updated);
Assertions.assertEquals(2, backing.map.size());
MatcherAssert.assertThat(
updated.entry.getHeaders(),
HeadersMatcher.same(
new BasicHeader("Server", "MockOrigin/1.0"),
new BasicHeader("ETag", "\"etag1\""),
new BasicHeader("Content-Encoding","gzip"),
new BasicHeader("Date", DateUtils.formatStandardDate(now)),
new BasicHeader("Cache-Control", "max-age=3600, public"),
new BasicHeader("Vary","User-Agent")));
}
@Test
public void testStoreFromNegotiatedVariant() throws Exception {
final HttpHost host = new HttpHost("foo.example.com");
final URI uri = new URI("http://foo.example.com/bar");
final HttpRequest req1 = new HttpGet(uri);
req1.setHeader("User-Agent", "agent1");
final HttpResponse resp1 = HttpTestUtils.make200Response();
resp1.setHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo));
resp1.setHeader("Cache-Control", "max-age=3600, public");
resp1.setHeader("ETag", "\"etag1\"");
resp1.setHeader("Content-Encoding","gzip");
resp1.setHeader("Vary", "User-Agent");
final CacheHit hit1 = impl.store(host, req1, resp1, null, now, now);
Assertions.assertNotNull(hit1);
Assertions.assertEquals(2, backing.map.size());
Assertions.assertSame(hit1.entry, backing.map.get(hit1.getEntryKey()));
final HttpRequest req2 = new HttpGet(uri);
req2.setHeader("User-Agent", "agent2");
final HttpResponse resp2 = HttpTestUtils.make304Response();
resp2.setHeader("Date", DateUtils.formatStandardDate(now));
resp2.setHeader("Cache-Control", "max-age=3600, public");
final CacheHit hit2 = impl.storeFromNegotiated(hit1, host, req2, resp2, now, now);
Assertions.assertNotNull(hit2);
Assertions.assertEquals(3, backing.map.size());
MatcherAssert.assertThat(
hit2.entry.getHeaders(),
HeadersMatcher.same(
new BasicHeader("Server", "MockOrigin/1.0"),
new BasicHeader("ETag", "\"etag1\""),
new BasicHeader("Content-Encoding","gzip"),
new BasicHeader("Vary","User-Agent"),
new BasicHeader("Date", DateUtils.formatStandardDate(now)),
new BasicHeader("Cache-Control", "max-age=3600, public")));
}
@Test
public void testInvalidatesUnsafeRequests() throws Exception {
final HttpRequest request = new BasicHttpRequest("POST","/path");
final String key = CacheKeyGenerator.INSTANCE.generateKey(host, request);
final HttpResponse response = HttpTestUtils.make200Response();
backing.putEntry(key, HttpTestUtils.makeCacheEntry());
impl.evictInvalidatedEntries(host, request, response);
verify(backing).getEntry(key);
verify(backing).removeEntry(key);
Assertions.assertNull(backing.getEntry(key));
}
@Test
public void testDoesNotInvalidateSafeRequests() throws Exception {
final HttpRequest request1 = new BasicHttpRequest("GET","/");
final HttpResponse response1 = HttpTestUtils.make200Response();
impl.evictInvalidatedEntries(host, request1, response1);
verifyNoMoreInteractions(backing);
final HttpRequest request2 = new BasicHttpRequest("HEAD","/");
final HttpResponse response2 = HttpTestUtils.make200Response();
impl.evictInvalidatedEntries(host, request2, response2);
verifyNoMoreInteractions(backing);
}
@Test
public void testInvalidatesUnsafeRequestsWithVariants() throws Exception {
final HttpRequest request = new BasicHttpRequest("POST","/path");
final String rootKey = CacheKeyGenerator.INSTANCE.generateKey(host, request);
final Set<String> variants = new HashSet<>();
variants.add("{var1}");
variants.add("{var2}");
final String variantKey1 = "{var1}" + rootKey;
final String variantKey2 = "{var2}" + rootKey;
final HttpResponse response = HttpTestUtils.make200Response();
backing.putEntry(rootKey, HttpTestUtils.makeCacheEntry(variants));
backing.putEntry(variantKey1, HttpTestUtils.makeCacheEntry());
backing.putEntry(variantKey2, HttpTestUtils.makeCacheEntry());
impl.evictInvalidatedEntries(host, request, response);
verify(backing).getEntry(rootKey);
verify(backing).removeEntry(rootKey);
verify(backing).removeEntry(variantKey1);
verify(backing).removeEntry(variantKey2);
Assertions.assertNull(backing.getEntry(rootKey));
Assertions.assertNull(backing.getEntry(variantKey1));
Assertions.assertNull(backing.getEntry(variantKey2));
}
@Test
public void testInvalidateUriSpecifiedByContentLocationAndFresher() throws Exception {
final HttpRequest request = new BasicHttpRequest("PUT", "/foo");
final String rootKey = CacheKeyGenerator.INSTANCE.generateKey(host, request);
final URI contentUri = new URIBuilder()
.setHttpHost(host)
.setPath("/bar")
.build();
final String contentKey = CacheKeyGenerator.INSTANCE.generateKey(contentUri);
final HttpResponse response = HttpTestUtils.make200Response();
response.setHeader("ETag","\"new-etag\"");
response.setHeader("Date", DateUtils.formatStandardDate(now));
response.setHeader("Content-Location", contentUri.toASCIIString());
backing.putEntry(rootKey, HttpTestUtils.makeCacheEntry());
backing.putEntry(contentKey, HttpTestUtils.makeCacheEntry(
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
new BasicHeader("ETag", "\"old-etag\"")
));
impl.evictInvalidatedEntries(host, request, response);
verify(backing).getEntry(rootKey);
verify(backing).removeEntry(rootKey);
verify(backing).getEntry(contentKey);
verify(backing).removeEntry(contentKey);
}
@Test
public void testInvalidateUriSpecifiedByLocationAndFresher() throws Exception {
final HttpRequest request = new BasicHttpRequest("PUT", "/foo");
final String rootKey = CacheKeyGenerator.INSTANCE.generateKey(host, request);
final URI contentUri = new URIBuilder()
.setHttpHost(host)
.setPath("/bar")
.build();
final String contentKey = CacheKeyGenerator.INSTANCE.generateKey(contentUri);
final HttpResponse response = HttpTestUtils.make200Response();
response.setHeader("ETag","\"new-etag\"");
response.setHeader("Date", DateUtils.formatStandardDate(now));
response.setHeader("Location", contentUri.toASCIIString());
backing.putEntry(rootKey, HttpTestUtils.makeCacheEntry());
backing.putEntry(contentKey, HttpTestUtils.makeCacheEntry(
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
new BasicHeader("ETag", "\"old-etag\"")
));
impl.evictInvalidatedEntries(host, request, response);
verify(backing).getEntry(rootKey);
verify(backing).removeEntry(rootKey);
verify(backing).getEntry(contentKey);
verify(backing).removeEntry(contentKey);
}
@Test
public void testDoesNotInvalidateForUnsuccessfulResponse() throws Exception {
final HttpRequest request = new BasicHttpRequest("PUT", "/foo");
final URI contentUri = new URIBuilder()
.setHttpHost(host)
.setPath("/bar")
.build();
final HttpResponse response = HttpTestUtils.make500Response();
response.setHeader("ETag","\"new-etag\"");
response.setHeader("Date", DateUtils.formatStandardDate(now));
response.setHeader("Content-Location", contentUri.toASCIIString());
impl.evictInvalidatedEntries(host, request, response);
verifyNoMoreInteractions(backing);
}
@Test
public void testInvalidateUriSpecifiedByContentLocationNonCanonical() throws Exception {
final HttpRequest request = new BasicHttpRequest("PUT", "/foo");
final String rootKey = CacheKeyGenerator.INSTANCE.generateKey(host, request);
final URI contentUri = new URIBuilder()
.setHttpHost(host)
.setPath("/bar")
.build();
final String contentKey = CacheKeyGenerator.INSTANCE.generateKey(contentUri);
final HttpResponse response = HttpTestUtils.make200Response();
response.setHeader("ETag","\"new-etag\"");
response.setHeader("Date", DateUtils.formatStandardDate(now));
response.setHeader("Content-Location", contentUri.toASCIIString());
backing.putEntry(rootKey, HttpTestUtils.makeCacheEntry());
backing.putEntry(contentKey, HttpTestUtils.makeCacheEntry(
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
new BasicHeader("ETag", "\"old-etag\"")));
impl.evictInvalidatedEntries(host, request, response);
verify(backing).getEntry(rootKey);
verify(backing).removeEntry(rootKey);
verify(backing).getEntry(contentKey);
verify(backing).removeEntry(contentKey);
Assertions.assertNull(backing.getEntry(rootKey));
Assertions.assertNull(backing.getEntry(contentKey));
}
@Test
public void testInvalidateUriSpecifiedByContentLocationRelative() throws Exception {
final HttpRequest request = new BasicHttpRequest("PUT", "/foo");
final String rootKey = CacheKeyGenerator.INSTANCE.generateKey(host, request);
final URI contentUri = new URIBuilder()
.setHttpHost(host)
.setPath("/bar")
.build();
final String contentKey = CacheKeyGenerator.INSTANCE.generateKey(contentUri);
final HttpResponse response = HttpTestUtils.make200Response();
response.setHeader("ETag","\"new-etag\"");
response.setHeader("Date", DateUtils.formatStandardDate(now));
response.setHeader("Content-Location", "/bar");
backing.putEntry(rootKey, HttpTestUtils.makeCacheEntry());
backing.putEntry(contentKey, HttpTestUtils.makeCacheEntry(
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
new BasicHeader("ETag", "\"old-etag\"")));
impl.evictInvalidatedEntries(host, request, response);
verify(backing).getEntry(rootKey);
verify(backing).removeEntry(rootKey);
verify(backing).getEntry(contentKey);
verify(backing).removeEntry(contentKey);
Assertions.assertNull(backing.getEntry(rootKey));
Assertions.assertNull(backing.getEntry(contentKey));
}
@Test
public void testDoesNotInvalidateUriSpecifiedByContentLocationOtherOrigin() throws Exception {
final HttpRequest request = new BasicHttpRequest("PUT", "/");
final URI contentUri = new URIBuilder()
.setHost("bar.example.com")
.setPath("/")
.build();
final String contentKey = CacheKeyGenerator.INSTANCE.generateKey(contentUri);
final HttpResponse response = HttpTestUtils.make200Response();
response.setHeader("ETag","\"new-etag\"");
response.setHeader("Date", DateUtils.formatStandardDate(now));
response.setHeader("Content-Location", contentUri.toASCIIString());
backing.putEntry(contentKey, HttpTestUtils.makeCacheEntry());
impl.evictInvalidatedEntries(host, request, response);
verify(backing, Mockito.never()).getEntry(contentKey);
verify(backing, Mockito.never()).removeEntry(contentKey);
}
@Test
public void testDoesNotInvalidateUriSpecifiedByContentLocationIfEtagsMatch() throws Exception {
final HttpRequest request = new BasicHttpRequest("PUT", "/foo");
final URI contentUri = new URIBuilder()
.setHttpHost(host)
.setPath("/bar")
.build();
final String contentKey = CacheKeyGenerator.INSTANCE.generateKey(contentUri);
final HttpResponse response = HttpTestUtils.make200Response();
response.setHeader("ETag","\"same-etag\"");
response.setHeader("Date", DateUtils.formatStandardDate(now));
response.setHeader("Content-Location", contentUri.toASCIIString());
backing.putEntry(contentKey, HttpTestUtils.makeCacheEntry(
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
new BasicHeader("ETag", "\"same-etag\"")));
impl.evictInvalidatedEntries(host, request, response);
verify(backing).getEntry(contentKey);
verify(backing, Mockito.never()).removeEntry(contentKey);
}
@Test
public void testDoesNotInvalidateUriSpecifiedByContentLocationIfOlder() throws Exception {
final HttpRequest request = new BasicHttpRequest("PUT", "/foo");
final URI contentUri = new URIBuilder()
.setHttpHost(host)
.setPath("/bar")
.build();
final String contentKey = CacheKeyGenerator.INSTANCE.generateKey(contentUri);
final HttpResponse response = HttpTestUtils.make200Response();
response.setHeader("ETag","\"new-etag\"");
response.setHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo));
response.setHeader("Content-Location", contentUri.toASCIIString());
backing.putEntry(contentKey, HttpTestUtils.makeCacheEntry(
new BasicHeader("Date", DateUtils.formatStandardDate(now)),
new BasicHeader("ETag", "\"old-etag\"")));
impl.evictInvalidatedEntries(host, request, response);
verify(backing).getEntry(contentKey);
verify(backing, Mockito.never()).removeEntry(contentKey);
}
@Test
public void testDoesNotInvalidateUriSpecifiedByContentLocationIfResponseHasNoEtag() throws Exception {
final HttpRequest request = new BasicHttpRequest("PUT", "/foo");
final URI contentUri = new URIBuilder()
.setHttpHost(host)
.setPath("/bar")
.build();
final String contentKey = CacheKeyGenerator.INSTANCE.generateKey(contentUri);
final HttpResponse response = HttpTestUtils.make200Response();
response.removeHeaders("ETag");
response.setHeader("Date", DateUtils.formatStandardDate(now));
response.setHeader("Content-Location", contentUri.toASCIIString());
backing.putEntry(contentKey, HttpTestUtils.makeCacheEntry(
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
new BasicHeader("ETag", "\"old-etag\"")));
impl.evictInvalidatedEntries(host, request, response);
verify(backing).getEntry(contentKey);
verify(backing, Mockito.never()).removeEntry(contentKey);
}
@Test
public void testDoesNotInvalidateUriSpecifiedByContentLocationIfEntryHasNoEtag() throws Exception {
final HttpRequest request = new BasicHttpRequest("PUT", "/foo");
final URI contentUri = new URIBuilder()
.setHttpHost(host)
.setPath("/bar")
.build();
final String contentKey = CacheKeyGenerator.INSTANCE.generateKey(contentUri);
final HttpResponse response = HttpTestUtils.make200Response();
response.setHeader("ETag", "\"some-etag\"");
response.setHeader("Date", DateUtils.formatStandardDate(now));
response.setHeader("Content-Location", contentUri.toASCIIString());
backing.putEntry(contentKey, HttpTestUtils.makeCacheEntry(
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo))));
impl.evictInvalidatedEntries(host, request, response);
verify(backing).getEntry(contentKey);
verify(backing, Mockito.never()).removeEntry(contentKey);
}
@Test
public void testInvalidatesUriSpecifiedByContentLocationIfResponseHasNoDate() throws Exception {
final HttpRequest request = new BasicHttpRequest("PUT", "/foo");
final URI contentUri = new URIBuilder()
.setHttpHost(host)
.setPath("/bar")
.build();
final String contentKey = CacheKeyGenerator.INSTANCE.generateKey(contentUri);
final HttpResponse response = HttpTestUtils.make200Response();
response.setHeader("ETag", "\"new-etag\"");
response.removeHeaders("Date");
response.setHeader("Content-Location", contentUri.toASCIIString());
backing.putEntry(contentKey, HttpTestUtils.makeCacheEntry(
new BasicHeader("ETag", "\"old-etag\""),
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo))));
impl.evictInvalidatedEntries(host, request, response);
verify(backing).getEntry(contentKey);
verify(backing).removeEntry(contentKey);
}
@Test
public void testInvalidatesUriSpecifiedByContentLocationIfEntryHasNoDate() throws Exception {
final HttpRequest request = new BasicHttpRequest("PUT", "/foo");
final URI contentUri = new URIBuilder()
.setHttpHost(host)
.setPath("/bar")
.build();
final String contentKey = CacheKeyGenerator.INSTANCE.generateKey(contentUri);
final HttpResponse response = HttpTestUtils.make200Response();
response.setHeader("ETag","\"new-etag\"");
response.setHeader("Date", DateUtils.formatStandardDate(now));
response.setHeader("Content-Location", contentUri.toASCIIString());
backing.putEntry(contentKey, HttpTestUtils.makeCacheEntry(
new BasicHeader("ETag", "\"old-etag\"")));
impl.evictInvalidatedEntries(host, request, response);
verify(backing).getEntry(contentKey);
verify(backing).removeEntry(contentKey);
}
@Test
public void testInvalidatesUriSpecifiedByContentLocationIfResponseHasMalformedDate() throws Exception {
final HttpRequest request = new BasicHttpRequest("PUT", "/foo");
final URI contentUri = new URIBuilder()
.setHttpHost(host)
.setPath("/bar")
.build();
final String contentKey = CacheKeyGenerator.INSTANCE.generateKey(contentUri);
final HttpResponse response = HttpTestUtils.make200Response();
response.setHeader("ETag","\"new-etag\"");
response.setHeader("Date", "huh?");
response.setHeader("Content-Location", contentUri.toASCIIString());
backing.putEntry(contentKey, HttpTestUtils.makeCacheEntry(
new BasicHeader("ETag", "\"old-etag\""),
new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo))));
impl.evictInvalidatedEntries(host, request, response);
verify(backing).getEntry(contentKey);
verify(backing).removeEntry(contentKey);
}
@Test
public void testInvalidatesUriSpecifiedByContentLocationIfEntryHasMalformedDate() throws Exception {
final HttpRequest request = new BasicHttpRequest("PUT", "/foo");
final URI contentUri = new URIBuilder()
.setHttpHost(host)
.setPath("/bar")
.build();
final String contentKey = CacheKeyGenerator.INSTANCE.generateKey(contentUri);
final HttpResponse response = HttpTestUtils.make200Response();
response.setHeader("ETag","\"new-etag\"");
response.setHeader("Date", DateUtils.formatStandardDate(now));
response.setHeader("Content-Location", contentUri.toASCIIString());
backing.putEntry(contentKey, HttpTestUtils.makeCacheEntry(
new BasicHeader("ETag", "\"old-etag\""),
new BasicHeader("Date", "huh?")));
impl.evictInvalidatedEntries(host, request, response);
verify(backing).getEntry(contentKey);
verify(backing).removeEntry(contentKey);
}
}