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 HazelcastHybridCacheLazyTest 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                  .replicateSynchronously()
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      @Test
79      public void testPutInvalidatesCache()
80      {
81          // fill the cache on node1
82          assertThat(cacheNode1.get("key"), equalTo(1L));
83  
84          cacheNode2.put("key", 99L);
85          assertThat(cacheNode2.get("key"), equalTo(99L));
86  
87          // verify that cache1 has been invalidated
88          assertThat(cacheNode1.get("key"), equalTo(2L));
89          assertThat(cacheNode2.get("key"), equalTo(99L));
90      }
91  
92      @Test(timeout = 2000L)
93      public void testPutIfAbsentInvalidatesCache() throws InterruptedException
94      {
95          // fill the cache on node1
96          assertThat(cacheNode1.get("key"), equalTo(1L));
97  
98          Long oldValue = cacheNode2.putIfAbsent("key", 99L);
99          assertThat(oldValue, nullValue());
100         assertThat(cacheNode2.get("key"), equalTo(99L));
101 
102         // verify that cache1 is invalidated (eventually)
103         assertEventuallyThat(() -> cacheNode1.get("key"), equalTo(2L));
104 
105         assertThat(cacheNode1.get("key"), equalTo(2L));
106         assertThat(cacheNode2.get("key"), equalTo(99L));
107 
108         // verify that putIfAbsent does not invalidate cache when there's a value
109         oldValue = cacheNode2.putIfAbsent("key", 101L);
110         assertThat(oldValue, equalTo(99L));
111 
112         assertEventuallyThat(() -> cacheNode1.get("key"), equalTo(2L)); // should still be the same
113     }
114 
115     @Test
116     public void testReplaceInvalidatesCache()
117     {
118         // fill the caches
119         assertThat(cacheNode1.get("key"), equalTo(1L));
120         assertThat(cacheNode2.get("key"), equalTo(2L));
121 
122         cacheNode2.replace("key", 2L, 99L);
123         assertThat(cacheNode1.get("key"), equalTo(3L)); // cache 1 should have invalidated
124         assertThat(cacheNode2.get("key"), equalTo(99L));
125 
126         // verify that caches don't invalidate if the value is not replaced
127         boolean replaced = cacheNode2.replace("key", 10012L, 1L);
128         assertThat(replaced, is(false));
129         assertThat(cacheNode1.get("key"), equalTo(3L)); // unchanged
130         assertThat(cacheNode2.get("key"), equalTo(99L)); // unchanged
131     }
132 
133     @Test
134     public void testRemoveInvalidatesCache()
135     {
136         // fill the caches
137         assertThat(cacheNode1.get("key"), equalTo(1L));
138         assertThat(cacheNode2.get("key"), equalTo(2L));
139 
140         cacheNode2.remove("key");
141         assertThat(cacheNode1.get("key"), equalTo(3L)); // invalidated
142         assertThat(cacheNode2.get("key"), equalTo(4L)); // invalidated
143 
144         // test conditional remove
145         boolean removed = cacheNode2.remove("key", 3L);
146         assertThat(removed, is(false));
147         assertThat(cacheNode1.get("key"), equalTo(3L)); // unchanged
148         assertThat(cacheNode2.get("key"), equalTo(4L)); // unchanged
149 
150         removed = cacheNode2.remove("key", 4L);
151         assertThat(removed, is(true));
152         assertThat(cacheNode1.get("key"), equalTo(5L)); // invalidated
153         assertThat(cacheNode2.get("key"), equalTo(6L)); // invalidated
154     }
155 
156     @Test
157     public void testRemoveAllInvalidatesCache()
158     {
159         // fill the caches
160         assertThat(cacheNode1.get("key"), equalTo(1L));
161         assertThat(cacheNode2.get("key"), equalTo(2L));
162 
163         cacheNode2.removeAll();
164         assertThat(cacheNode1.get("key"), equalTo(3L)); // invalidated
165         assertThat(cacheNode2.get("key"), equalTo(4L)); // invalidated
166     }
167 
168     @Test
169     public void testRemoveConcurrentWithLoadClustered()
170     {
171         final CacheFactory factory2 = HazelcastTestSupport.createDistributedFactory(cluster.getNode(1));
172         removeConcurrentWithLoader(factory, factory2, REMOVE_0);
173     }
174 
175     @Test
176     public void testRemoveAllConcurrentWithLoadClustered()
177     {
178         final CacheFactory factory2 = HazelcastTestSupport.createDistributedFactory(cluster.getNode(1));
179         removeConcurrentWithLoader(factory, factory2, REMOVE_ALL);
180     }
181 
182     private static class BadLoader implements CacheLoader<String, Long>
183     {
184         private long value;
185 
186         @Nonnull
187         @Override
188         public Long load(@Nonnull String key)
189         {
190             return ++value;
191         }
192     }
193 }