1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package org.apache.hc.client5.http.impl.cache;
28
29 import static org.mockito.Mockito.verify;
30 import static org.mockito.Mockito.verifyNoMoreInteractions;
31 import static org.mockito.Mockito.when;
32
33 import java.io.IOException;
34 import java.net.URI;
35 import java.time.Instant;
36 import java.util.HashMap;
37 import java.util.Map;
38
39 import org.apache.hc.client5.http.cache.HttpCacheEntry;
40 import org.apache.hc.client5.http.cache.HttpCacheStorage;
41 import org.apache.hc.client5.http.utils.DateUtils;
42 import org.apache.hc.core5.function.Resolver;
43 import org.apache.hc.core5.http.Header;
44 import org.apache.hc.core5.http.HttpHost;
45 import org.apache.hc.core5.http.HttpRequest;
46 import org.apache.hc.core5.http.HttpResponse;
47 import org.apache.hc.core5.http.HttpStatus;
48 import org.apache.hc.core5.http.message.BasicHeader;
49 import org.apache.hc.core5.http.message.BasicHttpRequest;
50 import org.apache.hc.core5.http.message.BasicHttpResponse;
51 import org.junit.jupiter.api.BeforeEach;
52 import org.junit.jupiter.api.Test;
53 import org.mockito.ArgumentMatchers;
54 import org.mockito.Mock;
55 import org.mockito.MockitoAnnotations;
56 import org.mockito.stubbing.Answer;
57
58 public class TestDefaultCacheInvalidator {
59
60 private DefaultCacheInvalidator impl;
61 private HttpHost host;
62 @Mock
63 private HttpCacheEntry mockEntry;
64 @Mock
65 private Resolver<URI, String> cacheKeyResolver;
66 @Mock
67 private HttpCacheStorage mockStorage;
68
69 private Instant now;
70 private Instant tenSecondsAgo;
71
72 @BeforeEach
73 public void setUp() {
74 MockitoAnnotations.openMocks(this);
75 now = Instant.now();
76 tenSecondsAgo = now.minusSeconds(10);
77
78 when(cacheKeyResolver.resolve(ArgumentMatchers.any())).thenAnswer((Answer<String>) invocation -> {
79 final URI uri = invocation.getArgument(0);
80 return HttpCacheSupport.normalize(uri).toASCIIString();
81 });
82
83 host = new HttpHost("foo.example.com");
84 impl = new DefaultCacheInvalidator();
85 }
86
87
88 @Test
89 public void testInvalidatesRequestsThatArentGETorHEAD() throws Exception {
90 final HttpRequest request = new BasicHttpRequest("POST","/path");
91 final String key = "http://foo.example.com:80/path";
92 final Map<String,String> variantMap = new HashMap<>();
93 cacheEntryHasVariantMap(variantMap);
94
95 cacheReturnsEntryForUri(key);
96
97 impl.flushCacheEntriesInvalidatedByRequest(host, request, cacheKeyResolver, mockStorage);
98
99 verify(mockEntry).getVariantMap();
100 verify(mockStorage).getEntry(key);
101 verify(mockStorage).removeEntry(key);
102 }
103
104 @Test
105 public void testInvalidatesUrisInContentLocationHeadersOnPUTs() throws Exception {
106 final HttpRequest request = new BasicHttpRequest("PUT","/");
107 request.setHeader("Content-Length","128");
108
109 final String contentLocation = "http://foo.example.com/content";
110 request.setHeader("Content-Location", contentLocation);
111
112 final URI uri = new URI("http://foo.example.com:80/");
113 final String key = uri.toASCIIString();
114 cacheEntryHasVariantMap(new HashMap<>());
115
116 cacheReturnsEntryForUri(key);
117
118 impl.flushCacheEntriesInvalidatedByRequest(host, request, cacheKeyResolver, mockStorage);
119
120 verify(mockEntry).getVariantMap();
121 verify(mockStorage).getEntry(key);
122 verify(mockStorage).removeEntry(key);
123 verify(mockStorage).removeEntry("http://foo.example.com:80/content");
124 }
125
126 @Test
127 public void testInvalidatesUrisInLocationHeadersOnPUTs() throws Exception {
128 final HttpRequest request = new BasicHttpRequest("PUT","/");
129 request.setHeader("Content-Length","128");
130
131 final String contentLocation = "http://foo.example.com/content";
132 request.setHeader("Location",contentLocation);
133
134 final URI uri = new URI("http://foo.example.com:80/");
135 final String key = uri.toASCIIString();
136 cacheEntryHasVariantMap(new HashMap<>());
137
138 cacheReturnsEntryForUri(key);
139
140 impl.flushCacheEntriesInvalidatedByRequest(host, request, cacheKeyResolver, mockStorage);
141
142 verify(mockEntry).getVariantMap();
143 verify(mockStorage).getEntry(key);
144 verify(mockStorage).removeEntry(key);
145 verify(mockStorage).removeEntry("http://foo.example.com:80/content");
146 }
147
148 @Test
149 public void testInvalidatesRelativeUrisInContentLocationHeadersOnPUTs() throws Exception {
150 final HttpRequest request = new BasicHttpRequest("PUT","/");
151 request.setHeader("Content-Length","128");
152
153 final String relativePath = "/content";
154 request.setHeader("Content-Location",relativePath);
155
156 final URI uri = new URI("http://foo.example.com:80/");
157 final String key = uri.toASCIIString();
158 cacheEntryHasVariantMap(new HashMap<>());
159
160 cacheReturnsEntryForUri(key);
161
162 impl.flushCacheEntriesInvalidatedByRequest(host, request, cacheKeyResolver, mockStorage);
163
164 verify(mockEntry).getVariantMap();
165 verify(mockStorage).getEntry(key);
166 verify(mockStorage).removeEntry(key);
167 verify(mockStorage).removeEntry("http://foo.example.com:80/content");
168 }
169
170 @Test
171 public void testDoesNotInvalidateUrisInContentLocationHeadersOnPUTsToDifferentHosts() throws Exception {
172 final HttpRequest request = new BasicHttpRequest("PUT","/");
173 request.setHeader("Content-Length","128");
174
175 final String contentLocation = "http://bar.example.com/content";
176 request.setHeader("Content-Location",contentLocation);
177
178 final URI uri = new URI("http://foo.example.com:80/");
179 final String key = uri.toASCIIString();
180 cacheEntryHasVariantMap(new HashMap<>());
181
182 cacheReturnsEntryForUri(key);
183
184 impl.flushCacheEntriesInvalidatedByRequest(host, request, cacheKeyResolver, mockStorage);
185
186 verify(mockEntry).getVariantMap();
187 verify(mockStorage).getEntry(key);
188 verify(mockStorage).removeEntry(key);
189 }
190
191 @Test
192 public void testDoesNotInvalidateGETRequest() throws Exception {
193 final HttpRequest request = new BasicHttpRequest("GET","/");
194 impl.flushCacheEntriesInvalidatedByRequest(host, request, cacheKeyResolver, mockStorage);
195
196 verify(mockStorage).getEntry("http://foo.example.com:80/");
197 verifyNoMoreInteractions(mockStorage);
198 }
199
200 @Test
201 public void testDoesNotInvalidateHEADRequest() throws Exception {
202 final HttpRequest request = new BasicHttpRequest("HEAD","/");
203 impl.flushCacheEntriesInvalidatedByRequest(host, request, cacheKeyResolver, mockStorage);
204
205 verify(mockStorage).getEntry("http://foo.example.com:80/");
206 verifyNoMoreInteractions(mockStorage);
207 }
208
209 @Test
210 public void testInvalidatesHEADCacheEntryIfSubsequentGETRequestsAreMadeToTheSameURI() throws Exception {
211 final URI uri = new URI("http://foo.example.com:80/");
212 final String key = uri.toASCIIString();
213 final HttpRequest request = new BasicHttpRequest("GET", uri);
214
215 cacheEntryisForMethod("HEAD");
216 cacheEntryHasVariantMap(new HashMap<>());
217 cacheReturnsEntryForUri(key);
218
219 impl.flushCacheEntriesInvalidatedByRequest(host, request, cacheKeyResolver, mockStorage);
220
221 verify(mockEntry).getRequestMethod();
222 verify(mockEntry).getVariantMap();
223 verify(mockStorage).getEntry(key);
224 verify(mockStorage).removeEntry(key);
225 }
226
227 @Test
228 public void testInvalidatesVariantHEADCacheEntriesIfSubsequentGETRequestsAreMadeToTheSameURI() throws Exception {
229 final URI uri = new URI("http://foo.example.com:80/");
230 final String key = uri.toASCIIString();
231 final HttpRequest request = new BasicHttpRequest("GET", uri);
232 final String theVariantKey = "{Accept-Encoding=gzip%2Cdeflate&User-Agent=Apache-HttpClient}";
233 final String theVariantURI = "{Accept-Encoding=gzip%2Cdeflate&User-Agent=Apache-HttpClient}http://foo.example.com:80/";
234 final Map<String, String> variants = HttpTestUtils.makeDefaultVariantMap(theVariantKey, theVariantURI);
235
236 cacheEntryisForMethod("HEAD");
237 cacheEntryHasVariantMap(variants);
238 cacheReturnsEntryForUri(key);
239
240 impl.flushCacheEntriesInvalidatedByRequest(host, request, cacheKeyResolver, mockStorage);
241
242 verify(mockEntry).getRequestMethod();
243 verify(mockEntry).getVariantMap();
244 verify(mockStorage).getEntry(key);
245 verify(mockStorage).removeEntry(key);
246 verify(mockStorage).removeEntry(theVariantURI);
247 }
248
249 @Test
250 public void testDoesNotInvalidateHEADCacheEntry() throws Exception {
251 final URI uri = new URI("http://foo.example.com:80/");
252 final String key = uri.toASCIIString();
253 final HttpRequest request = new BasicHttpRequest("HEAD", uri);
254
255 cacheReturnsEntryForUri(key);
256
257 impl.flushCacheEntriesInvalidatedByRequest(host, request, cacheKeyResolver, mockStorage);
258
259 verify(mockStorage).getEntry(key);
260 verifyNoMoreInteractions(mockStorage);
261 }
262
263 @Test
264 public void testDoesNotInvalidateHEADCacheEntryIfSubsequentHEADRequestsAreMadeToTheSameURI() throws Exception {
265 final URI uri = new URI("http://foo.example.com:80/");
266 final String key = uri.toASCIIString();
267 final HttpRequest request = new BasicHttpRequest("HEAD", uri);
268
269 cacheReturnsEntryForUri(key);
270
271 impl.flushCacheEntriesInvalidatedByRequest(host, request, cacheKeyResolver, mockStorage);
272
273 verify(mockStorage).getEntry(key);
274 verifyNoMoreInteractions(mockStorage);
275 }
276
277 @Test
278 public void testDoesNotInvalidateGETCacheEntryIfSubsequentGETRequestsAreMadeToTheSameURI() throws Exception {
279 final URI uri = new URI("http://foo.example.com:80/");
280 final String key = uri.toASCIIString();
281 final HttpRequest request = new BasicHttpRequest("GET", uri);
282
283 cacheEntryisForMethod("GET");
284 cacheReturnsEntryForUri(key);
285
286 impl.flushCacheEntriesInvalidatedByRequest(host, request, cacheKeyResolver, mockStorage);
287
288 verify(mockEntry).getRequestMethod();
289 verify(mockStorage).getEntry(key);
290 verifyNoMoreInteractions(mockStorage);
291 }
292
293 @Test
294 public void testDoesNotInvalidateRequestsWithClientCacheControlHeaders() throws Exception {
295 final HttpRequest request = new BasicHttpRequest("GET","/");
296 request.setHeader("Cache-Control","no-cache");
297
298 impl.flushCacheEntriesInvalidatedByRequest(host, request, cacheKeyResolver, mockStorage);
299
300 verify(mockStorage).getEntry("http://foo.example.com:80/");
301 verifyNoMoreInteractions(mockStorage);
302 }
303
304 @Test
305 public void testDoesNotInvalidateRequestsWithClientPragmaHeaders() throws Exception {
306 final HttpRequest request = new BasicHttpRequest("GET","/");
307 request.setHeader("Pragma","no-cache");
308
309 impl.flushCacheEntriesInvalidatedByRequest(host, request, cacheKeyResolver, mockStorage);
310
311 verify(mockStorage).getEntry("http://foo.example.com:80/");
312 verifyNoMoreInteractions(mockStorage);
313 }
314
315 @Test
316 public void testVariantURIsAreFlushedAlso() throws Exception {
317 final HttpRequest request = new BasicHttpRequest("POST","/");
318 final URI uri = new URI("http://foo.example.com:80/");
319 final String key = uri.toASCIIString();
320 final String variantUri = "theVariantURI";
321 final Map<String,String> mapOfURIs = HttpTestUtils.makeDefaultVariantMap(variantUri, variantUri);
322
323 cacheReturnsEntryForUri(key);
324 cacheEntryHasVariantMap(mapOfURIs);
325
326 impl.flushCacheEntriesInvalidatedByRequest(host, request, cacheKeyResolver, mockStorage);
327
328 verify(mockStorage).getEntry(key);
329 verify(mockEntry).getVariantMap();
330 verify(mockStorage).removeEntry(variantUri);
331 verify(mockStorage).removeEntry(key);
332 }
333
334 @Test
335 public void doesNotFlushForResponsesWithoutContentLocation() throws Exception {
336 final HttpRequest request = new BasicHttpRequest("POST","/");
337 final HttpResponse response = new BasicHttpResponse(HttpStatus.SC_OK);
338 impl.flushCacheEntriesInvalidatedByExchange(host, request, response, cacheKeyResolver, mockStorage);
339
340 verifyNoMoreInteractions(mockStorage);
341 }
342
343 @Test
344 public void flushesEntryIfFresherAndSpecifiedByContentLocation() throws Exception {
345 final HttpRequest request = new BasicHttpRequest("GET", "/");
346 final HttpResponse response = new BasicHttpResponse(HttpStatus.SC_OK);
347 response.setHeader("ETag","\"new-etag\"");
348 response.setHeader("Date", DateUtils.formatStandardDate(now));
349 final String key = "http://foo.example.com:80/bar";
350 response.setHeader("Content-Location", key);
351
352 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
353 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
354 new BasicHeader("ETag", "\"old-etag\"")
355 });
356
357 when(mockStorage.getEntry(key)).thenReturn(entry);
358
359 impl.flushCacheEntriesInvalidatedByExchange(host, request, response, cacheKeyResolver, mockStorage);
360
361 verify(mockStorage).getEntry(key);
362 verify(mockStorage).removeEntry(key);
363 }
364
365 @Test
366 public void flushesEntryIfFresherAndSpecifiedByLocation() throws Exception {
367 final HttpRequest request = new BasicHttpRequest("GET", "/");
368 final HttpResponse response = new BasicHttpResponse(201);
369 response.setHeader("ETag","\"new-etag\"");
370 response.setHeader("Date", DateUtils.formatStandardDate(now));
371 final String key = "http://foo.example.com:80/bar";
372 response.setHeader("Location", key);
373
374 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
375 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
376 new BasicHeader("ETag", "\"old-etag\"")
377 });
378
379 when(mockStorage.getEntry(key)).thenReturn(entry);
380
381 impl.flushCacheEntriesInvalidatedByExchange(host, request, response, cacheKeyResolver, mockStorage);
382
383 verify(mockStorage).getEntry(key);
384 verify(mockStorage).removeEntry(key);
385 }
386
387 @Test
388 public void doesNotFlushEntryForUnsuccessfulResponse() throws Exception {
389 final HttpRequest request = new BasicHttpRequest("GET", "/");
390 final HttpResponse response = new BasicHttpResponse(HttpStatus.SC_BAD_REQUEST, "Bad Request");
391 response.setHeader("ETag","\"new-etag\"");
392 response.setHeader("Date", DateUtils.formatStandardDate(now));
393 final String key = "http://foo.example.com:80/bar";
394 response.setHeader("Content-Location", key);
395
396 impl.flushCacheEntriesInvalidatedByExchange(host, request, response, cacheKeyResolver, mockStorage);
397
398 verifyNoMoreInteractions(mockStorage);
399 }
400
401 @Test
402 public void flushesEntryIfFresherAndSpecifiedByNonCanonicalContentLocation() throws Exception {
403 final HttpRequest request = new BasicHttpRequest("GET", "/");
404 final HttpResponse response = new BasicHttpResponse(HttpStatus.SC_OK);
405 response.setHeader("ETag","\"new-etag\"");
406 response.setHeader("Date", DateUtils.formatStandardDate(now));
407 final String cacheKey = "http://foo.example.com:80/bar";
408 response.setHeader("Content-Location", "http://foo.example.com/bar");
409
410 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
411 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
412 new BasicHeader("ETag", "\"old-etag\"")
413 });
414
415 when(mockStorage.getEntry(cacheKey)).thenReturn(entry);
416
417 impl.flushCacheEntriesInvalidatedByExchange(host, request, response, cacheKeyResolver, mockStorage);
418
419 verify(mockStorage).getEntry(cacheKey);
420 verify(mockStorage).removeEntry(cacheKey);
421 }
422
423 @Test
424 public void flushesEntryIfFresherAndSpecifiedByRelativeContentLocation() throws Exception {
425 final HttpRequest request = new BasicHttpRequest("GET", "/");
426 final HttpResponse response = new BasicHttpResponse(HttpStatus.SC_OK);
427 response.setHeader("ETag","\"new-etag\"");
428 response.setHeader("Date", DateUtils.formatStandardDate(now));
429 final String cacheKey = "http://foo.example.com:80/bar";
430 response.setHeader("Content-Location", "/bar");
431
432 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
433 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
434 new BasicHeader("ETag", "\"old-etag\"")
435 });
436
437 when(mockStorage.getEntry(cacheKey)).thenReturn(entry);
438
439 impl.flushCacheEntriesInvalidatedByExchange(host, request, response, cacheKeyResolver, mockStorage);
440
441 verify(mockStorage).getEntry(cacheKey);
442 verify(mockStorage).removeEntry(cacheKey);
443 }
444
445 @Test
446 public void doesNotFlushEntryIfContentLocationFromDifferentHost() throws Exception {
447 final HttpRequest request = new BasicHttpRequest("GET", "/");
448 final HttpResponse response = new BasicHttpResponse(HttpStatus.SC_OK);
449 response.setHeader("ETag","\"new-etag\"");
450 response.setHeader("Date", DateUtils.formatStandardDate(now));
451 final String cacheKey = "http://baz.example.com:80/bar";
452 response.setHeader("Content-Location", cacheKey);
453
454 impl.flushCacheEntriesInvalidatedByExchange(host, request, response, cacheKeyResolver, mockStorage);
455
456 verifyNoMoreInteractions(mockStorage);
457 }
458
459 @Test
460 public void doesNotFlushEntrySpecifiedByContentLocationIfEtagsMatch() throws Exception {
461 final HttpRequest request = new BasicHttpRequest("GET", "/");
462 final HttpResponse response = new BasicHttpResponse(HttpStatus.SC_OK);
463 response.setHeader("ETag","\"same-etag\"");
464 response.setHeader("Date", DateUtils.formatStandardDate(now));
465 final String key = "http://foo.example.com:80/bar";
466 response.setHeader("Content-Location", key);
467
468 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
469 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
470 new BasicHeader("ETag", "\"same-etag\"")
471 });
472
473 when(mockStorage.getEntry(key)).thenReturn(entry);
474 impl.flushCacheEntriesInvalidatedByExchange(host, request, response, cacheKeyResolver, mockStorage);
475
476 verify(mockStorage).getEntry(key);
477 verifyNoMoreInteractions(mockStorage);
478 }
479
480 @Test
481 public void doesNotFlushEntrySpecifiedByContentLocationIfOlder() throws Exception {
482 final HttpRequest request = new BasicHttpRequest("GET", "/");
483 final HttpResponse response = new BasicHttpResponse(HttpStatus.SC_OK);
484 response.setHeader("ETag","\"new-etag\"");
485 response.setHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo));
486 final String key = "http://foo.example.com:80/bar";
487 response.setHeader("Content-Location", key);
488
489 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
490 new BasicHeader("Date", DateUtils.formatStandardDate(now)),
491 new BasicHeader("ETag", "\"old-etag\"")
492 });
493
494 when(mockStorage.getEntry(key)).thenReturn(entry);
495
496 impl.flushCacheEntriesInvalidatedByExchange(host, request, response, cacheKeyResolver, mockStorage);
497
498 verify(mockStorage).getEntry(key);
499 verifyNoMoreInteractions(mockStorage);
500 }
501
502 @Test
503 public void doesNotFlushEntryIfNotInCache() throws Exception {
504 final HttpRequest request = new BasicHttpRequest("GET", "/");
505 final HttpResponse response = new BasicHttpResponse(HttpStatus.SC_OK);
506 response.setHeader("ETag","\"new-etag\"");
507 response.setHeader("Date", DateUtils.formatStandardDate(now));
508 final String key = "http://foo.example.com:80/bar";
509 response.setHeader("Content-Location", key);
510
511 when(mockStorage.getEntry(key)).thenReturn(null);
512
513 impl.flushCacheEntriesInvalidatedByExchange(host, request, response, cacheKeyResolver, mockStorage);
514
515 verify(mockStorage).getEntry(key);
516 verifyNoMoreInteractions(mockStorage);
517 }
518
519 @Test
520 public void doesNotFlushEntrySpecifiedByContentLocationIfResponseHasNoEtag() throws Exception {
521 final HttpRequest request = new BasicHttpRequest("GET", "/");
522 final HttpResponse response = new BasicHttpResponse(HttpStatus.SC_OK);
523 response.removeHeaders("ETag");
524 response.setHeader("Date", DateUtils.formatStandardDate(now));
525 final String key = "http://foo.example.com:80/bar";
526 response.setHeader("Content-Location", key);
527
528 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
529 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
530 new BasicHeader("ETag", "\"old-etag\"")
531 });
532
533 when(mockStorage.getEntry(key)).thenReturn(entry);
534
535 impl.flushCacheEntriesInvalidatedByExchange(host, request, response, cacheKeyResolver, mockStorage);
536
537 verify(mockStorage).getEntry(key);
538 verifyNoMoreInteractions(mockStorage);
539 }
540
541 @Test
542 public void doesNotFlushEntrySpecifiedByContentLocationIfEntryHasNoEtag() throws Exception {
543 final HttpRequest request = new BasicHttpRequest("GET", "/");
544 final HttpResponse response = new BasicHttpResponse(HttpStatus.SC_OK);
545 response.setHeader("ETag", "\"some-etag\"");
546 response.setHeader("Date", DateUtils.formatStandardDate(now));
547 final String key = "http://foo.example.com:80/bar";
548 response.setHeader("Content-Location", key);
549
550 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
551 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
552 });
553
554 when(mockStorage.getEntry(key)).thenReturn(entry);
555
556 impl.flushCacheEntriesInvalidatedByExchange(host, request, response, cacheKeyResolver, mockStorage);
557
558 verify(mockStorage).getEntry(key);
559 verifyNoMoreInteractions(mockStorage);
560 }
561
562 @Test
563 public void flushesEntrySpecifiedByContentLocationIfResponseHasNoDate() throws Exception {
564 final HttpRequest request = new BasicHttpRequest("GET", "/");
565 final HttpResponse response = new BasicHttpResponse(HttpStatus.SC_OK);
566 response.setHeader("ETag", "\"new-etag\"");
567 response.removeHeaders("Date");
568 final String key = "http://foo.example.com:80/bar";
569 response.setHeader("Content-Location", key);
570
571 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
572 new BasicHeader("ETag", "\"old-etag\""),
573 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
574 });
575
576 when(mockStorage.getEntry(key)).thenReturn(entry);
577
578 impl.flushCacheEntriesInvalidatedByExchange(host, request, response, cacheKeyResolver, mockStorage);
579
580 verify(mockStorage).getEntry(key);
581 verify(mockStorage).removeEntry(key);
582 verifyNoMoreInteractions(mockStorage);
583 }
584
585 @Test
586 public void flushesEntrySpecifiedByContentLocationIfEntryHasNoDate() throws Exception {
587 final HttpRequest request = new BasicHttpRequest("GET", "/");
588 final HttpResponse response = new BasicHttpResponse(HttpStatus.SC_OK);
589 response.setHeader("ETag","\"new-etag\"");
590 response.setHeader("Date", DateUtils.formatStandardDate(now));
591 final String key = "http://foo.example.com:80/bar";
592 response.setHeader("Content-Location", key);
593
594 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
595 new BasicHeader("ETag", "\"old-etag\"")
596 });
597
598 when(mockStorage.getEntry(key)).thenReturn(entry);
599
600 impl.flushCacheEntriesInvalidatedByExchange(host, request, response, cacheKeyResolver, mockStorage);
601
602 verify(mockStorage).getEntry(key);
603 verify(mockStorage).removeEntry(key);
604 verifyNoMoreInteractions(mockStorage);
605 }
606
607 @Test
608 public void flushesEntrySpecifiedByContentLocationIfResponseHasMalformedDate() throws Exception {
609 final HttpRequest request = new BasicHttpRequest("GET", "/");
610 final HttpResponse response = new BasicHttpResponse(HttpStatus.SC_OK);
611 response.setHeader("ETag","\"new-etag\"");
612 response.setHeader("Date", "blarg");
613 final String key = "http://foo.example.com:80/bar";
614 response.setHeader("Content-Location", key);
615
616 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
617 new BasicHeader("ETag", "\"old-etag\""),
618 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo))
619 });
620
621 when(mockStorage.getEntry(key)).thenReturn(entry);
622
623 impl.flushCacheEntriesInvalidatedByExchange(host, request, response, cacheKeyResolver, mockStorage);
624
625 verify(mockStorage).getEntry(key);
626 verify(mockStorage).removeEntry(key);
627 verifyNoMoreInteractions(mockStorage);
628 }
629
630 @Test
631 public void flushesEntrySpecifiedByContentLocationIfEntryHasMalformedDate() throws Exception {
632 final HttpRequest request = new BasicHttpRequest("GET", "/");
633 final HttpResponse response = new BasicHttpResponse(HttpStatus.SC_OK);
634 response.setHeader("ETag","\"new-etag\"");
635 response.setHeader("Date", DateUtils.formatStandardDate(now));
636 final String key = "http://foo.example.com:80/bar";
637 response.setHeader("Content-Location", key);
638
639 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(new Header[] {
640 new BasicHeader("ETag", "\"old-etag\""),
641 new BasicHeader("Date", "foo")
642 });
643
644 when(mockStorage.getEntry(key)).thenReturn(entry);
645
646 impl.flushCacheEntriesInvalidatedByExchange(host, request, response, cacheKeyResolver, mockStorage);
647
648 verify(mockStorage).getEntry(key);
649 verify(mockStorage).removeEntry(key);
650 verifyNoMoreInteractions(mockStorage);
651 }
652
653
654
655 private void cacheEntryHasVariantMap(final Map<String,String> variantMap) {
656 when(mockEntry.getVariantMap()).thenReturn(variantMap);
657 }
658
659 private void cacheReturnsEntryForUri(final String key) throws IOException {
660 when(mockStorage.getEntry(key)).thenReturn(mockEntry);
661 }
662
663 private void cacheEntryisForMethod(final String httpMethod) {
664 when(mockEntry.getRequestMethod()).thenReturn(httpMethod);
665 }
666 }