1 package com.atlassian.cache.ehcache;
2
3 import com.atlassian.cache.CacheLoader;
4 import net.sf.ehcache.Cache;
5 import net.sf.ehcache.CacheManager;
6 import net.sf.ehcache.Element;
7 import net.sf.ehcache.config.CacheConfiguration;
8 import net.sf.ehcache.config.Configuration;
9 import net.sf.ehcache.config.MemoryUnit;
10 import org.junit.After;
11 import org.junit.Before;
12 import org.junit.Test;
13
14 import javax.annotation.Nonnull;
15
16 import java.util.concurrent.CountDownLatch;
17 import java.util.concurrent.ExecutionException;
18 import java.util.concurrent.ExecutorService;
19 import java.util.concurrent.Executors;
20 import java.util.concurrent.Future;
21
22 import static org.junit.Assert.*;
23
24 public class SynchronizedLoadingCacheDecoratorTest {
25
26 private LoadingCache<Object, Object> testedLoadingCache;
27 private SynchronizedLoadingCacheDecorator testedSynchronizedLoadingCacheDecorator;
28 private CountDownLatch loadCountDownLatch;
29 private CountDownLatch testCountDownLatch;
30 private CacheManager cacheManager;
31
32 private ExecutorService executorService = Executors.newCachedThreadPool();
33
34 @Before
35 public void setup() {
36 loadCountDownLatch = new CountDownLatch(1);
37 testCountDownLatch = new CountDownLatch(1);
38
39 cacheManager = new CacheManager(new Configuration().name(SynchronizedLoadingCacheDecorator.class.getName()));
40 cacheManager.addCache(new Cache(new CacheConfiguration().name("tested").maxBytesLocalHeap(10, MemoryUnit.MEGABYTES)));
41 testedSynchronizedLoadingCacheDecorator = new SynchronizedLoadingCacheDecorator(cacheManager.getCache("tested"));
42 testedLoadingCache = new LoadingCache<>(
43 testedSynchronizedLoadingCacheDecorator,
44 new CacheLoader<Object, Object>() {
45 @Nonnull
46 @Override
47 public Object load(@Nonnull final Object key) {
48 testCountDownLatch.countDown();
49 try {
50 loadCountDownLatch.await();
51 } catch (InterruptedException e) {
52 throw new RuntimeException(e);
53 }
54 return key;
55 }
56 }
57 );
58 }
59
60 @After
61 public void destroy() {
62 cacheManager.shutdown();
63 }
64
65 @Test
66 public void shouldReturnProperlyLoadedValue() throws ExecutionException, InterruptedException {
67 assertEquals(0, testedLoadingCache.getKeys().size());
68
69 loadCountDownLatch.countDown();
70 Object key = new Object();
71 Future<Element> future = executorService.submit(() -> testedLoadingCache.get(key));
72
73 Element element = future.get();
74 assertEquals(key, element.getObjectValue());
75 assertEquals(key, element.getObjectKey());
76 assertEquals(1, testedLoadingCache.getKeys().size());
77 }
78
79 @Test
80 public void shouldNotStoreRemovedValueWhileLoading() throws ExecutionException, InterruptedException {
81 assertEquals(0, testedLoadingCache.getKeys().size());
82
83 Object key = new Object();
84 Future<Element> future = executorService.submit(() -> testedLoadingCache.get(key));
85
86 testCountDownLatch.await();
87 testedSynchronizedLoadingCacheDecorator.remove(key);
88 loadCountDownLatch.countDown();
89
90 Element element = future.get();
91 assertEquals(key, element.getObjectValue());
92 assertEquals(key, element.getObjectKey());
93 assertEquals(0, testedLoadingCache.getKeys().size());
94 }
95
96 @Test
97 public void shouldNotStoreAfterRemoveAllWhileLoading() throws ExecutionException, InterruptedException {
98 assertEquals(0, testedLoadingCache.getKeys().size());
99
100 Object key = new Object();
101 Future<Element> future = executorService.submit(() -> testedLoadingCache.get(key));
102
103 testCountDownLatch.await();
104 testedSynchronizedLoadingCacheDecorator.removeAll();
105 loadCountDownLatch.countDown();
106
107 Element element = future.get();
108 assertEquals(key, element.getObjectValue());
109 assertEquals(key, element.getObjectKey());
110 assertEquals(0, testedLoadingCache.getKeys().size());
111 }
112 }