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.cache;
28
29 import static org.junit.jupiter.api.Assertions.assertEquals;
30 import static org.junit.jupiter.api.Assertions.assertNotEquals;
31 import static org.junit.jupiter.api.Assertions.assertNotNull;
32 import static org.junit.jupiter.api.Assertions.assertNull;
33 import static org.junit.jupiter.api.Assertions.assertSame;
34 import static org.junit.jupiter.api.Assertions.assertTrue;
35 import static org.junit.jupiter.api.Assertions.fail;
36 import static org.mockito.Mockito.mock;
37
38 import java.time.Instant;
39 import java.time.temporal.ChronoField;
40 import java.util.Date;
41 import java.util.HashMap;
42 import java.util.Map;
43
44 import org.apache.hc.client5.http.utils.DateUtils;
45 import org.apache.hc.core5.http.Header;
46 import org.apache.hc.core5.http.HttpStatus;
47 import org.apache.hc.core5.http.message.BasicHeader;
48 import org.junit.jupiter.api.BeforeEach;
49 import org.junit.jupiter.api.Test;
50
51 public class TestHttpCacheEntry {
52
53 private Instant now;
54 private Instant elevenSecondsAgo;
55 private Instant nineSecondsAgo;
56 private Resource mockResource;
57 private HttpCacheEntry entry;
58
59 @BeforeEach
60 public void setUp() {
61 now = Instant.now();
62 elevenSecondsAgo = now.minusSeconds(11);
63 nineSecondsAgo = now.minusSeconds(9);
64 mockResource = mock(Resource.class);
65 }
66
67 private HttpCacheEntry makeEntry(final Header[] headers) {
68 return new HttpCacheEntry(elevenSecondsAgo, nineSecondsAgo,
69 HttpStatus.SC_OK, headers, mockResource);
70 }
71
72 @Test
73 public void testGetHeadersReturnsCorrectHeaders() {
74 final Header[] headers = { new BasicHeader("foo", "fooValue"),
75 new BasicHeader("bar", "barValue1"),
76 new BasicHeader("bar", "barValue2")
77 };
78 entry = makeEntry(headers);
79 assertEquals(2, entry.getHeaders("bar").length);
80 }
81
82 @Test
83 public void testGetFirstHeaderReturnsCorrectHeader() {
84 final Header[] headers = { new BasicHeader("foo", "fooValue"),
85 new BasicHeader("bar", "barValue1"),
86 new BasicHeader("bar", "barValue2")
87 };
88 entry = makeEntry(headers);
89 assertEquals("barValue1", entry.getFirstHeader("bar").getValue());
90 }
91
92 @Test
93 public void testGetHeadersReturnsEmptyArrayIfNoneMatch() {
94 final Header[] headers = { new BasicHeader("foo", "fooValue"),
95 new BasicHeader("bar", "barValue1"),
96 new BasicHeader("bar", "barValue2")
97 };
98 entry = makeEntry(headers);
99 assertEquals(0, entry.getHeaders("baz").length);
100 }
101
102 @Test
103 public void testGetFirstHeaderReturnsNullIfNoneMatch() {
104 final Header[] headers = { new BasicHeader("foo", "fooValue"),
105 new BasicHeader("bar", "barValue1"),
106 new BasicHeader("bar", "barValue2")
107 };
108 entry = makeEntry(headers);
109 assertNull(entry.getFirstHeader("quux"));
110 }
111
112 @Test
113 public void testCacheEntryWithOneVaryHeaderHasVariants() {
114 final Header[] headers = { new BasicHeader("Vary", "User-Agent") };
115 entry = makeEntry(headers);
116 assertTrue(entry.hasVariants());
117 }
118
119 @Test
120 public void testCacheEntryWithMultipleVaryHeadersHasVariants() {
121 final Header[] headers = { new BasicHeader("Vary", "User-Agent"),
122 new BasicHeader("Vary", "Accept-Encoding")
123 };
124 entry = makeEntry(headers);
125 assertTrue(entry.hasVariants());
126 }
127
128 @Test
129 public void testCacheEntryWithVaryStarHasVariants(){
130 final Header[] headers = { new BasicHeader("Vary", "*") };
131 entry = makeEntry(headers);
132 assertTrue(entry.hasVariants());
133 }
134
135
136 @Test
137 public void testGetMethodReturnsCorrectRequestMethod() {
138 final Header[] headers = { new BasicHeader("foo", "fooValue"),
139 new BasicHeader("bar", "barValue1"),
140 new BasicHeader("bar", "barValue2")
141 };
142 entry = makeEntry(headers);
143 assertEquals(HeaderConstants.GET_METHOD, entry.getRequestMethod());
144 }
145
146
147
148 @SuppressWarnings("unused")
149 @Test
150 public void mustProvideRequestDate() {
151 try {
152 new HttpCacheEntry(null, Instant.now(), HttpStatus.SC_OK, new Header[]{}, mockResource);
153 fail("Should have thrown exception");
154 } catch (final NullPointerException expected) {
155 }
156 }
157
158 @SuppressWarnings("unused")
159 @Test
160 public void mustProvideResponseDate() {
161 try {
162 new HttpCacheEntry(Instant.now(), null, HttpStatus.SC_OK, new Header[]{}, mockResource);
163 fail("Should have thrown exception");
164 } catch (final NullPointerException expected) {
165 }
166 }
167
168 @SuppressWarnings("unused")
169 @Test
170 public void mustProvideResponseHeaders() {
171 try {
172 new HttpCacheEntry(Instant.now(), Instant.now(), HttpStatus.SC_OK, null, mockResource);
173 fail("Should have thrown exception");
174 } catch (final NullPointerException expected) {
175 }
176 }
177
178 @Test
179 public void statusCodeComesFromOriginalStatusLine() {
180 entry = new HttpCacheEntry(Instant.now(), Instant.now(), HttpStatus.SC_OK, new Header[]{}, mockResource);
181 assertEquals(HttpStatus.SC_OK, entry.getStatus());
182 }
183
184 @Test
185 public void canGetOriginalRequestDate() {
186 final Instant requestDate = Instant.now();
187 entry = new HttpCacheEntry(requestDate, Instant.now(), HttpStatus.SC_OK, new Header[]{}, mockResource);
188 assertEquals(requestDate, entry.getRequestInstant());
189 }
190
191 @Test
192 public void canGetOriginalResponseDate() {
193 final Instant responseDate = Instant.now();
194 entry = new HttpCacheEntry(Instant.now(), responseDate, HttpStatus.SC_OK, new Header[]{}, mockResource);
195 assertEquals(responseDate, entry.getResponseInstant());
196 }
197
198 @Test
199 public void canGetOriginalResource() {
200 entry = new HttpCacheEntry(Instant.now(), Instant.now(), HttpStatus.SC_OK, new Header[]{}, mockResource);
201 assertSame(mockResource, entry.getResource());
202 }
203
204 @Test
205 public void canGetOriginalHeaders() {
206 final Header[] headers = {
207 new BasicHeader("Server", "MockServer/1.0"),
208 new BasicHeader("Date", DateUtils.formatStandardDate(now))
209 };
210 entry = new HttpCacheEntry(Instant.now(), Instant.now(), HttpStatus.SC_OK, headers, mockResource);
211 final Header[] result = entry.getHeaders();
212 assertEquals(headers.length, result.length);
213 for(int i=0; i<headers.length; i++) {
214 assertEquals(headers[i], result[i]);
215 }
216 }
217
218 @SuppressWarnings("unused")
219 @Test
220 public void canConstructWithoutVariants() {
221 new HttpCacheEntry(Instant.now(), Instant.now(), HttpStatus.SC_OK, new Header[]{}, mockResource);
222 }
223
224 @SuppressWarnings("unused")
225 @Test
226 public void canProvideVariantMap() {
227 new HttpCacheEntry(Instant.now(), Instant.now(), HttpStatus.SC_OK,
228 new Header[]{}, mockResource,
229 new HashMap<>());
230 }
231
232 @Test
233 public void canRetrieveOriginalVariantMap() {
234 final Map<String,String> variantMap = new HashMap<>();
235 variantMap.put("A","B");
236 variantMap.put("C","D");
237 entry = new HttpCacheEntry(Instant.now(), Instant.now(), HttpStatus.SC_OK,
238 new Header[]{}, mockResource,
239 variantMap);
240 final Map<String,String> result = entry.getVariantMap();
241 assertEquals(2, result.size());
242 assertEquals("B", result.get("A"));
243 assertEquals("D", result.get("C"));
244 }
245
246 @Test
247 public void retrievedVariantMapIsNotModifiable() {
248 final Map<String,String> variantMap = new HashMap<>();
249 variantMap.put("A","B");
250 variantMap.put("C","D");
251 entry = new HttpCacheEntry(Instant.now(), Instant.now(), HttpStatus.SC_OK,
252 new Header[]{}, mockResource,
253 variantMap);
254 final Map<String,String> result = entry.getVariantMap();
255 try {
256 result.remove("A");
257 fail("Should have thrown exception");
258 } catch (final UnsupportedOperationException expected) {
259 }
260 try {
261 result.put("E","F");
262 fail("Should have thrown exception");
263 } catch (final UnsupportedOperationException expected) {
264 }
265 }
266
267 @Test
268 public void canConvertToString() {
269 entry = new HttpCacheEntry(Instant.now(), Instant.now(), HttpStatus.SC_OK,
270 new Header[]{}, mockResource);
271 assertNotNull(entry.toString());
272 assertNotEquals("", entry.toString());
273 }
274
275 @Test
276 public void testMissingDateHeaderIsIgnored() {
277 final Header[] headers = new Header[] {};
278 entry = new HttpCacheEntry(Instant.now(), Instant.now(), HttpStatus.SC_OK,
279 headers, mockResource);
280 assertNull(entry.getDate());
281 }
282
283 @Test
284 public void testMalformedDateHeaderIsIgnored() {
285 final Header[] headers = new Header[] { new BasicHeader("Date", "asdf") };
286 entry = new HttpCacheEntry(Instant.now(), Instant.now(), HttpStatus.SC_OK,
287 headers, mockResource);
288 assertNull(entry.getDate());
289 }
290
291 @Test
292 public void testValidDateHeaderIsParsed() {
293 final Instant date = Instant.now().with(ChronoField.MILLI_OF_SECOND, 0);
294 final Header[] headers = new Header[] { new BasicHeader("Date", DateUtils.formatStandardDate(date)) };
295 entry = new HttpCacheEntry(Instant.now(), Instant.now(), HttpStatus.SC_OK,
296 headers, mockResource);
297 final Date dateHeaderValue = entry.getDate();
298 assertNotNull(dateHeaderValue);
299 assertEquals(DateUtils.toDate(date), dateHeaderValue);
300 }
301
302 }