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.http.impl.client.cache.memcached;
28
29 import static org.mockito.Mockito.doThrow;
30 import static org.mockito.Mockito.mock;
31 import static org.mockito.Mockito.times;
32 import static org.mockito.Mockito.verify;
33 import static org.mockito.Mockito.verifyNoMoreInteractions;
34 import static org.mockito.Mockito.when;
35
36 import java.io.IOException;
37 import java.io.UnsupportedEncodingException;
38
39 import junit.framework.TestCase;
40 import net.spy.memcached.CASResponse;
41 import net.spy.memcached.CASValue;
42 import net.spy.memcached.MemcachedClientIF;
43 import net.spy.memcached.OperationTimeoutException;
44
45 import org.apache.http.client.cache.HttpCacheEntry;
46 import org.apache.http.client.cache.HttpCacheUpdateCallback;
47 import org.apache.http.client.cache.HttpCacheUpdateException;
48 import org.apache.http.impl.client.cache.CacheConfig;
49 import org.apache.http.impl.client.cache.HttpTestUtils;
50 import org.junit.Before;
51 import org.junit.Test;
52
53 public class TestMemcachedHttpCacheStorage extends TestCase {
54 private MemcachedHttpCacheStorage impl;
55 private MemcachedClientIF mockMemcachedClient;
56 private KeyHashingScheme mockKeyHashingScheme;
57 private MemcachedCacheEntryFactory mockMemcachedCacheEntryFactory;
58 private MemcachedCacheEntry mockMemcachedCacheEntry;
59 private MemcachedCacheEntry mockMemcachedCacheEntry2;
60 private MemcachedCacheEntry mockMemcachedCacheEntry3;
61 private MemcachedCacheEntry mockMemcachedCacheEntry4;
62
63 @Override
64 @Before
65 public void setUp() throws Exception {
66 mockMemcachedClient = mock(MemcachedClientIF.class);
67 mockKeyHashingScheme = mock(KeyHashingScheme.class);
68 mockMemcachedCacheEntryFactory = mock(MemcachedCacheEntryFactory.class);
69 mockMemcachedCacheEntry = mock(MemcachedCacheEntry.class);
70 mockMemcachedCacheEntry2 = mock(MemcachedCacheEntry.class);
71 mockMemcachedCacheEntry3 = mock(MemcachedCacheEntry.class);
72 mockMemcachedCacheEntry4 = mock(MemcachedCacheEntry.class);
73 final CacheConfig config = CacheConfig.custom().setMaxUpdateRetries(1).build();
74 impl = new MemcachedHttpCacheStorage(mockMemcachedClient, config,
75 mockMemcachedCacheEntryFactory, mockKeyHashingScheme);
76 }
77
78 @Test
79 public void testSuccessfulCachePut() throws IOException {
80 final String url = "foo";
81 final String key = "key";
82 final HttpCacheEntry value = HttpTestUtils.makeCacheEntry();
83 final byte[] serialized = HttpTestUtils.getRandomBytes(128);
84
85 when(mockMemcachedCacheEntryFactory.getMemcachedCacheEntry(url, value))
86 .thenReturn(mockMemcachedCacheEntry);
87 when(mockMemcachedCacheEntry.toByteArray())
88 .thenReturn(serialized);
89 when(mockKeyHashingScheme.hash(url))
90 .thenReturn(key);
91 when(mockMemcachedClient.set(key, 0, serialized))
92 .thenReturn(null);
93
94 impl.putEntry(url, value);
95 verify(mockMemcachedCacheEntryFactory).getMemcachedCacheEntry(url, value);
96 verify(mockMemcachedCacheEntry).toByteArray();
97 verify(mockKeyHashingScheme).hash(url);
98 verify(mockMemcachedClient).set(key, 0, serialized);
99 }
100
101 @Test
102 public void testCachePutFailsSilentlyWhenWeCannotHashAKey() throws IOException {
103 final String url = "foo";
104 final HttpCacheEntry value = HttpTestUtils.makeCacheEntry();
105 final byte[] serialized = HttpTestUtils.getRandomBytes(128);
106
107 when(mockMemcachedCacheEntryFactory.getMemcachedCacheEntry(url, value))
108 .thenReturn(mockMemcachedCacheEntry);
109 when(mockMemcachedCacheEntry.toByteArray())
110 .thenReturn(serialized);
111 when(mockKeyHashingScheme.hash(url))
112 .thenThrow(new MemcachedKeyHashingException(new Exception()));
113
114 impl.putEntry(url, value);
115
116 verify(mockMemcachedCacheEntryFactory).getMemcachedCacheEntry(url, value);
117 verify(mockMemcachedCacheEntry).toByteArray();
118 verify(mockKeyHashingScheme).hash(url);
119 }
120
121 public void testThrowsIOExceptionWhenMemcachedPutTimesOut() {
122 final String url = "foo";
123 final String key = "key";
124 final HttpCacheEntry value = HttpTestUtils.makeCacheEntry();
125 final byte[] serialized = HttpTestUtils.getRandomBytes(128);
126
127 when(mockMemcachedCacheEntryFactory.getMemcachedCacheEntry(url, value))
128 .thenReturn(mockMemcachedCacheEntry);
129 when(mockMemcachedCacheEntry.toByteArray())
130 .thenReturn(serialized);
131 when(mockKeyHashingScheme.hash(url))
132 .thenReturn(key);
133 when(mockMemcachedClient.set(key, 0, serialized))
134 .thenThrow(new OperationTimeoutException("timed out"));
135
136 try {
137 impl.putEntry(url, value);
138 fail("should have thrown exception");
139 } catch (final IOException expected) {
140 }
141
142 verify(mockMemcachedCacheEntryFactory).getMemcachedCacheEntry(url, value);
143 verify(mockMemcachedCacheEntry).toByteArray();
144 verify(mockKeyHashingScheme).hash(url);
145 verify(mockMemcachedClient).set(key, 0, serialized);
146 }
147
148 @Test
149 public void testCachePutThrowsIOExceptionIfCannotSerializeEntry() {
150 final String url = "foo";
151 final String key = "key";
152 final HttpCacheEntry value = HttpTestUtils.makeCacheEntry();
153
154 when(mockMemcachedCacheEntryFactory.getMemcachedCacheEntry(url, value))
155 .thenReturn(mockMemcachedCacheEntry);
156 when(mockMemcachedCacheEntry.toByteArray())
157 .thenThrow(new MemcachedSerializationException(new Exception()));
158
159 try {
160 impl.putEntry(url, value);
161 fail("should have thrown exception");
162 } catch (final IOException expected) {
163
164 }
165
166 verify(mockMemcachedCacheEntryFactory).getMemcachedCacheEntry(url, value);
167 verify(mockMemcachedCacheEntry).toByteArray();
168 }
169
170 @Test
171 public void testSuccessfulCacheGet() throws UnsupportedEncodingException,
172 IOException {
173 final String url = "foo";
174 final String key = "key";
175 final byte[] serialized = HttpTestUtils.getRandomBytes(128);
176 final HttpCacheEntry cacheEntry = HttpTestUtils.makeCacheEntry();
177
178 when(mockKeyHashingScheme.hash(url)).thenReturn(key);
179 when(mockMemcachedClient.get(key)).thenReturn(serialized);
180 when(mockMemcachedCacheEntryFactory.getUnsetCacheEntry())
181 .thenReturn(mockMemcachedCacheEntry);
182 when(mockMemcachedCacheEntry.getStorageKey()).thenReturn(url);
183 when(mockMemcachedCacheEntry.getHttpCacheEntry()).thenReturn(cacheEntry);
184
185 final HttpCacheEntry resultingEntry = impl.getEntry(url);
186
187 verify(mockKeyHashingScheme).hash(url);
188 verify(mockMemcachedClient).get(key);
189 verify(mockMemcachedCacheEntryFactory).getUnsetCacheEntry();
190 verify(mockMemcachedCacheEntry).set(serialized);
191 verify(mockMemcachedCacheEntry).getStorageKey();
192 verify(mockMemcachedCacheEntry).getHttpCacheEntry();
193
194 assertSame(cacheEntry, resultingEntry);
195 }
196
197 @Test
198 public void testTreatsNoneByteArrayFromMemcachedAsCacheMiss() throws UnsupportedEncodingException,
199 IOException {
200 final String url = "foo";
201 final String key = "key";
202
203 when(mockKeyHashingScheme.hash(url)).thenReturn(key);
204 when(mockMemcachedClient.get(key)).thenReturn(new Object());
205
206 final HttpCacheEntry resultingEntry = impl.getEntry(url);
207
208 verify(mockKeyHashingScheme).hash(url);
209 verify(mockMemcachedClient).get(key);
210
211 assertNull(resultingEntry);
212 }
213
214 @Test
215 public void testTreatsNullFromMemcachedAsCacheMiss() throws UnsupportedEncodingException,
216 IOException {
217 final String url = "foo";
218 final String key = "key";
219
220 when(mockKeyHashingScheme.hash(url)).thenReturn(key);
221 when(mockMemcachedClient.get(key)).thenReturn(null);
222
223 final HttpCacheEntry resultingEntry = impl.getEntry(url);
224
225 verify(mockKeyHashingScheme).hash(url);
226 verify(mockMemcachedClient).get(key);
227
228 assertNull(resultingEntry);
229 }
230
231 @Test
232 public void testTreatsAsCacheMissIfCannotReconstituteEntry() throws UnsupportedEncodingException,
233 IOException {
234 final String url = "foo";
235 final String key = "key";
236 final byte[] serialized = HttpTestUtils.getRandomBytes(128);
237
238 when(mockKeyHashingScheme.hash(url)).thenReturn(key);
239 when(mockMemcachedClient.get(key)).thenReturn(serialized);
240 when(mockMemcachedCacheEntryFactory.getUnsetCacheEntry())
241 .thenReturn(mockMemcachedCacheEntry);
242 doThrow(new MemcachedSerializationException(new Exception())).when(mockMemcachedCacheEntry).set(serialized);
243
244 assertNull(impl.getEntry(url));
245
246 verify(mockKeyHashingScheme).hash(url);
247 verify(mockMemcachedClient).get(key);
248 verify(mockMemcachedCacheEntryFactory).getUnsetCacheEntry();
249 verify(mockMemcachedCacheEntry).set(serialized);
250 }
251
252 @Test
253 public void testTreatsAsCacheMissIfCantHashStorageKey() throws UnsupportedEncodingException,
254 IOException {
255 final String url = "foo";
256
257 when(mockKeyHashingScheme.hash(url)).thenThrow(new MemcachedKeyHashingException(new Exception()));
258
259 assertNull(impl.getEntry(url));
260 verify(mockKeyHashingScheme).hash(url);
261 }
262
263 @Test
264 public void testThrowsIOExceptionIfMemcachedTimesOutOnGet() {
265 final String url = "foo";
266 final String key = "key";
267 when(mockKeyHashingScheme.hash(url)).thenReturn(key);
268 when(mockMemcachedClient.get(key))
269 .thenThrow(new OperationTimeoutException(""));
270
271 try {
272 impl.getEntry(url);
273 fail("should have thrown exception");
274 } catch (final IOException expected) {
275 }
276 verify(mockKeyHashingScheme).hash(url);
277 verify(mockMemcachedClient).get(key);
278 }
279
280 @Test
281 public void testCacheRemove() throws IOException {
282 final String url = "foo";
283 final String key = "key";
284 when(mockKeyHashingScheme.hash(url)).thenReturn(key);
285 when(mockMemcachedClient.delete(key)).thenReturn(null);
286
287 impl.removeEntry(url);
288
289 verify(mockKeyHashingScheme).hash(url);
290 verify(mockMemcachedClient).delete(key);
291 }
292
293 @Test
294 public void testCacheRemoveHandlesKeyHashingFailure() throws IOException {
295 final String url = "foo";
296 when(mockKeyHashingScheme.hash(url)).thenReturn(null);
297 impl.removeEntry(url);
298 verify(mockKeyHashingScheme).hash(url);
299 }
300
301 @Test
302 public void testCacheRemoveThrowsIOExceptionOnMemcachedTimeout() {
303 final String url = "foo";
304 final String key = "key";
305 when(mockKeyHashingScheme.hash(url)).thenReturn(key);
306 when(mockMemcachedClient.delete(key))
307 .thenThrow(new OperationTimeoutException(""));
308
309 try {
310 impl.removeEntry(url);
311 fail("should have thrown exception");
312 } catch (final IOException expected) {
313 }
314
315 verify(mockKeyHashingScheme).hash(url);
316 verify(mockMemcachedClient).delete(key);
317 }
318
319 @Test
320 public void testCacheUpdateCanUpdateNullEntry() throws IOException,
321 HttpCacheUpdateException {
322 final String url = "foo";
323 final String key = "key";
324 final HttpCacheEntry updatedValue = HttpTestUtils.makeCacheEntry();
325 final byte[] serialized = HttpTestUtils.getRandomBytes(128);
326
327 final HttpCacheUpdateCallback callback = new HttpCacheUpdateCallback() {
328 @Override
329 public HttpCacheEntry update(final HttpCacheEntry old) {
330 assertNull(old);
331 return updatedValue;
332 }
333 };
334
335
336 when(mockKeyHashingScheme.hash(url)).thenReturn(key);
337 when(mockMemcachedClient.gets(key)).thenReturn(null);
338 when(mockMemcachedCacheEntryFactory.getMemcachedCacheEntry(url, updatedValue))
339 .thenReturn(mockMemcachedCacheEntry);
340 when(mockMemcachedCacheEntry.toByteArray()).thenReturn(serialized);
341 when(
342 mockMemcachedClient.set(key, 0,
343 serialized)).thenReturn(null);
344
345 impl.updateEntry(url, callback);
346
347 verify(mockKeyHashingScheme, times(2)).hash(url);
348 verify(mockMemcachedClient).gets(key);
349 verify(mockMemcachedCacheEntryFactory).getMemcachedCacheEntry(url, updatedValue);
350 verify(mockMemcachedCacheEntry).toByteArray();
351 verify(mockMemcachedClient).set(key, 0, serialized);
352 }
353
354 @Test
355 public void testCacheUpdateOverwritesNonMatchingHashCollision() throws IOException,
356 HttpCacheUpdateException {
357 final String url = "foo";
358 final String key = "key";
359 final HttpCacheEntry updatedValue = HttpTestUtils.makeCacheEntry();
360 final byte[] oldBytes = HttpTestUtils.getRandomBytes(128);
361 final CASValue<Object> casValue = new CASValue<Object>(-1, oldBytes);
362 final byte[] newBytes = HttpTestUtils.getRandomBytes(128);
363
364 final HttpCacheUpdateCallback callback = new HttpCacheUpdateCallback() {
365 @Override
366 public HttpCacheEntry update(final HttpCacheEntry old) {
367 assertNull(old);
368 return updatedValue;
369 }
370 };
371
372
373 when(mockKeyHashingScheme.hash(url)).thenReturn(key);
374 when(mockMemcachedClient.gets(key)).thenReturn(casValue);
375 when(mockMemcachedCacheEntryFactory.getUnsetCacheEntry())
376 .thenReturn(mockMemcachedCacheEntry);
377 when(mockMemcachedCacheEntry.getStorageKey()).thenReturn("not" + url);
378
379 when(mockMemcachedCacheEntryFactory.getMemcachedCacheEntry(url, updatedValue))
380 .thenReturn(mockMemcachedCacheEntry2);
381 when(mockMemcachedCacheEntry2.toByteArray()).thenReturn(newBytes);
382 when(
383 mockMemcachedClient.set(key, 0,
384 newBytes)).thenReturn(null);
385
386 impl.updateEntry(url, callback);
387
388 verify(mockKeyHashingScheme, times(2)).hash(url);
389 verify(mockMemcachedClient).gets(key);
390 verify(mockMemcachedCacheEntryFactory).getUnsetCacheEntry();
391 verify(mockMemcachedCacheEntry).getStorageKey();
392 verify(mockMemcachedCacheEntryFactory).getMemcachedCacheEntry(url, updatedValue);
393 verify(mockMemcachedCacheEntry2).toByteArray();
394 verify(mockMemcachedClient).set(key, 0, newBytes);
395 }
396
397 @Test
398 public void testCacheUpdateCanUpdateExistingEntry() throws IOException,
399 HttpCacheUpdateException {
400 final String url = "foo";
401 final String key = "key";
402 final HttpCacheEntry existingValue = HttpTestUtils.makeCacheEntry();
403 final HttpCacheEntry updatedValue = HttpTestUtils.makeCacheEntry();
404 final byte[] oldBytes = HttpTestUtils.getRandomBytes(128);
405 final CASValue<Object> casValue = new CASValue<Object>(1, oldBytes);
406 final byte[] newBytes = HttpTestUtils.getRandomBytes(128);
407
408
409 final HttpCacheUpdateCallback callback = new HttpCacheUpdateCallback() {
410 @Override
411 public HttpCacheEntry update(final HttpCacheEntry old) {
412 assertSame(existingValue, old);
413 return updatedValue;
414 }
415 };
416
417
418 when(mockKeyHashingScheme.hash(url)).thenReturn(key);
419 when(mockMemcachedClient.gets(key)).thenReturn(casValue);
420 when(mockMemcachedCacheEntryFactory.getUnsetCacheEntry())
421 .thenReturn(mockMemcachedCacheEntry);
422 when(mockMemcachedCacheEntry.getStorageKey()).thenReturn(url);
423 when(mockMemcachedCacheEntry.getHttpCacheEntry()).thenReturn(existingValue);
424
425 when(mockMemcachedCacheEntryFactory.getMemcachedCacheEntry(url, updatedValue))
426 .thenReturn(mockMemcachedCacheEntry2);
427 when(mockMemcachedCacheEntry2.toByteArray()).thenReturn(newBytes);
428
429 when(
430 mockMemcachedClient.cas(key, casValue.getCas(),
431 newBytes)).thenReturn(CASResponse.OK);
432
433 impl.updateEntry(url, callback);
434
435 verify(mockKeyHashingScheme).hash(url);
436 verify(mockMemcachedClient).gets(key);
437 verify(mockMemcachedCacheEntryFactory).getUnsetCacheEntry();
438 verify(mockMemcachedCacheEntry).getStorageKey();
439 verify(mockMemcachedCacheEntry).getHttpCacheEntry();
440 verify(mockMemcachedCacheEntryFactory).getMemcachedCacheEntry(url, updatedValue);
441 verify(mockMemcachedCacheEntry2).toByteArray();
442 verify(mockMemcachedClient).cas(key, casValue.getCas(), newBytes);
443 }
444
445 @Test
446 public void testCacheUpdateThrowsExceptionsIfCASFailsEnoughTimes() throws IOException {
447 final String url = "foo";
448 final String key = "key";
449 final HttpCacheEntry existingValue = HttpTestUtils.makeCacheEntry();
450 final HttpCacheEntry updatedValue = HttpTestUtils.makeCacheEntry();
451 final byte[] oldBytes = HttpTestUtils.getRandomBytes(128);
452 final CASValue<Object> casValue = new CASValue<Object>(1, oldBytes);
453 final byte[] newBytes = HttpTestUtils.getRandomBytes(128);
454
455 final CacheConfig config = CacheConfig.custom().setMaxUpdateRetries(0).build();
456 impl = new MemcachedHttpCacheStorage(mockMemcachedClient, config,
457 mockMemcachedCacheEntryFactory, mockKeyHashingScheme);
458
459 final HttpCacheUpdateCallback callback = new HttpCacheUpdateCallback() {
460 @Override
461 public HttpCacheEntry update(final HttpCacheEntry old) {
462 assertSame(existingValue, old);
463 return updatedValue;
464 }
465 };
466
467
468 when(mockKeyHashingScheme.hash(url)).thenReturn(key);
469 when(mockMemcachedClient.gets(key)).thenReturn(casValue);
470 when(mockMemcachedCacheEntryFactory.getUnsetCacheEntry())
471 .thenReturn(mockMemcachedCacheEntry);
472 when(mockMemcachedCacheEntry.getStorageKey()).thenReturn(url);
473 when(mockMemcachedCacheEntry.getHttpCacheEntry()).thenReturn(existingValue);
474
475 when(mockMemcachedCacheEntryFactory.getMemcachedCacheEntry(url, updatedValue))
476 .thenReturn(mockMemcachedCacheEntry2);
477 when(mockMemcachedCacheEntry2.toByteArray()).thenReturn(newBytes);
478
479 when(
480 mockMemcachedClient.cas(key, casValue.getCas(),
481 newBytes)).thenReturn(CASResponse.EXISTS);
482
483 try {
484 impl.updateEntry(url, callback);
485 fail("should have thrown exception");
486 } catch (final HttpCacheUpdateException expected) {
487 }
488
489 verify(mockKeyHashingScheme).hash(url);
490 verify(mockMemcachedClient).gets(key);
491 verify(mockMemcachedCacheEntryFactory).getUnsetCacheEntry();
492 verify(mockMemcachedCacheEntry).getStorageKey();
493 verify(mockMemcachedCacheEntry).getHttpCacheEntry();
494 verify(mockMemcachedCacheEntryFactory).getMemcachedCacheEntry(url, updatedValue);
495 verify(mockMemcachedCacheEntry2).toByteArray();
496 verify(mockMemcachedClient).cas(key, casValue.getCas(), newBytes);
497 }
498
499
500 @Test
501 public void testCacheUpdateCanUpdateExistingEntryWithRetry() throws IOException,
502 HttpCacheUpdateException {
503 final String url = "foo";
504 final String key = "key";
505 final HttpCacheEntry existingValue = HttpTestUtils.makeCacheEntry();
506 final HttpCacheEntry existingValue2 = HttpTestUtils.makeCacheEntry();
507 final HttpCacheEntry updatedValue = HttpTestUtils.makeCacheEntry();
508 final HttpCacheEntry updatedValue2 = HttpTestUtils.makeCacheEntry();
509 final byte[] oldBytes2 = HttpTestUtils.getRandomBytes(128);
510 final CASValue<Object> casValue2 = new CASValue<Object>(2, oldBytes2);
511 final byte[] newBytes2 = HttpTestUtils.getRandomBytes(128);
512
513 final HttpCacheUpdateCallback callback = new HttpCacheUpdateCallback() {
514 @Override
515 public HttpCacheEntry update(final HttpCacheEntry old) {
516 if (old == existingValue) {
517 return updatedValue;
518 }
519 assertSame(existingValue2, old);
520 return updatedValue2;
521 }
522 };
523
524 when(mockKeyHashingScheme.hash(url)).thenReturn(key);
525
526
527 when(mockMemcachedClient.gets(key)).thenReturn(casValue2);
528 when(mockMemcachedCacheEntryFactory.getUnsetCacheEntry())
529 .thenReturn(mockMemcachedCacheEntry3);
530 when(mockMemcachedCacheEntry3.getStorageKey()).thenReturn(url);
531 when(mockMemcachedCacheEntry3.getHttpCacheEntry()).thenReturn(existingValue2);
532
533 when(mockMemcachedCacheEntryFactory.getMemcachedCacheEntry(url, updatedValue2))
534 .thenReturn(mockMemcachedCacheEntry4);
535 when(mockMemcachedCacheEntry4.toByteArray()).thenReturn(newBytes2);
536
537 when(
538 mockMemcachedClient.cas(key, casValue2.getCas(),
539 newBytes2)).thenReturn(CASResponse.OK);
540
541 impl.updateEntry(url, callback);
542
543 verify(mockKeyHashingScheme).hash(url);
544 verify(mockMemcachedClient).gets(key);
545 verify(mockMemcachedCacheEntryFactory).getUnsetCacheEntry();
546
547 verify(mockMemcachedCacheEntry3).set(oldBytes2);
548 verify(mockMemcachedCacheEntry3).getStorageKey();
549 verify(mockMemcachedCacheEntry3).getHttpCacheEntry();
550 verify(mockMemcachedCacheEntryFactory).getMemcachedCacheEntry(url, updatedValue2);
551 verify(mockMemcachedCacheEntry4).toByteArray();
552 verify(mockMemcachedClient).cas(key, casValue2.getCas(), newBytes2);
553
554 verifyNoMoreInteractions(mockMemcachedClient);
555 verifyNoMoreInteractions(mockKeyHashingScheme);
556 verifyNoMoreInteractions(mockMemcachedCacheEntry);
557 verifyNoMoreInteractions(mockMemcachedCacheEntry2);
558 verifyNoMoreInteractions(mockMemcachedCacheEntry3);
559 verifyNoMoreInteractions(mockMemcachedCacheEntry4);
560 verifyNoMoreInteractions(mockMemcachedCacheEntryFactory);
561 }
562
563
564 @Test
565 public void testUpdateThrowsIOExceptionIfMemcachedTimesOut() throws HttpCacheUpdateException {
566 final String url = "foo";
567 final String key = "key";
568 final HttpCacheEntry updatedValue = HttpTestUtils.makeCacheEntry();
569
570 final HttpCacheUpdateCallback callback = new HttpCacheUpdateCallback() {
571 @Override
572 public HttpCacheEntry update(final HttpCacheEntry old) {
573 assertNull(old);
574 return updatedValue;
575 }
576 };
577
578
579 when(mockKeyHashingScheme.hash(url)).thenReturn(key);
580 when(mockMemcachedClient.gets(key))
581 .thenThrow(new OperationTimeoutException(""));
582
583 try {
584 impl.updateEntry(url, callback);
585 fail("should have thrown exception");
586 } catch (final IOException expected) {
587 }
588
589 verify(mockKeyHashingScheme).hash(url);
590 verify(mockMemcachedClient).gets(key);
591 }
592
593
594 @Test(expected=HttpCacheUpdateException.class)
595 public void testThrowsExceptionOnUpdateIfCannotHashStorageKey() throws Exception {
596 final String url = "foo";
597
598 when(mockKeyHashingScheme.hash(url))
599 .thenThrow(new MemcachedKeyHashingException(new Exception()));
600
601 try {
602 impl.updateEntry(url, null);
603 fail("should have thrown exception");
604 } catch (final HttpCacheUpdateException expected) {
605 }
606
607 verify(mockKeyHashingScheme).hash(url);
608 }
609 }