View Javadoc
1   package com.atlassian.cache.hazelcast;
2   
3   import javax.annotation.Nonnull;
4   
5   import com.atlassian.cache.AbstractCacheLazyTest;
6   import com.atlassian.cache.Cache;
7   import com.atlassian.cache.CacheFactory;
8   import com.atlassian.cache.CacheLoader;
9   import com.atlassian.cache.CacheSettingsBuilder;
10  
11  import org.junit.After;
12  import org.junit.Before;
13  import org.junit.ClassRule;
14  import org.junit.Test;
15  
16  import static org.hamcrest.MatcherAssert.assertThat;
17  import static org.hamcrest.Matchers.equalTo;
18  import static org.hamcrest.Matchers.is;
19  import static org.hamcrest.Matchers.nullValue;
20  
21  public class HazelcastAsyncHybridCacheLazyTest extends AbstractCacheLazyTest
22  {
23      @ClassRule
24      public static InitOnceHazelcastCluster cluster = InitOnceHazelcastCluster.getInstance();
25  
26      private Cache<String, Long> cacheNode1;
27      private Cache<String, Long> cacheNode2;
28      private HazelcastCacheManager factory1;
29      private HazelcastCacheManager factory2;
30  
31      @Before
32      public void setUp() throws Exception
33      {
34          cluster.reset();
35          factory1 = HazelcastTestSupport.createDistributedFactory(cluster.getNode(0));
36          factory2 = HazelcastTestSupport.createDistributedFactory(cluster.getNode(1));
37  
38          // create a loader that never creates the same value twice. Used to verify indirectly that the cache has been
39          // invalidated
40          CacheLoader<String, Long> loader = new BadLoader();
41          // create two caches backed by the same version map, but different local caches.
42          cacheNode1 = factory1.getCache("test", loader, settingsBuilder().build());
43          cacheNode2 = factory2.getCache("test", loader, settingsBuilder().build());
44  
45          factory = factory1;
46      }
47  
48      @After
49      public void tearDown()
50      {
51          factory1.destroy();
52          factory2.destroy();
53      }
54  
55      @Override
56      protected CacheSettingsBuilder settingsBuilder()
57      {
58          return new CacheSettingsBuilder()
59                  .remote()
60                  .replicateAsynchronously()
61                  .replicateViaInvalidation();
62      }
63  
64      @Test
65      public void testLazyCreationDoestNotInvalidateCache()
66      {
67          // verify that the value is cached properly
68          assertThat(cacheNode1.get("key"), equalTo(1L));
69          assertThat(cacheNode1.get("key"), equalTo(1L));
70  
71          // retrieve the same key from the other cache - should be a local cache miss and trigger a call to BadLoader
72          assertThat(cacheNode2.get("key"), equalTo(2L));
73  
74          // but this should not trigger a cache eviction for cacheNode1
75          assertThat(cacheNode1.get("key"), equalTo(1L));
76      }
77  
78      public void testPutInvalidatesCache()
79      {
80          // fill the cache on node1
81          assertThat(cacheNode1.get("key"), equalTo(1L));
82  
83          cacheNode2.put("key", 99L);
84          assertThat(cacheNode2.get("key"), equalTo(99L));
85  
86          // verify that cache1 has been invalidated
87          assertEventuallyThat(() -> cacheNode1.get("key"), equalTo(2L));
88          assertThat(cacheNode2.get("key"), equalTo(99L));
89      }
90  
91      @Test(timeout = 2000L)
92      public void testPutIfAbsentInvalidatesCache() throws InterruptedException
93      {
94          // fill the cache on node1
95          assertThat(cacheNode1.get("key"), equalTo(1L));
96  
97          Long oldValue = cacheNode2.putIfAbsent("key", 99L);
98          assertThat(oldValue, nullValue());
99          assertThat(cacheNode2.get("key"), equalTo(99L));
100 
101         // verify that cache1 is invalidated (eventually)
102         assertEventuallyThat(() -> cacheNode1.get("key"), equalTo(2L));
103 
104         assertThat(cacheNode1.get("key"), equalTo(2L));
105         assertThat(cacheNode2.get("key"), equalTo(99L));
106 
107         // verify that putIfAbsent does not invalidate cache when there's a value
108         oldValue = cacheNode2.putIfAbsent("key", 101L);
109         assertThat(oldValue, equalTo(99L));
110 
111         assertEventuallyThat(() -> cacheNode1.get("key"), equalTo(2L)); // should still be the same
112     }
113 
114     @Test
115     public void testReplaceInvalidatesCache()
116     {
117         // fill the caches
118         assertThat(cacheNode1.get("key"), equalTo(1L));
119         assertThat(cacheNode2.get("key"), equalTo(2L));
120 
121         cacheNode2.replace("key", 2L, 99L);
122         assertEventuallyThat(() -> cacheNode1.get("key"), equalTo(3L)); // cache 1 should have invalidated
123         assertThat(cacheNode2.get("key"), equalTo(99L));
124 
125         // verify that caches don't invalidate if the value is not replaced
126         boolean replaced = cacheNode2.replace("key", 10012L, 1L);
127         assertThat(replaced, is(false));
128         assertThat(cacheNode1.get("key"), equalTo(3L)); // unchanged
129         assertThat(cacheNode2.get("key"), equalTo(99L)); // unchanged
130     }
131 
132     @Test
133     public void testRemoveInvalidatesCache()
134     {
135         // fill the caches
136         assertThat(cacheNode1.get("key"), equalTo(1L));
137         assertThat(cacheNode2.get("key"), equalTo(2L));
138 
139         cacheNode2.remove("key");
140         assertEventuallyThat(() -> cacheNode1.get("key"), equalTo(3L)); // invalidated
141         assertThat(cacheNode2.get("key"), equalTo(4L)); // invalidated
142 
143         // test conditional remove
144         boolean removed = cacheNode2.remove("key", 3L);
145         assertThat(removed, is(false));
146         assertThat(cacheNode1.get("key"), equalTo(3L)); // unchanged
147         assertThat(cacheNode2.get("key"), equalTo(4L)); // unchanged
148 
149         removed = cacheNode2.remove("key", 4L);
150         assertThat(removed, is(true));
151         assertEventuallyThat(() -> cacheNode1.get("key"), equalTo(5L)); // invalidated
152         assertThat(cacheNode2.get("key"), equalTo(6L)); // invalidated
153     }
154 
155     @Test
156     public void testRemoveAllInvalidatesCache()
157     {
158         // fill the caches
159         assertThat(cacheNode1.get("key"), equalTo(1L));
160         assertThat(cacheNode2.get("key"), equalTo(2L));
161 
162         cacheNode2.removeAll();
163         assertEventuallyThat(() -> cacheNode1.get("key"), equalTo(3L)); // invalidated
164         assertThat(cacheNode2.get("key"), equalTo(4L)); // invalidated
165     }
166 
167     @Test
168     public void testRemoveConcurrentWithLoadClustered()
169     {
170         final CacheFactory factory2 = HazelcastTestSupport.createDistributedFactory(cluster.getNode(1));
171         removeConcurrentWithLoader(factory, factory2, REMOVE_0);
172     }
173 
174     @Test
175     public void testRemoveAllConcurrentWithLoadClustered()
176     {
177         final CacheFactory factory2 = HazelcastTestSupport.createDistributedFactory(cluster.getNode(1));
178         removeConcurrentWithLoader(factory, factory2, REMOVE_ALL);
179     }
180 
181     private static class BadLoader implements CacheLoader<String, Long>
182     {
183         private long value;
184 
185         @Nonnull
186         @Override
187         public Long load(@Nonnull String key)
188         {
189             return ++value;
190         }
191     }
192 }