source: josm/trunk/test/unit/org/openstreetmap/josm/data/cache/JCSCachedTileLoaderJobTest.java@ 19050

Last change on this file since 19050 was 19050, checked in by taylor.smock, 15 months ago

Revert most var changes from r19048, fix most new compile warnings and checkstyle issues

Also, document why various ErrorProne checks were originally disabled and fix
generic SonarLint issues.

  • Property svn:eol-style set to native
File size: 26.4 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.cache;
3
4import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
5import static com.github.tomakehurst.wiremock.client.WireMock.anyUrl;
6import static com.github.tomakehurst.wiremock.client.WireMock.get;
7import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor;
8import static com.github.tomakehurst.wiremock.client.WireMock.head;
9import static com.github.tomakehurst.wiremock.client.WireMock.headRequestedFor;
10import static com.github.tomakehurst.wiremock.client.WireMock.status;
11import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
12import static org.junit.jupiter.api.Assertions.assertArrayEquals;
13import static org.junit.jupiter.api.Assertions.assertEquals;
14import static org.junit.jupiter.api.Assertions.assertFalse;
15import static org.junit.jupiter.api.Assertions.assertTrue;
16
17import java.io.IOException;
18import java.net.MalformedURLException;
19import java.net.URL;
20import java.nio.charset.StandardCharsets;
21import java.util.concurrent.TimeUnit;
22
23import org.apache.commons.jcs3.access.behavior.ICacheAccess;
24import org.apache.commons.jcs3.engine.behavior.ICacheElement;
25import org.junit.jupiter.api.BeforeEach;
26import org.junit.jupiter.api.Test;
27import org.junit.jupiter.api.Timeout;
28import org.openstreetmap.josm.TestUtils;
29import org.openstreetmap.josm.data.cache.ICachedLoaderListener.LoadResult;
30import org.openstreetmap.josm.data.imagery.TileJobOptions;
31import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
32import org.openstreetmap.josm.testutils.annotations.BasicWiremock;
33import org.openstreetmap.josm.tools.Logging;
34
35import com.github.tomakehurst.wiremock.WireMockServer;
36import com.github.tomakehurst.wiremock.matching.UrlPattern;
37
38/**
39 * Unit tests for class {@link JCSCachedTileLoaderJob}.
40 */
41@BasicWiremock
42@BasicPreferences
43@Timeout(20)
44class JCSCachedTileLoaderJobTest {
45
46 /**
47 * mocked tile server
48 */
49 @BasicWiremock
50 WireMockServer tileServer;
51
52 private static class TestCachedTileLoaderJob extends JCSCachedTileLoaderJob<String, CacheEntry> {
53 private final String url;
54 private final String key;
55
56 TestCachedTileLoaderJob(String url, String key) {
57 this(url, key, (int) TimeUnit.DAYS.toSeconds(1));
58 }
59
60 TestCachedTileLoaderJob(String url, String key, int minimumExpiry) {
61 super(getCache(), new TileJobOptions(30000, 30000, null, minimumExpiry));
62
63 this.url = url;
64 this.key = key;
65 }
66
67 @Override
68 public String getCacheKey() {
69 return key;
70 }
71
72 @Override
73 public URL getUrl() {
74 try {
75 return new URL(url);
76 } catch (MalformedURLException e) {
77 throw new RuntimeException(e);
78 }
79 }
80
81 @Override
82 protected CacheEntry createCacheEntry(byte[] content) {
83 return new CacheEntry(content);
84 }
85 }
86
87 private static final class Listener implements ICachedLoaderListener {
88 private CacheEntryAttributes attributes;
89 private boolean ready;
90 private LoadResult result;
91 private byte[] data;
92
93 @Override
94 public synchronized void loadingFinished(CacheEntry data, CacheEntryAttributes attributes, LoadResult result) {
95 this.attributes = attributes;
96 this.ready = true;
97 this.result = result;
98 if (data != null) {
99 this.data = data.content;
100 }
101 this.notifyAll();
102 }
103 }
104
105 /**
106 * Always clear cache before tests
107 * @throws Exception when clearing fails
108 */
109 @BeforeEach
110 void clearCache() throws Exception {
111 getCache().clear();
112 }
113
114 /**
115 * Test status codes
116 * @throws InterruptedException in case of thread interruption
117 * @throws IOException in case of I/O error
118 */
119 @Test
120 void testStatusCodes() throws IOException, InterruptedException {
121 doTestStatusCode(200);
122 doTestStatusCode(401);
123 doTestStatusCode(402);
124 doTestStatusCode(403);
125 doTestStatusCode(404);
126 doTestStatusCode(405);
127 doTestStatusCode(500);
128 doTestStatusCode(501);
129 doTestStatusCode(502);
130 }
131
132 /**
133 * Test unknown host
134 * @throws IOException in case of I/O error
135 */
136 @Test
137 void testUnknownHost() throws IOException {
138 String key = "key_unknown_host";
139 TestCachedTileLoaderJob job = new TestCachedTileLoaderJob("http://unkownhost.unkownhost/unkown", key);
140 Listener listener = submitJob(job);
141 assertEquals(LoadResult.FAILURE, listener.result); // because response will be cached, and that is checked below
142 assertEquals("java.net.UnknownHostException: unkownhost.unkownhost", listener.attributes.getErrorMessage());
143
144 ICacheAccess<String, CacheEntry> cache = getCache();
145 CacheEntry e = new CacheEntry(new byte[]{0, 1, 2, 3});
146 CacheEntryAttributes attributes = new CacheEntryAttributes();
147 attributes.setExpirationTime(2);
148 cache.put(key, e, attributes);
149
150 job = new TestCachedTileLoaderJob("http://unkownhost.unkownhost/unkown", key);
151 listener = submitJob(job);
152 assertEquals(LoadResult.SUCCESS, listener.result);
153 assertFalse(job.isCacheElementValid());
154 }
155
156 private void doTestStatusCode(int responseCode) throws IOException {
157 tileServer.stubFor(get(urlEqualTo("/httpstat/" + responseCode)).willReturn(aResponse().withStatus(responseCode)));
158 TestCachedTileLoaderJob job = getStatusLoaderJob(responseCode);
159 Listener listener = submitJob(job);
160 assertEquals(responseCode, listener.attributes.getResponseCode());
161 }
162
163 private Listener submitJob(TestCachedTileLoaderJob job) throws IOException {
164 return submitJob(job, true);
165 }
166
167 private Listener submitJob(TestCachedTileLoaderJob job, boolean force) throws IOException {
168 Listener listener = new Listener();
169 job.submit(listener, force);
170 synchronized (listener) {
171 while (!listener.ready) {
172 try {
173 listener.wait();
174 } catch (InterruptedException e) {
175 // do nothing, wait
176 Logging.trace(e);
177 }
178 }
179 }
180 return listener;
181 }
182
183 /**
184 * That no request is made when entry is in cache and force == false
185 * @throws IOException exception
186 */
187 @Test
188 void testNoRequestMadeWhenEntryInCache() throws IOException {
189 ICacheAccess<String, CacheEntry> cache = getCache();
190 long expires = TimeUnit.DAYS.toMillis(1);
191 long testStart = System.currentTimeMillis();
192 cache.put("test",
193 new CacheEntry("cached entry".getBytes(StandardCharsets.UTF_8)),
194 createEntryAttributes(expires, 200, testStart, "eTag")
195 );
196 createHeadGetStub(urlEqualTo("/test"), expires, testStart, "eTag", "mock entry");
197
198 TestCachedTileLoaderJob job = new TestCachedTileLoaderJob(tileServer.url("/test"), "test");
199 Listener listener = submitJob(job, false);
200 tileServer.verify(0, getRequestedFor(anyUrl()));
201 assertArrayEquals("cached entry".getBytes(StandardCharsets.UTF_8), listener.data);
202 }
203
204 /**
205 * that request is made, when object is in cache, but force mode is used
206 * @throws IOException exception
207 */
208 @Test
209 void testRequestMadeWhenEntryInCacheAndForce() throws IOException {
210 ICacheAccess<String, CacheEntry> cache = getCache();
211 long expires = TimeUnit.DAYS.toMillis(1);
212 long testStart = System.currentTimeMillis();
213 cache.put("test",
214 new CacheEntry("cached dummy".getBytes(StandardCharsets.UTF_8)),
215 createEntryAttributes(expires, 200, testStart + expires, "eTag")
216 );
217 createHeadGetStub(urlEqualTo("/test"), expires, testStart, "eTag", "mock entry");
218
219 TestCachedTileLoaderJob job = new TestCachedTileLoaderJob(tileServer.url("/test"), "test");
220 Listener listener = submitJob(job, true);
221 tileServer.verify(1, getRequestedFor(urlEqualTo("/test")));
222 assertArrayEquals("mock entry".getBytes(StandardCharsets.UTF_8), listener.data);
223 }
224
225 /**
226 * Mock returns no cache-control / expires headers
227 * Expire time should be set to DEFAULT_EXPIRE_TIME
228 * @throws IOException exception
229 */
230 @Test
231 void testSettingMinimumExpiryWhenNoExpires() throws IOException {
232 long testStart = System.currentTimeMillis();
233 tileServer.stubFor(get(urlEqualTo("/test")).willReturn(aResponse().withBody("mock entry")));
234
235 TestCachedTileLoaderJob job = new TestCachedTileLoaderJob(tileServer.url("/test"), "test");
236 Listener listener = submitJob(job, false);
237 tileServer.verify(1, getRequestedFor(urlEqualTo("/test")));
238
239 assertTrue(listener.attributes.getExpirationTime() >= testStart + JCSCachedTileLoaderJob.DEFAULT_EXPIRE_TIME,
240 "Cache entry expiration is " + (listener.attributes.getExpirationTime() - testStart) + " which is not larger than " +
241 JCSCachedTileLoaderJob.DEFAULT_EXPIRE_TIME + " (DEFAULT_EXPIRE_TIME)");
242
243 assertTrue(listener.attributes.getExpirationTime() <= System.currentTimeMillis() + JCSCachedTileLoaderJob.DEFAULT_EXPIRE_TIME,
244 "Cache entry expiration is " +
245 (listener.attributes.getExpirationTime() - System.currentTimeMillis()) +
246 " which is not less than " +
247 JCSCachedTileLoaderJob.DEFAULT_EXPIRE_TIME + " (DEFAULT_EXPIRE_TIME)"
248 );
249
250 assertArrayEquals("mock entry".getBytes(StandardCharsets.UTF_8), listener.data);
251 }
252
253 /**
254 * Mock returns expires headers, but Cache-Control
255 * Expire time should be set to max-age
256 * @throws IOException exception
257 */
258 @Test
259 void testSettingExpireByMaxAge() throws IOException {
260 long testStart = System.currentTimeMillis();
261 long expires = TimeUnit.DAYS.toSeconds(1);
262 tileServer.stubFor(get(urlEqualTo("/test"))
263 .willReturn(aResponse()
264 .withHeader("Cache-control", "max-age=" + expires)
265 .withBody("mock entry")
266 )
267 );
268
269 TestCachedTileLoaderJob job = new TestCachedTileLoaderJob(tileServer.url("/test"), "test");
270 Listener listener = submitJob(job, false);
271 tileServer.verify(1, getRequestedFor(urlEqualTo("/test")));
272
273 assertTrue(listener.attributes.getExpirationTime() >= testStart + TimeUnit.SECONDS.toMillis(expires),
274 "Cache entry expiration is " + (listener.attributes.getExpirationTime() - testStart) + " which is not larger than " +
275 TimeUnit.SECONDS.toMillis(expires) + " (max-age)");
276
277 assertTrue(
278 listener.attributes.getExpirationTime() <= System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(expires),
279 "Cache entry expiration is " +
280 (listener.attributes.getExpirationTime() - System.currentTimeMillis()) +
281 " which is not less than " +
282 TimeUnit.SECONDS.toMillis(expires) + " (max-age)"
283 );
284
285 assertArrayEquals("mock entry".getBytes(StandardCharsets.UTF_8), listener.data);
286 }
287
288 /**
289 * mock returns expiration: JCSCachedTileLoaderJob.DEFAULT_EXPIRE_TIME / 10
290 * minimum expire time: JCSCachedTileLoaderJob.DEFAULT_EXPIRE_TIME / 2
291 * @throws IOException exception
292 */
293 @Test
294 void testSettingMinimumExpiryByMinimumExpiryTimeLessThanDefault() throws IOException {
295 long testStart = System.currentTimeMillis();
296 int minimumExpiryTimeSeconds = (int) (JCSCachedTileLoaderJob.DEFAULT_EXPIRE_TIME / 2);
297
298 createHeadGetStub(urlEqualTo("/test"), (JCSCachedTileLoaderJob.DEFAULT_EXPIRE_TIME / 10), testStart, "eTag", "mock entry");
299
300 TestCachedTileLoaderJob job = new TestCachedTileLoaderJob(tileServer.url("/test"), "test", minimumExpiryTimeSeconds);
301 Listener listener = submitJob(job, false);
302 tileServer.verify(1, getRequestedFor(urlEqualTo("/test")));
303 assertArrayEquals("mock entry".getBytes(StandardCharsets.UTF_8), listener.data);
304
305
306 assertTrue(
307 listener.attributes.getExpirationTime() >= testStart + TimeUnit.SECONDS.toMillis(minimumExpiryTimeSeconds),
308 "Cache entry expiration is " + (listener.attributes.getExpirationTime() - testStart) + " which is not larger than " +
309 TimeUnit.SECONDS.toMillis(minimumExpiryTimeSeconds) + " (minimumExpireTime)");
310
311 assertTrue(
312 listener.attributes.getExpirationTime() <= System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(minimumExpiryTimeSeconds),
313 "Cache entry expiration is " +
314 (listener.attributes.getExpirationTime() - System.currentTimeMillis()) +
315 " which is not less than " +
316 TimeUnit.SECONDS.toMillis(minimumExpiryTimeSeconds) + " (minimumExpireTime)"
317 );
318 }
319
320 /**
321 * mock returns expiration: JCSCachedTileLoaderJob.DEFAULT_EXPIRE_TIME / 10
322 * minimum expire time: JCSCachedTileLoaderJob.DEFAULT_EXPIRE_TIME * 2
323 * @throws IOException exception
324 */
325
326 @Test
327 void testSettingMinimumExpiryByMinimumExpiryTimeGreaterThanDefault() throws IOException {
328 long testStart = System.currentTimeMillis();
329 int minimumExpiryTimeSeconds = (int) (JCSCachedTileLoaderJob.DEFAULT_EXPIRE_TIME * 2);
330
331 createHeadGetStub(urlEqualTo("/test"), (JCSCachedTileLoaderJob.DEFAULT_EXPIRE_TIME / 10), testStart, "eTag", "mock entry");
332
333 TestCachedTileLoaderJob job = new TestCachedTileLoaderJob(tileServer.url("/test"), "test", minimumExpiryTimeSeconds);
334 Listener listener = submitJob(job, false);
335 tileServer.verify(1, getRequestedFor(urlEqualTo("/test")));
336 assertArrayEquals("mock entry".getBytes(StandardCharsets.UTF_8), listener.data);
337
338
339 assertTrue(
340 listener.attributes.getExpirationTime() >= testStart + TimeUnit.SECONDS.toMillis(minimumExpiryTimeSeconds),
341 "Cache entry expiration is " + (listener.attributes.getExpirationTime() - testStart) + " which is not larger than " +
342 TimeUnit.SECONDS.toMillis(minimumExpiryTimeSeconds) + " (minimumExpireTime)");
343
344 assertTrue(
345 listener.attributes.getExpirationTime() <= System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(minimumExpiryTimeSeconds),
346 "Cache entry expiration is " +
347 (listener.attributes.getExpirationTime() - System.currentTimeMillis()) +
348 " which is not less than " +
349 TimeUnit.SECONDS.toMillis(minimumExpiryTimeSeconds) + " (minimumExpireTime)"
350 );
351 }
352
353 /**
354 * Check if Cache-Control takes precedence over max-age
355 * Expires is lower - JCSCachedTileLoaderJob.DEFAULT_EXPIRE_TIME / 10
356 * Cache control : JCSCachedTileLoaderJob.DEFAULT_EXPIRE_TIME / 2
357 *
358 * Both are smaller than DEFAULT_EXPIRE_TIME, so we can test, that it's not DEFAULT_EXPIRE_TIME that extended
359 * expiration
360 *
361 * @throws IOException exception
362 */
363
364 @Test
365 void testCacheControlVsExpires() throws IOException {
366 long testStart = System.currentTimeMillis();
367 int minimumExpiryTimeSeconds = 0;
368
369 tileServer.stubFor(get(urlEqualTo("/test"))
370 .willReturn(aResponse()
371 .withHeader("Expires", TestUtils.getHTTPDate(testStart + (JCSCachedTileLoaderJob.DEFAULT_EXPIRE_TIME / 10)))
372 .withHeader("Cache-Control", "max-age=" +
373 TimeUnit.MILLISECONDS.toSeconds((JCSCachedTileLoaderJob.DEFAULT_EXPIRE_TIME / 2)))
374 .withBody("mock entry")
375 )
376 );
377 tileServer.stubFor(head(urlEqualTo("/test"))
378 .willReturn(aResponse()
379 .withHeader("Expires", TestUtils.getHTTPDate(testStart + (JCSCachedTileLoaderJob.DEFAULT_EXPIRE_TIME / 10)))
380 .withHeader("Cache-Control", "max-age=" +
381 TimeUnit.MILLISECONDS.toSeconds((JCSCachedTileLoaderJob.DEFAULT_EXPIRE_TIME / 2)))
382 )
383 );
384 TestCachedTileLoaderJob job = new TestCachedTileLoaderJob(tileServer.url("/test"), "test", minimumExpiryTimeSeconds);
385 Listener listener = submitJob(job, false);
386 tileServer.verify(1, getRequestedFor(urlEqualTo("/test")));
387 assertArrayEquals("mock entry".getBytes(StandardCharsets.UTF_8), listener.data);
388
389
390 assertTrue(
391 listener.attributes.getExpirationTime() >= testStart + (JCSCachedTileLoaderJob.DEFAULT_EXPIRE_TIME / 10),
392 "Cache entry expiration is " + (listener.attributes.getExpirationTime() - testStart) + " which is not larger than " +
393 (JCSCachedTileLoaderJob.DEFAULT_EXPIRE_TIME / 10) + " (Expires header)");
394
395 assertTrue(listener.attributes.getExpirationTime() <= System.currentTimeMillis() + (JCSCachedTileLoaderJob.DEFAULT_EXPIRE_TIME / 2),
396 "Cache entry expiration is " +
397 (listener.attributes.getExpirationTime() - System.currentTimeMillis()) +
398 " which is not less than " +
399 (JCSCachedTileLoaderJob.DEFAULT_EXPIRE_TIME / 2) + " (Cache-Control: max-age=)"
400 );
401 }
402
403 /**
404 * Check if Cache-Control s-max-age is honored
405 * mock returns expiration: JCSCachedTileLoaderJob.DEFAULT_EXPIRE_TIME / 10
406 * minimum expire time: JCSCachedTileLoaderJob.DEFAULT_EXPIRE_TIME * 2
407 *
408 * @throws IOException exception
409 */
410 @Test
411 void testMaxAgeVsSMaxAge() throws IOException {
412 long testStart = System.currentTimeMillis();
413 int minimumExpiryTimeSeconds = 0;
414
415 tileServer.stubFor(get(urlEqualTo("/test"))
416 .willReturn(aResponse()
417 .withHeader("Cache-Control", "" +
418 "max-age=" + TimeUnit.MILLISECONDS.toSeconds((JCSCachedTileLoaderJob.DEFAULT_EXPIRE_TIME / 10)) + "," +
419 "s-max-age=" + TimeUnit.MILLISECONDS.toSeconds((JCSCachedTileLoaderJob.DEFAULT_EXPIRE_TIME / 2))
420 )
421 .withBody("mock entry")
422 )
423 );
424 tileServer.stubFor(head(urlEqualTo("/test"))
425 .willReturn(aResponse()
426 .withHeader("Cache-Control", "" +
427 "max-age=" + TimeUnit.MILLISECONDS.toSeconds((JCSCachedTileLoaderJob.DEFAULT_EXPIRE_TIME / 10)) + "," +
428 "s-max-age=" + TimeUnit.MILLISECONDS.toSeconds((JCSCachedTileLoaderJob.DEFAULT_EXPIRE_TIME / 2))
429 )
430 ));
431 TestCachedTileLoaderJob job = new TestCachedTileLoaderJob(tileServer.url("/test"), "test", minimumExpiryTimeSeconds);
432 Listener listener = submitJob(job, false);
433 tileServer.verify(1, getRequestedFor(urlEqualTo("/test")));
434 assertArrayEquals("mock entry".getBytes(StandardCharsets.UTF_8), listener.data);
435
436 assertTrue(
437 listener.attributes.getExpirationTime() >= testStart + (JCSCachedTileLoaderJob.DEFAULT_EXPIRE_TIME / 10),
438 "Cache entry expiration is " + (listener.attributes.getExpirationTime() - testStart) + " which is not larger than " +
439 (JCSCachedTileLoaderJob.DEFAULT_EXPIRE_TIME / 10) + " (Cache-Control: max-age)");
440
441 assertTrue(listener.attributes.getExpirationTime() <= System.currentTimeMillis() + (JCSCachedTileLoaderJob.DEFAULT_EXPIRE_TIME / 2),
442 "Cache entry expiration is " +
443 (listener.attributes.getExpirationTime() - System.currentTimeMillis()) +
444 " which is not less than " +
445 (JCSCachedTileLoaderJob.DEFAULT_EXPIRE_TIME / 2) + " (Cache-Control: s-max-age)"
446 );
447 }
448
449 /**
450 * Check if verifying cache entries using HEAD requests work properly
451 * @throws IOException exception
452 */
453 @Test
454 void testCheckUsingHead() throws IOException {
455 ICacheAccess<String, CacheEntry> cache = getCache();
456 long expires = TimeUnit.DAYS.toMillis(1);
457 long testStart = System.currentTimeMillis();
458 cache.put("test",
459 new CacheEntry("cached dummy".getBytes(StandardCharsets.UTF_8)),
460 createEntryAttributes(-1 * expires, 200, testStart, "eTag--gzip") // Jetty adds --gzip to etags when compressing output
461 );
462
463 tileServer.stubFor(get(urlEqualTo("/test"))
464 .willReturn(aResponse()
465 .withHeader("Expires", TestUtils.getHTTPDate(testStart + expires))
466 .withHeader("Last-Modified", Long.toString(testStart))
467 .withHeader("ETag", "eTag") // Jetty adds "--gzip" suffix for compressed content
468 .withBody("mock entry")
469 )
470 );
471 tileServer.stubFor(head(urlEqualTo("/test"))
472 .willReturn(aResponse()
473 .withHeader("Expires", TestUtils.getHTTPDate(testStart + expires))
474 .withHeader("Last-Modified", Long.toString(testStart))
475 .withHeader("ETag", "eTag--gzip") // but doesn't add to uncompressed
476 )
477 );
478
479 TestCachedTileLoaderJob job = new TestCachedTileLoaderJob(tileServer.url("/test"), "test");
480 Listener listener = submitJob(job, false); // cache entry is expired, no need to force refetch
481 tileServer.verify(1, getRequestedFor(urlEqualTo("/test")));
482 assertArrayEquals("mock entry".getBytes(StandardCharsets.UTF_8), listener.data);
483
484 // cache entry should be retrieved from cache
485 listener = submitJob(job, false);
486 tileServer.verify(1, getRequestedFor(urlEqualTo("/test")));
487 assertArrayEquals("mock entry".getBytes(StandardCharsets.UTF_8), listener.data);
488
489 // invalidate entry in cache
490 ICacheElement<String, CacheEntry> cacheEntry = cache.getCacheElement("test");
491 CacheEntryAttributes attributes = (CacheEntryAttributes) cacheEntry.getElementAttributes();
492 attributes.setExpirationTime(testStart - TimeUnit.DAYS.toMillis(1));
493 cache.put("test", cacheEntry.getVal(), attributes);
494
495 // because cache entry is invalid - HEAD request shall be made
496 tileServer.verify(0, headRequestedFor(urlEqualTo("/test"))); // no head requests were made until now
497 listener = submitJob(job, false);
498 tileServer.verify(1, headRequestedFor(urlEqualTo("/test"))); // verify head requests were made
499 tileServer.verify(1, getRequestedFor(urlEqualTo("/test"))); // verify no more get requests were made
500 assertArrayEquals("mock entry".getBytes(StandardCharsets.UTF_8), listener.data);
501 assertTrue(listener.attributes.getExpirationTime() >= testStart + expires);
502
503 // cache entry should be retrieved from cache
504 listener = submitJob(job, false); // cache entry is expired, no need to force refetch
505 tileServer.verify(1, getRequestedFor(urlEqualTo("/test")));
506 tileServer.verify(1, getRequestedFor(urlEqualTo("/test")));
507 assertArrayEquals("mock entry".getBytes(StandardCharsets.UTF_8), listener.data);
508 }
509
510 /**
511 * Check if server returns 304 - it will update cache attributes and not ask again for it
512 * @throws IOException exception
513 */
514 @Test
515 void testCheckUsing304() throws IOException {
516 ICacheAccess<String, CacheEntry> cache = getCache();
517 long expires = TimeUnit.DAYS.toMillis(1);
518 long testStart = System.currentTimeMillis();
519 cache.put("test",
520 new CacheEntry("cached dummy".getBytes(StandardCharsets.UTF_8)),
521 createEntryAttributes(-1 * expires, 200, testStart, "eTag")
522 );
523
524 tileServer.stubFor(get(urlEqualTo("/test"))
525 .willReturn(status(304)
526 .withHeader("Expires", TestUtils.getHTTPDate(testStart + expires))
527 .withHeader("Last-Modified", Long.toString(testStart))
528 .withHeader("ETag", "eTag")
529 )
530 );
531
532 TestCachedTileLoaderJob job = new TestCachedTileLoaderJob(tileServer.url("/test"), "test");
533 Listener listener = submitJob(job, false);
534 tileServer.verify(1, getRequestedFor(urlEqualTo("/test")));
535 assertArrayEquals("cached dummy".getBytes(StandardCharsets.UTF_8), listener.data);
536 assertTrue(testStart + expires <= listener.attributes.getExpirationTime());
537 submitJob(job, false);
538 tileServer.verify(1, getRequestedFor(urlEqualTo("/test"))); // no more requests were made
539 }
540
541 private void createHeadGetStub(UrlPattern url, long expires, long lastModified, String eTag, String body) {
542 tileServer.stubFor(get(url)
543 .willReturn(aResponse()
544 .withHeader("Expires", TestUtils.getHTTPDate(lastModified + expires))
545 .withHeader("Last-Modified", Long.toString(lastModified))
546 .withHeader("ETag", eTag)
547 .withBody(body)
548 )
549 );
550 tileServer.stubFor(head(url)
551 .willReturn(aResponse()
552 .withHeader("Expires", TestUtils.getHTTPDate(lastModified + expires))
553 .withHeader("Last-Modified", Long.toString(lastModified))
554 .withHeader("ETag", eTag)
555 )
556 );
557 }
558
559 private CacheEntryAttributes createEntryAttributes(long expirationTime, int responseCode, long lastModification, String eTag) {
560 CacheEntryAttributes entryAttributes = new CacheEntryAttributes();
561 entryAttributes.setExpirationTime(lastModification + expirationTime);
562 entryAttributes.setResponseCode(responseCode);
563 entryAttributes.setLastModification(lastModification);
564 entryAttributes.setEtag(eTag);
565 return entryAttributes;
566 }
567
568 private TestCachedTileLoaderJob getStatusLoaderJob(int responseCode) {
569 return new TestCachedTileLoaderJob(tileServer.url("/httpstat/" + responseCode), "key_" + responseCode);
570 }
571
572 private static ICacheAccess<String, CacheEntry> getCache() {
573 return JCSCacheManager.getCache("test");
574 }
575}
Note: See TracBrowser for help on using the repository browser.