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, 6 weeks 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.