1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package org.apache.hc.client5.http.impl.cache;
28
29
30 import static org.junit.jupiter.api.Assertions.assertEquals;
31 import static org.junit.jupiter.api.Assertions.assertTrue;
32
33 import java.time.Instant;
34
35 import org.apache.hc.client5.http.cache.HttpCacheEntry;
36 import org.apache.hc.client5.http.utils.DateUtils;
37 import org.apache.hc.core5.http.Header;
38 import org.apache.hc.core5.http.message.BasicHeader;
39 import org.apache.hc.core5.util.TimeValue;
40 import org.junit.jupiter.api.BeforeEach;
41 import org.junit.jupiter.api.Test;
42
43 public class TestCacheValidityPolicy {
44
45 private CacheValidityPolicy impl;
46 private Instant now;
47 private Instant oneSecondAgo;
48 private Instant sixSecondsAgo;
49 private Instant tenSecondsAgo;
50 private Instant elevenSecondsAgo;
51
52 @BeforeEach
53 public void setUp() {
54 impl = new CacheValidityPolicy();
55 now = Instant.now();
56 oneSecondAgo = now.minusSeconds(1);
57 sixSecondsAgo = now.minusSeconds(6);
58 tenSecondsAgo = now.minusSeconds(10);
59 elevenSecondsAgo = now.minusSeconds(11);
60 }
61
62 @Test
63 public void testApparentAgeIsMaxIntIfDateHeaderNotPresent() {
64 final Header[] headers = {
65 new BasicHeader("Server", "MockServer/1.0")
66 };
67 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
68 assertEquals(CacheSupport.MAX_AGE, impl.getApparentAge(entry));
69 }
70
71 @Test
72 public void testApparentAgeIsResponseReceivedTimeLessDateHeader() {
73 final Header[] headers = new Header[] { new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)) };
74
75 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(now, sixSecondsAgo, headers);
76 assertEquals(TimeValue.ofSeconds(4), impl.getApparentAge(entry));
77 }
78
79 @Test
80 public void testNegativeApparentAgeIsBroughtUpToZero() {
81 final Header[] headers = new Header[] { new BasicHeader("Date", DateUtils.formatStandardDate(sixSecondsAgo)) };
82 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(now, tenSecondsAgo, headers);
83 assertEquals(TimeValue.ofSeconds(0), impl.getApparentAge(entry));
84 }
85
86 @Test
87 public void testCorrectedReceivedAgeIsAgeHeaderIfLarger() {
88 final Header[] headers = new Header[] { new BasicHeader("Age", "10"), };
89 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
90 impl = new CacheValidityPolicy() {
91 @Override
92 protected TimeValue getApparentAge(final HttpCacheEntry ent) {
93 return TimeValue.ofSeconds(6);
94 }
95 };
96 assertEquals(TimeValue.ofSeconds(10), impl.getCorrectedAgeValue(entry));
97 }
98
99 @Test
100 public void testGetCorrectedAgeValue() {
101 final Header[] headers = new Header[] { new BasicHeader("Age", "6"), };
102 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
103 assertEquals(TimeValue.ofSeconds(6), impl.getCorrectedAgeValue(entry));
104 }
105
106 @Test
107 public void testResponseDelayIsDifferenceBetweenResponseAndRequestTimes() {
108 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(tenSecondsAgo, sixSecondsAgo);
109 assertEquals(TimeValue.ofSeconds(4), impl.getResponseDelay(entry));
110 }
111
112 @Test
113 public void testCorrectedInitialAgeIsCorrectedReceivedAgePlusResponseDelay() {
114 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
115 impl = new CacheValidityPolicy() {
116 @Override
117 protected TimeValue getCorrectedAgeValue(final HttpCacheEntry ent) {
118 return TimeValue.ofSeconds(7);
119 }
120
121 @Override
122 protected TimeValue getResponseDelay(final HttpCacheEntry ent) {
123 return TimeValue.ofSeconds(13);
124 }
125 };
126 assertEquals(TimeValue.ofSeconds(7), impl.getCorrectedInitialAge(entry));
127 }
128
129 @Test
130 public void testResidentTimeSecondsIsTimeSinceResponseTime() {
131 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(now, sixSecondsAgo);
132 assertEquals(TimeValue.ofSeconds(6), impl.getResidentTime(entry, now));
133 }
134
135 @Test
136 public void testCurrentAgeIsCorrectedInitialAgePlusResidentTime() {
137 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
138 impl = new CacheValidityPolicy() {
139 @Override
140 protected TimeValue getCorrectedInitialAge(final HttpCacheEntry ent) {
141 return TimeValue.ofSeconds(11);
142 }
143 @Override
144 protected TimeValue getResidentTime(final HttpCacheEntry ent, final Instant d) {
145 return TimeValue.ofSeconds(17);
146 }
147 };
148 assertEquals(TimeValue.ofSeconds(28), impl.getCurrentAge(entry, Instant.now()));
149 }
150
151 @Test
152 public void testFreshnessLifetimeIsSMaxAgeIfPresent() {
153 final ResponseCacheControl cacheControl = ResponseCacheControl.builder()
154 .setSharedMaxAge(10)
155 .setMaxAge(5)
156 .build();
157 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
158 assertEquals(TimeValue.ofSeconds(10), impl.getFreshnessLifetime(cacheControl, entry));
159 }
160
161 @Test
162 public void testSMaxAgeIsIgnoredWhenNotShared() {
163 final CacheConfig cacheConfig = CacheConfig.custom()
164 .setSharedCache(false)
165 .build();
166 impl = new CacheValidityPolicy(cacheConfig);
167 final ResponseCacheControl cacheControl = ResponseCacheControl.builder()
168 .setSharedMaxAge(10)
169 .setMaxAge(5)
170 .build();
171 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
172 assertEquals(TimeValue.ofSeconds(5), impl.getFreshnessLifetime(cacheControl, entry));
173 }
174
175 @Test
176 public void testFreshnessLifetimeIsMaxAgeIfPresent() {
177 final ResponseCacheControl cacheControl = ResponseCacheControl.builder()
178 .setMaxAge(10)
179 .build();
180 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
181 assertEquals(TimeValue.ofSeconds(10), impl.getFreshnessLifetime(cacheControl, entry));
182 }
183
184 @Test
185 public void testFreshnessLifetimeUsesSharedMaxAgeInSharedCache() {
186
187 final ResponseCacheControl cacheControl = ResponseCacheControl.builder()
188 .setMaxAge(10)
189 .setSharedMaxAge(20)
190 .build();
191 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
192 assertEquals(TimeValue.ofSeconds(20), impl.getFreshnessLifetime(cacheControl, entry));
193 }
194
195 @Test
196 public void testFreshnessLifetimeUsesMaxAgeWhenSharedMaxAgeNotPresent() {
197
198 final ResponseCacheControl cacheControl = ResponseCacheControl.builder()
199 .setMaxAge(10)
200 .build();
201 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
202 assertEquals(TimeValue.ofSeconds(10), impl.getFreshnessLifetime(cacheControl, entry));
203 }
204
205 @Test
206 public void testFreshnessLifetimeIsMaxAgeEvenIfExpiresIsPresent() {
207 final ResponseCacheControl cacheControl = ResponseCacheControl.builder()
208 .setMaxAge(10)
209 .build();
210 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(
211 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
212 new BasicHeader("Expires", DateUtils.formatStandardDate(sixSecondsAgo)));
213 assertEquals(TimeValue.ofSeconds(10), impl.getFreshnessLifetime(cacheControl, entry));
214 }
215
216 @Test
217 public void testFreshnessLifetimeIsSMaxAgeEvenIfExpiresIsPresent() {
218 final ResponseCacheControl cacheControl = ResponseCacheControl.builder()
219 .setSharedMaxAge(10)
220 .build();
221 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(
222 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
223 new BasicHeader("Expires", DateUtils.formatStandardDate(sixSecondsAgo)));
224 assertEquals(TimeValue.ofSeconds(10), impl.getFreshnessLifetime(cacheControl, entry));
225 }
226
227 @Test
228 public void testFreshnessLifetimeIsFromExpiresHeaderIfNoMaxAge() {
229 final ResponseCacheControl cacheControl = ResponseCacheControl.builder()
230 .build();
231 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(
232 new BasicHeader("Date", DateUtils.formatStandardDate(tenSecondsAgo)),
233 new BasicHeader("Expires", DateUtils.formatStandardDate(sixSecondsAgo)));
234 assertEquals(TimeValue.ofSeconds(4), impl.getFreshnessLifetime(cacheControl, entry));
235 }
236
237 @Test
238 public void testHeuristicFreshnessLifetime() {
239 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(
240 new BasicHeader("Date", DateUtils.formatStandardDate(oneSecondAgo)),
241 new BasicHeader("Last-Modified", DateUtils.formatStandardDate(elevenSecondsAgo)));
242 assertEquals(TimeValue.ofSeconds(1), impl.getHeuristicFreshnessLifetime(entry));
243 }
244
245 @Test
246 public void testHeuristicFreshnessLifetimeDefaultsProperly() {
247 final TimeValue defaultFreshness = TimeValue.ofSeconds(0);
248 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
249 assertEquals(defaultFreshness, impl.getHeuristicFreshnessLifetime(entry));
250 }
251
252 @Test
253 public void testHeuristicFreshnessLifetimeIsNonNegative() {
254 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(
255 new BasicHeader("Date", DateUtils.formatStandardDate(elevenSecondsAgo)),
256 new BasicHeader("Last-Modified", DateUtils.formatStandardDate(oneSecondAgo)));
257 assertTrue(TimeValue.isNonNegative(impl.getHeuristicFreshnessLifetime(entry)));
258 }
259
260 @Test
261 public void testHeuristicFreshnessLifetimeCustomProperly() {
262 final CacheConfig cacheConfig = CacheConfig.custom().setHeuristicDefaultLifetime(TimeValue.ofSeconds(10))
263 .setHeuristicCoefficient(0.5f).build();
264 impl = new CacheValidityPolicy(cacheConfig);
265 final TimeValue defaultFreshness = TimeValue.ofSeconds(10);
266 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry();
267 assertEquals(defaultFreshness, impl.getHeuristicFreshnessLifetime(entry));
268 }
269
270 @Test
271 public void testNegativeAgeHeaderValueReturnsZero() {
272 final Header[] headers = new Header[] { new BasicHeader("Age", "-100") };
273 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
274
275 assertEquals(0, impl.getAgeValue(entry));
276 }
277
278 @Test
279 public void testMalformedAgeHeaderValueReturnsMaxAge() {
280 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(
281 new BasicHeader("Age", "asdf"));
282
283 assertEquals(0, impl.getAgeValue(entry));
284 }
285
286 @Test
287 public void testMalformedAgeHeaderMultipleWellFormedAges() {
288 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(
289 new BasicHeader("Age", "123,456,789"));
290
291 assertEquals(123, impl.getAgeValue(entry));
292 }
293
294 @Test
295 public void testMalformedAgeHeaderMultiplesMalformedAges() {
296 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(
297 new BasicHeader("Age", "123 456 789"));
298
299 assertEquals(0, impl.getAgeValue(entry));
300 }
301
302 @Test
303 public void testMalformedAgeHeaderNegativeAge() {
304 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(
305 new BasicHeader("Age", "-123"));
306
307 assertEquals(0, impl.getAgeValue(entry));
308 }
309
310 @Test
311 public void testMalformedAgeHeaderOverflow() {
312 final String reallyOldAge = "1" + Long.MAX_VALUE;
313 final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(
314 new BasicHeader("Age", reallyOldAge));
315
316 assertEquals(0, impl.getAgeValue(entry));
317 }
318
319 }