View Javadoc
1   package de.juplo.httpresources;
2   
3   
4   import mockit.Expectations;
5   import mockit.Injectable;
6   import mockit.Verifications;
7   import org.apache.http.Header;
8   import org.apache.http.HttpHeaders;
9   import org.apache.http.client.methods.CloseableHttpResponse;
10  import org.apache.http.client.methods.HttpUriRequest;
11  import org.apache.http.conn.HttpHostConnectException;
12  import org.apache.http.impl.client.CloseableHttpClient;
13  import org.apache.http.protocol.HttpContext;
14  import org.junit.jupiter.api.DisplayName;
15  import org.junit.jupiter.api.Test;
16  import org.slf4j.Logger;
17  import org.slf4j.LoggerFactory;
18  import org.springframework.cache.Cache;
19  import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
20  
21  import java.net.InetAddress;
22  import java.net.URI;
23  import java.time.Clock;
24  import java.time.ZoneId;
25  
26  import static de.juplo.httpresources.HttpData.NOT_FETCHED;
27  import static de.juplo.httpresources.HttpResourceFetcher.DEFAULT_TTL;
28  import static de.juplo.httpresources.TestUtil.*;
29  import static org.junit.Assert.*;
30  
31  
32  /**
33   * Tests the inner class {@link HttpResourceFetcher}.
34   * @author Kai Moritz
35   */
36  public class HttpResourceFetcherTest
37  {
38    private final static Logger LOG =
39        LoggerFactory.getLogger(HttpResourceFetcherTest.class);
40  
41    final static String ADDRESS = "http://foo/bar";
42    final static URI ADDRESS_URI = URI.create(ADDRESS);
43  
44    final static HttpData WHATEVER = DATA_EXPIRED_DUMMY;
45    final static HttpData SAME_AS_CACHED = DATA_NOT_EXPIRED_DUMMY;
46  
47    @Injectable
48    CloseableHttpClient client;
49    @Injectable
50    CloseableHttpResponse response;
51    @Injectable
52    Cache cache;
53  
54    Clock clock;
55    HttpResourceFetcher fetcher;
56    HttpResources resources;
57  
58    public void withServeStaleFalse()
59    {
60      Clock clock = Clock.fixed(NOW.toInstant(), ZoneId.of("GMT"));
61      fetcher = new HttpResourceFetcher(
62          new HttpComponentsClientHttpRequestFactory(client),
63          cache,
64          clock,
65          DEFAULT_TTL,
66          0,
67          false);
68      resources = new HttpResources(
69          fetcher,
70          clock);
71    }
72  
73    public void withServeStaleFalseAndMinTTL()
74    { 
75      clock = Clock.fixed(NOW.toInstant(), ZoneId.of("GMT"));
76      fetcher = new HttpResourceFetcher(
77          new HttpComponentsClientHttpRequestFactory(client),
78          cache,
79          clock,
80          DEFAULT_TTL,
81          MIN_TTL,
82          false);
83      resources = new HttpResources(
84          fetcher,
85          clock);
86    }
87  
88    public void withServeStaleTrue()
89    {
90      Clock clock = Clock.fixed(NOW.toInstant(), ZoneId.of("GMT"));
91      fetcher = new HttpResourceFetcher(
92          new HttpComponentsClientHttpRequestFactory(client),
93          cache,
94          clock);
95      resources = new HttpResources(
96          fetcher,
97          clock);
98    }
99  
100 
101   @Test
102   @DisplayName("first request -- cached - valid")
103   public void test_Fetch_Cached_Valid() throws Exception
104   {
105     LOG.info("<-- start of test-case");
106     withServeStaleFalse();
107     new Expectations()
108     {{
109       cache.get(withInstanceOf(URI.class), withEqual(HttpData.class)); result = DATA_NOT_EXPIRED;
110       // Should not be called...
111       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); result = response; minTimes = 0;
112       response.getStatusLine(); result = OK; minTimes = 0;
113       response.getAllHeaders(); result = new Header[0]; minTimes = 0;
114       response.getEntity(); result = null; minTimes = 0;
115       response.close(); minTimes = 0;
116     }};
117 
118     HttpData data = fetcher.fetch(ADDRESS_URI, NOT_FETCHED);
119 
120     new Verifications()
121     {{
122       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); times = 0;
123     }};
124 
125     assertEquals(data, DATA_NOT_EXPIRED);
126   }
127 
128 
129   @Test
130   @DisplayName("first request -- cached - expired")
131   public void test_Fetch_Cached_Expired() throws Exception
132   {
133     LOG.info("<-- start of test-case");
134     withServeStaleFalse();
135     new Expectations()
136     {{
137       cache.get(withInstanceOf(URI.class), withEqual(HttpData.class)); result = DATA_EXPIRED;
138       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); result = response;
139       response.getStatusLine(); result = OK;
140       response.getAllHeaders(); result = new Header[0];
141       response.getEntity(); result = null;
142       response.close();
143     }};
144 
145     HttpData data = fetcher.fetch(ADDRESS_URI, NOT_FETCHED);
146 
147     new Verifications()
148     {{
149       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); times = 1;
150       cache.put(ADDRESS_URI, data);
151     }};
152 
153     assertNull(data.headers.getContentType());
154     assertNotNull(data.content);
155     assertEquals("", new String(data.content, UTF8));
156     assertEquals(LONG_NOW + DEFAULT_TTL, data.expires);
157     assertFalse(data.revalidate);
158     assertNull(data.eTag);
159     assertEquals(0l, data.lastModified);
160   }
161 
162 
163   @Test
164   @DisplayName("first request -- cached - not found")
165   public void test_Fetch_Cached_NotFound() throws Exception
166   {
167     LOG.info("<-- start of test-case");
168     withServeStaleFalse();
169     new Expectations()
170     {{
171       cache.get(withInstanceOf(URI.class), withEqual(HttpData.class)); result = HttpData.NOT_FOUND;
172       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); result = response;
173       response.getStatusLine(); result = OK;
174       response.getAllHeaders(); result = new Header[0];
175       response.getEntity(); result = null;
176       response.close();
177     }};
178 
179     HttpData data = fetcher.fetch(ADDRESS_URI, NOT_FETCHED);
180 
181     new Verifications()
182     {{
183       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); times = 1;
184       cache.put(ADDRESS_URI, data);
185     }};
186 
187     assertNull(data.headers.getContentType());
188     assertNotNull(data.content);
189     assertEquals("", new String(data.content, UTF8));
190     assertEquals(LONG_NOW + DEFAULT_TTL, data.expires);
191     assertFalse(data.revalidate);
192     assertNull(data.eTag);
193     assertEquals(0l, data.lastModified);
194   }
195 
196 
197   @Test
198   @DisplayName("first request -- cached - server error")
199   public void test_Fetch_Cached_ServerError() throws Exception
200   {
201     LOG.info("<-- start of test-case");
202     withServeStaleFalse();
203     new Expectations()
204     {{
205       cache.get(withInstanceOf(URI.class), withEqual(HttpData.class)); result = HttpData.SERVER_ERROR;
206       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); result = response;
207       response.getStatusLine(); result = OK;
208       response.getAllHeaders(); result = new Header[0];
209       response.getEntity(); result = null;
210       response.close();
211     }};
212 
213     HttpData data = fetcher.fetch(ADDRESS_URI, NOT_FETCHED);
214 
215     new Verifications()
216     {{
217       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); times = 1;
218       cache.put(ADDRESS_URI, data);
219     }};
220 
221     assertNull(data.headers.getContentType());
222     assertNotNull(data.content);
223     assertEquals("", new String(data.content, UTF8));
224     assertEquals(LONG_NOW + DEFAULT_TTL, data.expires);
225     assertFalse(data.revalidate);
226     assertNull(data.eTag);
227     assertEquals(0l, data.lastModified);
228   }
229 
230 
231   @Test
232   @DisplayName("first request -- 200 - no headers / no body")
233   public void test_Fetch_200_NoHeaders_NoBody() throws Exception
234   {
235     LOG.info("<-- start of test-case");
236     withServeStaleFalse();
237     new Expectations()
238     {{
239       cache.get(withInstanceOf(URI.class), withEqual(HttpData.class)); result = null;
240       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); result = response;
241       response.getStatusLine(); result = OK;
242       response.getAllHeaders(); result = new Header[0];
243       response.getEntity(); result = null;
244       response.close();
245     }};
246 
247     HttpData data = fetcher.fetch(ADDRESS_URI, NOT_FETCHED);
248 
249     new Verifications()
250     {{
251       HttpUriRequest request;
252       client.execute(request = withCapture(), withInstanceOf(HttpContext.class)); times = 1;
253       assertEquals(ADDRESS_URI, request.getURI());
254       assertNull(request.getLastHeader(HttpHeaders.IF_NONE_MATCH));
255       assertNull(request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE));
256       cache.put(ADDRESS_URI, data);
257     }};
258 
259     assertNull(data.headers.getContentType());
260     assertNotNull(data.content);
261     assertEquals("", new String(data.content, UTF8));
262     assertEquals(LONG_NOW + DEFAULT_TTL, data.expires);
263     assertFalse(data.revalidate);
264     assertNull(data.eTag);
265     assertEquals(0l, data.lastModified);
266   }
267 
268 
269   @Test
270   @DisplayName("first request -- 200 - no headers")
271   public void test_Fetch_200_NoHeaders() throws Exception
272   {
273     LOG.info("<-- start of test-case");
274     withServeStaleFalse();
275     new Expectations()
276     {{
277       cache.get(withInstanceOf(URI.class), withEqual(HttpData.class)); result = null;
278       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); result = response;
279       response.getStatusLine(); result = OK;
280       response.getAllHeaders(); result = new Header[0];
281       response.getEntity(); result = BODY;
282       response.close();
283     }};
284 
285     HttpData data = fetcher.fetch(ADDRESS_URI, NOT_FETCHED);
286 
287     new Verifications()
288     {{
289       HttpUriRequest request;
290       client.execute(request = withCapture(), withInstanceOf(HttpContext.class)); times = 1;
291       assertEquals(ADDRESS_URI, request.getURI());
292       assertNull(request.getLastHeader(HttpHeaders.IF_NONE_MATCH));
293       assertNull(request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE));
294       cache.put(ADDRESS_URI, data);
295     }};
296 
297     assertNull(data.headers.getContentType());
298     assertNotNull(data.content);
299     assertEquals(STR_CONTENT, new String(data.content, UTF8));
300     assertEquals(LONG_NOW + DEFAULT_TTL, data.expires);
301     assertFalse(data.revalidate);
302     assertNull(data.eTag);
303     assertEquals(0l, data.lastModified);
304   }
305 
306 
307   @Test
308   @DisplayName("first request -- 200 - HTTP/1.1")
309   public void test_Fetch_200_HTTP11() throws Exception
310   {
311     LOG.info("<-- start of test-case");
312     withServeStaleFalse();
313     new Expectations()
314     {{
315       cache.get(withInstanceOf(URI.class), withEqual(HttpData.class)); result = null;
316       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); result = response;
317       response.getStatusLine(); result = OK;
318       response.getAllHeaders(); result = new Header[] { CONTENT_TYPE_HTML, DATE, LAST_MODIFIED, ETAG, CACHE_CONTROL_MAX_AGE };
319       response.getEntity(); result = BODY;
320       response.close();
321     }};
322 
323     HttpData data = fetcher.fetch(ADDRESS_URI, NOT_FETCHED);
324 
325     new Verifications()
326     {{
327       HttpUriRequest request;
328       client.execute(request = withCapture(), withInstanceOf(HttpContext.class)); times = 1;
329       assertEquals(ADDRESS_URI, request.getURI());
330       assertNull(request.getLastHeader(HttpHeaders.IF_NONE_MATCH));
331       assertNull(request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE));
332       cache.put(ADDRESS_URI, data);
333     }};
334 
335     assertEquals(MIME_TYPE_CONTENT_TYPE_HTML, data.headers.getContentType());
336     assertNotNull(data.content);
337     assertEquals(STR_CONTENT, new String(data.content, UTF8));
338     assertEquals(LONG_SEND + (MAX_AGE - 1) * 1000, data.expires);
339     assertFalse(data.revalidate);
340     assertEquals(STR_ETAG, data.eTag);
341     assertEquals(LONG_THEN, data.lastModified);
342   }
343 
344   @Test
345   @DisplayName("first request + min-TTL -- 200 - HTTP/1.1")
346   public void test_Fetch_200_HTTP11_MinTTL() throws Exception
347   {
348     LOG.info("<-- start of test-case");
349     withServeStaleFalseAndMinTTL();
350     new Expectations()
351     {{
352       cache.get(withInstanceOf(URI.class), withEqual(HttpData.class)); result = null;
353       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); result = response;
354       response.getStatusLine(); result = OK;
355       response.getAllHeaders(); result = new Header[] { CONTENT_TYPE_HTML, DATE, LAST_MODIFIED, ETAG, CACHE_CONTROL_MAX_AGE };
356       response.getEntity(); result = BODY;
357       response.close();
358     }};
359 
360     HttpData data = fetcher.fetch(ADDRESS_URI, NOT_FETCHED);
361 
362     new Verifications()
363     {{
364       HttpUriRequest request;
365       client.execute(request = withCapture(), withInstanceOf(HttpContext.class)); times = 1;
366       assertEquals(ADDRESS_URI, request.getURI());
367       assertNull(request.getLastHeader(HttpHeaders.IF_NONE_MATCH));
368       assertNull(request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE));
369       cache.put(ADDRESS_URI, data);
370     }};
371 
372     assertEquals(MIME_TYPE_CONTENT_TYPE_HTML, data.headers.getContentType());
373     assertNotNull(data.content);
374     assertEquals(STR_CONTENT, new String(data.content, UTF8));
375     assertEquals(LONG_SEND + MIN_TTL - 1000, data.expires);
376     assertFalse(data.revalidate);
377     assertEquals(STR_ETAG, data.eTag);
378     assertEquals(LONG_THEN, data.lastModified);
379   }
380 
381 
382   @Test
383   @DisplayName("first request -- 200 - HTTP/1.1 / Date-Header is missing")
384   public void test_Fetch_200_HTTP11_DateMissing_() throws Exception
385   {
386     LOG.info("<-- start of test-case");
387     withServeStaleFalse();
388     new Expectations()
389     {{
390       cache.get(withInstanceOf(URI.class), withEqual(HttpData.class)); result = null;
391       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); result = response;
392       response.getStatusLine(); result = OK;
393       response.getAllHeaders(); result = new Header[] { CONTENT_TYPE_HTML, LAST_MODIFIED, ETAG, CACHE_CONTROL_MAX_AGE };
394       response.getEntity(); result = BODY;
395       response.close();
396     }};
397 
398     HttpData data = fetcher.fetch(ADDRESS_URI, NOT_FETCHED);
399 
400     new Verifications()
401     {{
402       HttpUriRequest request;
403       client.execute(request = withCapture(), withInstanceOf(HttpContext.class)); times = 1;
404       assertEquals(ADDRESS_URI, request.getURI());
405       assertNull(request.getLastHeader(HttpHeaders.IF_NONE_MATCH));
406       assertNull(request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE));
407       cache.put(ADDRESS_URI, data);
408     }};
409 
410     assertEquals(MIME_TYPE_CONTENT_TYPE_HTML, data.headers.getContentType());
411     assertNotNull(data.content);
412     assertEquals(STR_CONTENT, new String(data.content, UTF8));
413     assertEquals(LONG_NOW + MAX_AGE * 1000, data.expires);
414     assertFalse(data.revalidate);
415     assertEquals(STR_ETAG, data.eTag);
416     assertEquals(LONG_THEN, data.lastModified);
417   }
418 
419 
420   @Test
421   @DisplayName("first request -- 200 - HTTP/1.1 / Cache-Control: public, max-age=0")
422   public void test_Fetch_200_HTTP11_MaxAge0() throws Exception
423   {
424     LOG.info("<-- start of test-case");
425     withServeStaleFalse();
426     new Expectations()
427     {{
428       cache.get(withInstanceOf(URI.class), withEqual(HttpData.class)); result = null;
429       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); result = response;
430       response.getStatusLine(); result = OK;
431       response.getAllHeaders(); result = new Header[] { CONTENT_TYPE_HTML, DATE, LAST_MODIFIED, ETAG, CACHE_CONTROL_MAX_AGE_0 };
432       response.getEntity(); result = BODY;
433       response.close();
434     }};
435 
436     HttpData data = fetcher.fetch(ADDRESS_URI, NOT_FETCHED);
437 
438     new Verifications()
439     {{
440       HttpUriRequest request;
441       client.execute(request = withCapture(), withInstanceOf(HttpContext.class)); times = 1;
442       assertEquals(ADDRESS_URI, request.getURI());
443       assertNull(request.getLastHeader(HttpHeaders.IF_NONE_MATCH));
444       assertNull(request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE));
445       cache.put(ADDRESS_URI, data);
446     }};
447 
448     assertEquals(MIME_TYPE_CONTENT_TYPE_HTML, data.headers.getContentType());
449     assertNotNull(data.content);
450     assertEquals(LONG_SEND - 1000, data.expires);
451     assertFalse(data.revalidate);
452     assertEquals(STR_ETAG, data.eTag);
453     assertEquals(LONG_THEN, data.lastModified);
454   }
455   @Test
456   @DisplayName("first request -- 200 - HTTP/1.1 / Cache-Control: no-cache")
457   public void test_Fetch_200_HTTP11_NoCache() throws Exception
458   {
459     LOG.info("<-- start of test-case");
460     withServeStaleFalse();
461     new Expectations()
462     {{
463       cache.get(withInstanceOf(URI.class), withEqual(HttpData.class)); result = null;
464       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); result = response;
465       response.getStatusLine(); result = OK;
466       response.getAllHeaders(); result = new Header[] { CONTENT_TYPE_HTML, DATE, LAST_MODIFIED, ETAG, CACHE_CONTROL_NO_CACHE };
467       response.getEntity(); result = BODY;
468       response.close();
469     }};
470 
471     HttpData data = fetcher.fetch(ADDRESS_URI, NOT_FETCHED);
472 
473     new Verifications()
474     {{
475       HttpUriRequest request;
476       client.execute(request = withCapture(), withInstanceOf(HttpContext.class)); times = 1;
477       assertEquals(ADDRESS_URI, request.getURI());
478       assertNull(request.getLastHeader(HttpHeaders.IF_NONE_MATCH));
479       assertNull(request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE));
480       cache.put(ADDRESS_URI, data);
481     }};
482 
483     assertEquals(MIME_TYPE_CONTENT_TYPE_HTML, data.headers.getContentType());
484     assertNotNull(data.content);
485     assertEquals(LONG_SEND, data.expires);
486     assertFalse(data.revalidate);
487     assertEquals(STR_ETAG, data.eTag);
488     assertEquals(LONG_THEN, data.lastModified);
489   }
490 
491 
492   @Test
493   @DisplayName("first request -- 200 - HTTP/1.1 / Cache-Control: no-cache=\"Cookie\"")
494   public void test_Fetch_200_HTTP11_NoCacheQualified() throws Exception
495   {
496     LOG.info("<-- start of test-case");
497     withServeStaleFalse();
498     new Expectations()
499     {{
500       cache.get(withInstanceOf(URI.class), withEqual(HttpData.class)); result = null;
501       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); result = response;
502       response.getStatusLine(); result = OK;
503       response.getAllHeaders(); result = new Header[] { CONTENT_TYPE_HTML, DATE, LAST_MODIFIED, ETAG, CACHE_CONTROL_NO_CACHE_QUALIFIED };
504       response.getEntity(); result = BODY;
505       response.close();
506     }};
507 
508     HttpData data = fetcher.fetch(ADDRESS_URI, NOT_FETCHED);
509 
510     new Verifications()
511     {{
512       HttpUriRequest request;
513       client.execute(request = withCapture(), withInstanceOf(HttpContext.class)); times = 1;
514       assertEquals(ADDRESS_URI, request.getURI());
515       assertNull(request.getLastHeader(HttpHeaders.IF_NONE_MATCH));
516       assertNull(request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE));
517       cache.put(ADDRESS_URI, data);
518     }};
519 
520     assertEquals(MIME_TYPE_CONTENT_TYPE_HTML, data.headers.getContentType());
521     assertNotNull(data.content);
522     assertEquals(STR_CONTENT, new String(data.content, UTF8));
523     assertEquals(LONG_SEND + (MAX_AGE - 1) * 1000, data.expires);
524     assertFalse(data.revalidate);
525     assertEquals(STR_ETAG, data.eTag);
526     assertEquals(LONG_THEN, data.lastModified);
527   }
528 
529 
530   @Test
531   @DisplayName("first request -- 200 - HTTP/1.0")
532   public void test_Fetch_200_HTTP10() throws Exception
533   {
534     LOG.info("<-- start of test-case");
535     withServeStaleFalse();
536     new Expectations()
537     {{
538       cache.get(withInstanceOf(URI.class), withEqual(HttpData.class)); result = null;
539       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); result = response;
540       response.getStatusLine(); result = OK;
541       response.getAllHeaders(); result = new Header[] { CONTENT_TYPE_HTML, DATE, LAST_MODIFIED, EXPIRES_VALID };
542       response.getEntity(); result = BODY;
543       response.close();
544     }};
545 
546     HttpData data = fetcher.fetch(ADDRESS_URI, NOT_FETCHED);
547 
548     new Verifications()
549     {{
550       HttpUriRequest request;
551       client.execute(request = withCapture(), withInstanceOf(HttpContext.class)); times = 1;
552       assertEquals(ADDRESS_URI, request.getURI());
553       assertNull(request.getLastHeader(HttpHeaders.IF_NONE_MATCH));
554       assertNull(request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE));
555       cache.put(ADDRESS_URI, data);
556     }};
557 
558     assertEquals(MIME_TYPE_CONTENT_TYPE_HTML, data.headers.getContentType());
559     assertNotNull(data.content);
560     assertEquals(STR_CONTENT, new String(data.content, UTF8));
561     assertEquals(LONG_FEATURE, data.expires);
562     assertFalse(data.revalidate);
563     assertNull(data.eTag);
564     assertEquals(LONG_THEN, data.lastModified);
565   }
566 
567 
568   @Test
569   @DisplayName("first request -- 200 - HTTP/1.0 / invalid Expires-Header")
570   public void test_Fetch_200_HTTP10_InvalidExpires() throws Exception
571   {
572     LOG.info("<-- start of test-case");
573     withServeStaleFalse();
574     new Expectations()
575     {{
576       cache.get(withInstanceOf(URI.class), withEqual(HttpData.class)); result = null;
577       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); result = response;
578       response.getStatusLine(); result = OK;
579       response.getAllHeaders(); result = new Header[] { CONTENT_TYPE_HTML, DATE, LAST_MODIFIED, EXPIRES_INVALID };
580       response.getEntity(); result = BODY;
581       response.close();
582     }};
583 
584     HttpData data = fetcher.fetch(ADDRESS_URI, NOT_FETCHED);
585 
586     new Verifications()
587     {{
588       HttpUriRequest request;
589       client.execute(request = withCapture(), withInstanceOf(HttpContext.class)); times = 1;
590       assertEquals(ADDRESS_URI, request.getURI());
591       assertNull(request.getLastHeader(HttpHeaders.IF_NONE_MATCH));
592       assertNull(request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE));
593       cache.put(ADDRESS_URI, data);
594     }};
595 
596     assertEquals(MIME_TYPE_CONTENT_TYPE_HTML, data.headers.getContentType());
597     assertNotNull(data.content);
598     assertEquals(0l, data.expires);
599     assertFalse(data.revalidate);
600     assertNull(data.eTag);
601     assertEquals(LONG_THEN, data.lastModified);
602   }
603 
604 
605   @Test
606   @DisplayName("first request -- 200 - HTTP/mixed: Expires + Cache-Control: private")
607   public void test_Fetch_200_Mixed() throws Exception
608   {
609     LOG.info("<-- start of test-case");
610     withServeStaleFalse();
611     new Expectations()
612     {{
613       cache.get(withInstanceOf(URI.class), withEqual(HttpData.class)); result = null;
614       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); result = response;
615       response.getStatusLine(); result = OK;
616       response.getAllHeaders(); result = new Header[] { CONTENT_TYPE_HTML, DATE, LAST_MODIFIED, ETAG, EXPIRES_VALID, CACHE_CONTROL_PRIVATE };
617       response.getEntity(); result = BODY;
618       response.close();
619     }};
620 
621     HttpData data = fetcher.fetch(ADDRESS_URI, NOT_FETCHED);
622 
623     new Verifications()
624     {{
625       HttpUriRequest request;
626       client.execute(request = withCapture(), withInstanceOf(HttpContext.class)); times = 1;
627       assertEquals(ADDRESS_URI, request.getURI());
628       assertNull(request.getLastHeader(HttpHeaders.IF_NONE_MATCH));
629       assertNull(request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE));
630       cache.put(ADDRESS_URI, data);
631     }};
632 
633     assertEquals(MIME_TYPE_CONTENT_TYPE_HTML, data.headers.getContentType());
634     assertNotNull(data.content);
635     assertEquals(STR_CONTENT, new String(data.content, UTF8));
636     assertEquals(LONG_FEATURE, data.expires);
637     assertFalse(data.revalidate);
638     assertEquals(STR_ETAG, data.eTag);
639     assertEquals(LONG_THEN, data.lastModified);
640   }
641 
642 
643   @Test
644   @DisplayName("first request -- 200 - HTTP/mixed: Expires + Cache-Control: max-age")
645   public void test_Fetch_200_Mixed_ExpiresOverwritten() throws Exception
646   {
647     LOG.info("<-- start of test-case");
648     withServeStaleFalse();
649     new Expectations()
650     {{
651       cache.get(withInstanceOf(URI.class), withEqual(HttpData.class)); result = null;
652       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); result = response;
653       response.getStatusLine(); result = OK;
654       response.getAllHeaders(); result = new Header[] { CONTENT_TYPE_HTML, DATE, LAST_MODIFIED, ETAG, CACHE_CONTROL_MAX_AGE };
655       response.getEntity(); result = BODY;
656       response.close();
657     }};
658 
659     HttpData data = fetcher.fetch(ADDRESS_URI, NOT_FETCHED);
660 
661     new Verifications()
662     {{
663       HttpUriRequest request;
664       client.execute(request = withCapture(), withInstanceOf(HttpContext.class)); times = 1;
665       assertEquals(ADDRESS_URI, request.getURI());
666       assertNull(request.getLastHeader(HttpHeaders.IF_NONE_MATCH));
667       assertNull(request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE));
668       cache.put(ADDRESS_URI, data);
669     }};
670 
671     assertEquals(DATA_NOT_EXPIRED, data);
672   }
673 
674 
675   @Test
676   @DisplayName("first request -- 200 - HTTP/1.1 + Content-Encoding: gzip")
677   public void test_Fetch_200_HTTP11_Encoding() throws Exception
678   {
679     LOG.info("<-- start of test-case");
680     withServeStaleFalse();
681     new Expectations()
682     {{
683       cache.get(withInstanceOf(URI.class), withEqual(HttpData.class)); result = null;
684       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); result = response;
685       response.getStatusLine(); result = OK;
686       response.getAllHeaders(); result = new Header[] { CONTENT_TYPE_HTML, CONTENT_ENCODING, DATE, LAST_MODIFIED, ETAG, CACHE_CONTROL_MAX_AGE };
687       response.getEntity(); result = BODY_GZIPPED;
688       response.close();
689     }};
690 
691     HttpData data = fetcher.fetch(ADDRESS_URI, NOT_FETCHED);
692 
693     new Verifications()
694     {{
695       HttpUriRequest request;
696       client.execute(request = withCapture(), withInstanceOf(HttpContext.class)); times = 1;
697       assertEquals(ADDRESS_URI, request.getURI());
698       assertNull(request.getLastHeader(HttpHeaders.IF_NONE_MATCH));
699       assertNull(request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE));
700       cache.put(ADDRESS_URI, data);
701     }};
702 
703     assertEquals(MIME_TYPE_CONTENT_TYPE_HTML, data.headers.getContentType());
704     assertNotNull(data.content);
705     assertEquals(new String(CONTENT_GZIPPED), new String(data.content, UTF8));
706     assertEquals(LONG_SEND + (MAX_AGE - 1) * 1000, data.expires);
707     assertFalse(data.revalidate);
708     assertEquals(STR_ETAG, data.eTag);
709     assertEquals(LONG_THEN, data.lastModified);
710   }
711 
712   @Test
713   @DisplayName("first request -- 200 - HTTP/1.1 + Cache-Control: must-revalidate")
714   public void test_Fetch_200_HTTP11_MustRevalidate() throws Exception
715   {
716     LOG.info("<-- start of test-case");
717     withServeStaleFalse();
718     new Expectations()
719     {{
720       cache.get(withInstanceOf(URI.class), withEqual(HttpData.class)); result = null;
721       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); result = response;
722       response.getStatusLine(); result = OK;
723       response.getAllHeaders(); result = new Header[] { CONTENT_TYPE_HTML, DATE, LAST_MODIFIED, ETAG, CACHE_CONTROL_REVALIDATE };
724       response.getEntity(); result = BODY;
725       response.close();
726     }};
727 
728     HttpData data = fetcher.fetch(ADDRESS_URI, NOT_FETCHED);
729 
730     new Verifications()
731     {{
732       HttpUriRequest request;
733       client.execute(request = withCapture(), withInstanceOf(HttpContext.class)); times = 1;
734       assertEquals(ADDRESS_URI, request.getURI());
735       assertNull(request.getLastHeader(HttpHeaders.IF_NONE_MATCH));
736       assertNull(request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE));
737       cache.put(ADDRESS_URI, data);
738     }};
739 
740     assertEquals(DATA_NOT_EXPIRED_REVALIDATION_REQUIRED, data);
741   }
742 
743 
744   @Test
745   @DisplayName("first request -- 400 - HTTP/1.1")
746   public void test_Fetch_404_HTTP11() throws Exception
747   {
748     LOG.info("<-- start of test-case");
749     withServeStaleFalse();
750     new Expectations()
751     {{
752       cache.get(withInstanceOf(URI.class), withEqual(HttpData.class)); result = null;
753       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); result = response;
754       response.getStatusLine(); result = NOT_FOUND;
755       response.getAllHeaders(); result = new Header[] { DATE };
756       response.close();
757     }};
758 
759     HttpData data = fetcher.fetch(ADDRESS_URI, NOT_FETCHED);
760 
761     new Verifications()
762     {{
763       HttpUriRequest request;
764       client.execute(request = withCapture(), withInstanceOf(HttpContext.class)); times = 1;
765       assertEquals(ADDRESS_URI, request.getURI());
766       assertNull(request.getLastHeader(HttpHeaders.IF_NONE_MATCH));
767       assertNull(request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE));
768       cache.put(ADDRESS_URI, data);
769     }};
770 
771     assertNull(data.headers.getContentType());
772     assertNull(data.content);
773     assertEquals(LONG_SEND - 1000, data.expires);
774     assertFalse(data.revalidate);
775     assertNull(data.eTag);
776     assertEquals(0, data.lastModified);
777   }
778 
779 
780   @Test
781   @DisplayName("first request -- 404 - HTTP/1.1 + Cache-Control: max-age")
782   public void test_Fetch_404_HTTP11_Cacheable() throws Exception
783   {
784     LOG.info("<-- start of test-case");
785     withServeStaleFalse();
786     new Expectations()
787     {{
788       cache.get(withInstanceOf(URI.class), withEqual(HttpData.class)); result = null;
789       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); result = response;
790       response.getStatusLine(); result = NOT_FOUND;
791       response.getAllHeaders(); result = new Header[] { DATE };
792       response.close();
793     }};
794 
795     HttpData data = fetcher.fetch(ADDRESS_URI, NOT_FETCHED);
796 
797     new Verifications()
798     {{
799       HttpUriRequest request;
800       client.execute(request = withCapture(), withInstanceOf(HttpContext.class)); times = 1;
801       assertEquals(ADDRESS_URI, request.getURI());
802       assertNull(request.getLastHeader(HttpHeaders.IF_NONE_MATCH));
803       assertNull(request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE));
804       cache.put(ADDRESS_URI, data);
805     }};
806 
807     assertEquals(DATA_NOT_FOUND, data);
808   }
809 
810 
811   @Test
812   @DisplayName("first request -- 500 - HTTP/1.1")
813   public void test_Fetch_500_HTTP11() throws Exception
814   {
815     LOG.info("<-- start of test-case");
816     withServeStaleFalse();
817     new Expectations()
818     {{
819       cache.get(withInstanceOf(URI.class), withEqual(HttpData.class)); result = null;
820       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); result = response; times = 1;
821       response.getStatusLine(); result = SERVER_ERROR;
822       response.close();
823     }};
824 
825     HttpData data = fetcher.fetch(ADDRESS_URI, NOT_FETCHED);
826 
827     new Verifications()
828     {{
829       HttpUriRequest request;
830       client.execute(request = withCapture(), withInstanceOf(HttpContext.class)); times = 1;
831       assertEquals(ADDRESS_URI, request.getURI());
832       assertNull(request.getLastHeader(HttpHeaders.IF_NONE_MATCH));
833       assertNull(request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE));
834       cache.put(ADDRESS_URI, data);
835     }};
836 
837     assertEquals(HttpData.SERVER_ERROR, data);
838   }
839 
840 
841   @Test
842   @DisplayName("first request -- server is down")
843   public void test_Fetch_ServerDown() throws Exception
844   {
845     LOG.info("<-- start of test-case");
846     withServeStaleFalse();
847     new Expectations()
848     {{
849       cache.get(withInstanceOf(URI.class), withEqual(HttpData.class)); result = null;
850       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); result = new HttpHostConnectException(null, null, (InetAddress)null);
851     }};
852 
853     HttpData data = fetcher.fetch(ADDRESS_URI, NOT_FETCHED);
854 
855     new Verifications()
856     {{
857       HttpUriRequest request;
858       client.execute(request = withCapture(), withInstanceOf(HttpContext.class)); times = 1;
859       assertEquals(ADDRESS_URI, request.getURI());
860       assertNull(request.getLastHeader(HttpHeaders.IF_NONE_MATCH));
861       assertNull(request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE));
862       cache.put(ADDRESS_URI, data);
863     }};
864 
865     assertEquals(HttpData.SERVER_ERROR, data);
866   }
867 
868 
869   @Test
870   @DisplayName("update request -- cached - same -> request is executed")
871   public void test_Update_Cached_Same_RequestIsExecuted() throws Exception
872   {
873     LOG.info("<-- start of test-case");
874     withServeStaleFalse();
875     new Expectations()
876     {{
877       cache.get(withInstanceOf(URI.class), withEqual(HttpData.class)); result = SAME_AS_CACHED;
878       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); result = response; minTimes = 0;
879       response.getStatusLine(); result = NOT_MODIFIED; minTimes = 0;
880       response.getAllHeaders(); result = new Header[] { DATE, LAST_MODIFIED, ETAG, CACHE_CONTROL_MAX_AGE }; minTimes = 0;
881       response.close(); minTimes = 0;
882     }};
883 
884     HttpData data = fetcher.fetch(ADDRESS_URI, SAME_AS_CACHED);
885 
886     new Verifications()
887     {{
888       HttpUriRequest request;
889       client.execute(request = withCapture(), withInstanceOf(HttpContext.class));
890       times = 1;
891       assertEquals(ADDRESS_URI, request.getURI());
892       assertNotNull(request.getLastHeader(HttpHeaders.IF_NONE_MATCH));
893       assertEquals(STR_ETAG, request.getLastHeader(HttpHeaders.IF_NONE_MATCH).getValue());
894       assertNotNull(request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE));
895       assertEquals(STR_THEN, request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE).getValue());
896       cache.put(ADDRESS_URI, data);
897     }};
898 
899     assertEquals(DATA_NOT_EXPIRED, data);
900   }
901 
902 
903   @Test
904   @DisplayName("update request -- cached - valid")
905   public void test_Update_Cached_Valid() throws Exception
906   {
907     LOG.info("<-- start of test-case");
908     withServeStaleFalse();
909     new Expectations()
910     {{
911       cache.get(withInstanceOf(URI.class), withEqual(HttpData.class)); result = DATA_NOT_EXPIRED;
912       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); result = response; minTimes = 0;
913       response.getStatusLine(); result = NOT_MODIFIED; minTimes = 0;
914       response.getAllHeaders(); result = new Header[] { DATE, LAST_MODIFIED, ETAG, CACHE_CONTROL_MAX_AGE }; minTimes = 0;
915       response.close(); minTimes = 0;
916     }};
917 
918     HttpData data = fetcher.fetch(ADDRESS_URI, WHATEVER);
919 
920     new Verifications()
921     {{
922       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); times = 0;
923     }};
924 
925     assertEquals(data, DATA_NOT_EXPIRED);
926   }
927 
928 
929   @Test
930   @DisplayName("update request -- cached - expired -> request is executed")
931   public void test_Update_Cached_Expired_RequestIsExecuted() throws Exception
932   {
933     LOG.info("<-- start of test-case");
934     withServeStaleFalse();
935     new Expectations()
936     {{
937       cache.get(withInstanceOf(URI.class), withEqual(HttpData.class)); result = DATA_EXPIRED;
938       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); result = response; minTimes = 0;
939       response.getStatusLine(); result = NOT_MODIFIED; minTimes = 0;
940       response.getAllHeaders(); result = new Header[] { DATE, LAST_MODIFIED, ETAG, CACHE_CONTROL_MAX_AGE }; minTimes = 0;
941       response.close(); minTimes = 0;
942     }};
943 
944     HttpData data = fetcher.fetch(ADDRESS_URI, WHATEVER);
945 
946     new Verifications()
947     {{
948       HttpUriRequest request;
949       client.execute(request = withCapture(), withInstanceOf(HttpContext.class));
950       times = 1;
951       assertEquals(ADDRESS_URI, request.getURI());
952       assertNotNull(request.getLastHeader(HttpHeaders.IF_NONE_MATCH));
953       assertEquals(STR_ETAG, request.getLastHeader(HttpHeaders.IF_NONE_MATCH).getValue());
954       assertNotNull(request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE));
955       assertEquals(STR_THEN, request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE).getValue());
956       cache.put(ADDRESS_URI, data);
957     }};
958 
959     assertEquals(DATA_NOT_EXPIRED, data);
960   }
961 
962 
963   @Test
964   @DisplayName("update request -- 304: not modified")
965   public void test_Update_304() throws Exception
966   {
967     LOG.info("<-- start of test-case");
968     withServeStaleFalse();
969     new Expectations()
970     {{
971       cache.get(withInstanceOf(URI.class), withEqual(HttpData.class)); result = null;
972       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); result = response; minTimes = 0;
973       response.getStatusLine(); result = NOT_MODIFIED; minTimes = 0;
974       response.getAllHeaders(); result = new Header[] { DATE, LAST_MODIFIED, ETAG, CACHE_CONTROL_MAX_AGE }; minTimes = 0;
975       response.close(); minTimes = 0;
976     }};
977 
978     HttpData data = fetcher.fetch(ADDRESS_URI, DATA_EXPIRED);
979 
980     new Verifications()
981     {{
982       HttpUriRequest request;
983       client.execute(request = withCapture(), withInstanceOf(HttpContext.class));
984       times = 1;
985       assertEquals(ADDRESS_URI, request.getURI());
986       assertNotNull(request.getLastHeader(HttpHeaders.IF_NONE_MATCH));
987       assertEquals(STR_ETAG, request.getLastHeader(HttpHeaders.IF_NONE_MATCH).getValue());
988       assertNotNull(request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE));
989       assertEquals(STR_THEN, request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE).getValue());
990       cache.put(ADDRESS_URI, data);
991     }};
992 
993     assertEquals(DATA_NOT_EXPIRED, data);
994   }
995 
996 
997   @Test
998   @DisplayName("update request -- 200: modified")
999   public void test_Update_200() throws Exception
1000   {
1001     LOG.info("<-- start of test-case");
1002     withServeStaleFalse();
1003     new Expectations()
1004     {{
1005       cache.get(withInstanceOf(URI.class), withEqual(HttpData.class)); result = null;
1006       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); result = response; minTimes = 0;
1007       response.getStatusLine(); result = OK; minTimes = 0;
1008       response.getAllHeaders(); result = new Header[] { CONTENT_TYPE_HTML, DATE_MODIFIED, LAST_MODIFIED_MODIFIED, ETAG_MODIFIED, CACHE_CONTROL_MAX_AGE }; minTimes = 0;
1009       response.getEntity(); result = BODY_MODIFIED; minTimes = 0;
1010       response.close(); minTimes = 0;
1011     }};
1012 
1013     HttpData data = fetcher.fetch(ADDRESS_URI, DATA_EXPIRED);
1014 
1015     new Verifications()
1016     {{
1017       HttpUriRequest request;
1018       client.execute(request = withCapture(), withInstanceOf(HttpContext.class));
1019       times = 1;
1020       assertEquals(ADDRESS_URI, request.getURI());
1021       assertNotNull(request.getLastHeader(HttpHeaders.IF_NONE_MATCH));
1022       assertEquals(STR_ETAG, request.getLastHeader(HttpHeaders.IF_NONE_MATCH).getValue());
1023       assertNotNull(request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE));
1024       assertEquals(STR_THEN, request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE).getValue());
1025       cache.put(ADDRESS_URI, data);
1026     }};
1027 
1028     assertEquals(DATA_UPDATED, data);
1029   }
1030 
1031 
1032   @Test
1033   @DisplayName("update request -- 404: not found")
1034   public void test_Update_404() throws Exception
1035   {
1036     LOG.info("<-- start of test-case");
1037     withServeStaleFalse();
1038     new Expectations()
1039     {{
1040       cache.get(withInstanceOf(URI.class), withEqual(HttpData.class)); result = null;
1041       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); result = response; minTimes = 0;
1042       response.getStatusLine(); result = NOT_FOUND; minTimes = 0;
1043       response.getAllHeaders(); result = new Header[] { DATE }; minTimes = 0;
1044       response.close(); minTimes = 0;
1045     }};
1046 
1047     HttpData data = fetcher.fetch(ADDRESS_URI, DATA_EXPIRED);
1048 
1049     new Verifications()
1050     {{
1051       HttpUriRequest request;
1052       client.execute(request = withCapture(), withInstanceOf(HttpContext.class));
1053       times = 1;
1054       assertNotNull(request.getLastHeader(HttpHeaders.IF_NONE_MATCH));
1055       assertEquals(STR_ETAG, request.getLastHeader(HttpHeaders.IF_NONE_MATCH).getValue());
1056       assertNotNull(request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE));
1057       assertEquals(STR_THEN, request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE).getValue());
1058       cache.put(ADDRESS_URI, data);
1059     }};
1060 
1061     assertEquals(DATA_NOT_FOUND, data);
1062   }
1063 
1064 
1065   @Test
1066   @DisplayName("update request -- 500: server error")
1067   public void test_Update_500() throws Exception
1068   {
1069     LOG.info("<-- start of test-case");
1070     withServeStaleFalse();
1071     new Expectations()
1072     {{
1073       cache.get(withInstanceOf(URI.class), withEqual(HttpData.class)); result = null;
1074       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); result = response; minTimes = 0;
1075       response.getStatusLine(); result = SERVER_ERROR; minTimes = 0;
1076       response.close(); minTimes = 0;
1077     }};
1078 
1079     HttpData data = fetcher.fetch(ADDRESS_URI, DATA_EXPIRED);
1080 
1081     new Verifications()
1082     {{
1083       HttpUriRequest request;
1084       client.execute(request = withCapture(), withInstanceOf(HttpContext.class));
1085       times = 1;
1086       assertEquals(ADDRESS_URI, request.getURI());
1087       assertNotNull(request.getLastHeader(HttpHeaders.IF_NONE_MATCH));
1088       assertEquals(STR_ETAG, request.getLastHeader(HttpHeaders.IF_NONE_MATCH).getValue());
1089       assertNotNull(request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE));
1090       assertEquals(STR_THEN, request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE).getValue());
1091       cache.put(ADDRESS_URI, data);
1092     }};
1093 
1094     assertEquals(DATA_EXPIRED, data);
1095   }
1096 
1097 
1098   @Test
1099   @DisplayName("update request -- must revalidate / 304: not modified")
1100   public void test_Update_MustRevalidate_304() throws Exception
1101   {
1102     LOG.info("<-- start of test-case");
1103     withServeStaleFalse();
1104     new Expectations()
1105     {{
1106       cache.get(withInstanceOf(URI.class), withEqual(HttpData.class)); result = null;
1107       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); result = response; minTimes = 0;
1108       response.getStatusLine(); result = NOT_MODIFIED; minTimes = 0;
1109       response.getAllHeaders(); result = new Header[] { DATE, LAST_MODIFIED, ETAG, CACHE_CONTROL_MAX_AGE }; minTimes = 0;
1110       response.close(); minTimes = 0;
1111     }};
1112 
1113     HttpResource resource = new HttpResource(resources, fetcher, clock, ADDRESS_URI);
1114     resource.data = DATA_NOT_EXPIRED_REVALIDATION_REQUIRED;
1115 
1116     HttpData data = fetcher.fetch(resource.uri, resource.data);
1117 
1118     new Verifications()
1119     {{
1120       HttpUriRequest request;
1121       client.execute(request = withCapture(), withInstanceOf(HttpContext.class));
1122       times = 1;
1123       assertEquals(ADDRESS_URI, request.getURI());
1124       assertNotNull(request.getLastHeader(HttpHeaders.IF_NONE_MATCH));
1125       assertEquals(STR_ETAG, request.getLastHeader(HttpHeaders.IF_NONE_MATCH).getValue());
1126       assertNotNull(request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE));
1127       assertEquals(STR_THEN, request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE).getValue());
1128       cache.put(ADDRESS_URI, data);
1129     }};
1130 
1131     assertEquals(DATA_NOT_EXPIRED, data); // << Flag "revalidate" is cleared, because header ist not set
1132   }
1133 
1134 
1135   @Test
1136   @DisplayName("update request -- must-revalidate / 500: server error")
1137   public void test_Update_MustRevalidate_500() throws Exception
1138   {
1139     LOG.info("<-- start of test-case");
1140     withServeStaleFalse();
1141     new Expectations()
1142     {{
1143       cache.get(withInstanceOf(URI.class), withEqual(HttpData.class)); result = null;
1144       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); result = response; minTimes = 0;
1145       response.getStatusLine(); result = SERVER_ERROR; minTimes = 0;
1146       response.close(); minTimes = 0;
1147     }};
1148 
1149     HttpData data = fetcher.fetch(ADDRESS_URI, DATA_NOT_EXPIRED_REVALIDATION_REQUIRED);
1150 
1151     new Verifications() {{
1152       HttpUriRequest request;
1153       client.execute(request = withCapture(), withInstanceOf(HttpContext.class));
1154       times = 1;
1155       assertNotNull(request.getLastHeader(HttpHeaders.IF_NONE_MATCH));
1156       assertEquals(STR_ETAG, request.getLastHeader(HttpHeaders.IF_NONE_MATCH).getValue());
1157       assertNotNull(request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE));
1158       assertEquals(STR_THEN, request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE).getValue());
1159       cache.put(ADDRESS_URI, data);
1160     }};
1161 
1162     assertEquals(HttpData.SERVER_ERROR, data);
1163   }
1164 
1165 
1166   @Test
1167   @DisplayName("update request + serve-stale -- 404: not found")
1168   public void test_Update_404_ServeStale() throws Exception
1169   {
1170     LOG.info("<-- start of test-case");
1171     withServeStaleTrue();
1172     new Expectations()
1173     {{
1174       cache.get(withInstanceOf(URI.class), withEqual(HttpData.class)); result = null;
1175       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); result = response; minTimes = 0;
1176       response.getStatusLine(); result = NOT_FOUND; minTimes = 0;
1177       response.close(); minTimes = 0;
1178     }};
1179 
1180     HttpData data = fetcher.fetch(ADDRESS_URI, DATA_EXPIRED);
1181 
1182     new Verifications()
1183     {{
1184       HttpUriRequest request;
1185       client.execute(request = withCapture(), withInstanceOf(HttpContext.class));
1186       assertNotNull(request.getLastHeader(HttpHeaders.IF_NONE_MATCH));
1187       assertEquals(STR_ETAG, request.getLastHeader(HttpHeaders.IF_NONE_MATCH).getValue());
1188       assertNotNull(request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE));
1189       assertEquals(STR_THEN, request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE).getValue());
1190       cache.put(ADDRESS_URI, data);
1191     }};
1192 
1193     assertEquals(DATA_EXPIRED, data);
1194   }
1195 
1196 
1197   @Test
1198   @DisplayName("update request + serve-stale -- must-revalidate / 500: server error")
1199   public void test_Update_500_MustRevalidate_ServeStale() throws Exception
1200   {
1201     LOG.info("<-- start of test-case");
1202     withServeStaleTrue();
1203     new Expectations()
1204     {{
1205       cache.get(withInstanceOf(URI.class), withEqual(HttpData.class)); result = null;
1206       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); result = response; minTimes = 0;
1207       response.getStatusLine(); result = SERVER_ERROR; minTimes = 0;
1208       response.close(); minTimes = 0;
1209     }};
1210 
1211     HttpData data = fetcher.fetch(ADDRESS_URI, DATA_NOT_EXPIRED_REVALIDATION_REQUIRED);
1212 
1213     new Verifications()
1214     {{
1215       HttpUriRequest request;
1216       client.execute(request = withCapture(), withInstanceOf(HttpContext.class)); times = 1;
1217       assertNotNull(request.getLastHeader(HttpHeaders.IF_NONE_MATCH));
1218       assertEquals(STR_ETAG, request.getLastHeader(HttpHeaders.IF_NONE_MATCH).getValue());
1219       assertNotNull(request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE));
1220       assertEquals(STR_THEN, request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE).getValue());
1221       cache.put(ADDRESS_URI, data);
1222     }};
1223 
1224     assertEquals(DATA_NOT_EXPIRED_REVALIDATION_REQUIRED, data);
1225   }
1226 
1227 
1228   @Test
1229   @DisplayName("update request -- server is down")
1230   public void test_Update_ServerDown() throws Exception
1231   {
1232     LOG.info("<-- start of test-case");
1233     withServeStaleFalse();
1234     new Expectations()
1235     {{
1236       cache.get(withInstanceOf(URI.class), withEqual(HttpData.class)); result = null;
1237       client.execute(withInstanceOf(HttpUriRequest.class), withInstanceOf(HttpContext.class)); result = new HttpHostConnectException(null, null, (InetAddress)null); minTimes = 0;
1238     }};
1239 
1240     HttpData data = fetcher.fetch(ADDRESS_URI, DATA_EXPIRED);
1241 
1242     new Verifications()
1243     {{
1244       HttpUriRequest request;
1245       client.execute(request = withCapture(), withInstanceOf(HttpContext.class));
1246       times = 1;
1247       assertNotNull(request.getLastHeader(HttpHeaders.IF_NONE_MATCH));
1248       assertEquals(STR_ETAG, request.getLastHeader(HttpHeaders.IF_NONE_MATCH).getValue());
1249       assertNotNull(request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE));
1250       assertEquals(STR_THEN, request.getLastHeader(HttpHeaders.IF_MODIFIED_SINCE).getValue());
1251       cache.put(ADDRESS_URI, data);
1252     }};
1253 
1254     assertEquals(DATA_EXPIRED, data);
1255   }
1256 }