1 package com.atlassian.vcache.internal.test;
2
3 import com.atlassian.utt.concurrency.Barrier;
4 import com.atlassian.utt.concurrency.TestThread;
5 import com.atlassian.vcache.JvmCache;
6 import com.atlassian.vcache.JvmCacheSettings;
7 import com.atlassian.vcache.JvmCacheSettingsBuilder;
8 import com.atlassian.vcache.LocalCacheOperations;
9 import com.atlassian.vcache.VCache;
10 import org.junit.Test;
11
12 import java.time.Duration;
13 import java.util.Arrays;
14 import java.util.concurrent.CountDownLatch;
15 import java.util.concurrent.TimeUnit;
16 import java.util.concurrent.atomic.AtomicInteger;
17 import java.util.function.Consumer;
18 import java.util.function.Supplier;
19 import java.util.stream.Collectors;
20
21 import static org.hamcrest.Matchers.containsInAnyOrder;
22 import static org.hamcrest.Matchers.is;
23 import static org.hamcrest.Matchers.isOneOf;
24 import static org.junit.Assert.assertThat;
25
26
27
28
29 public abstract class AbstractJvmCacheTest extends AbstractLocalCacheOperationsTest {
30
31 protected abstract <K, V> JvmCache<K, V> createCache(String name, JvmCacheSettings settings);
32
33 @Override
34 protected final <K, V> JvmCache<K, V> createCache(String name) {
35 final JvmCacheSettings settings = new JvmCacheSettingsBuilder().maxEntries(3).defaultTtl(Duration.ofSeconds(10)).build();
36 return createCache(name, settings);
37 }
38
39 @Test
40 public void testGetName() throws Exception {
41 final VCache namedCache = createCache("jvmcache");
42 assertThat(namedCache.getName(), is("jvmcache"));
43 }
44
45 @SuppressWarnings("unchecked")
46 @Test
47 public void testKeys() {
48 final JvmCache<String, String> mycache = createCache("ignored");
49
50 assertThat(mycache.getKeys(), containsInAnyOrder());
51
52 mycache.put("k1", "v1");
53
54 assertThat(mycache.getKeys(), containsInAnyOrder("k1"));
55
56 mycache.put("k2", "v2");
57
58 assertThat(mycache.getKeys(), containsInAnyOrder("k1", "k2"));
59 }
60
61 @Test
62 public void testSize() {
63 final JvmCache<String, String> mycache = createCache("ignored");
64
65 assertThat(mycache.getKeys().size(), is(0));
66
67 mycache.put("k1", "v1");
68
69 assertThat(mycache.getKeys().size(), is(1));
70
71 mycache.put("k2", "v2");
72
73 assertThat(mycache.getKeys().size(), is(2));
74
75 mycache.put("k3", "v3");
76
77 assertThat(mycache.getKeys().size(), is(3));
78
79 mycache.put("k4", "v4");
80
81 assertThat(mycache.getKeys().size(), is(3));
82
83 Arrays.asList("k1", "k2", "k3", "k4").forEach(mycache::remove);
84
85 assertThat(mycache.getKeys().size(), is(0));
86 }
87
88 @Test
89 public void testRemoveConcurrentWithSupplier() {
90 removeConcurrentWithSupplier(c -> c.remove(0));
91 }
92
93 @Test
94 public void testRemoveAllConcurrentWithSupplier() {
95 removeConcurrentWithSupplier(LocalCacheOperations::removeAll);
96 }
97
98 private void removeConcurrentWithSupplier(Consumer<JvmCache<Integer, Integer>> removeFn) {
99 final Barrier doUpdate = new Barrier();
100 final CountDownLatch removeCalled = new CountDownLatch(1);
101 final Barrier afterGet = new Barrier();
102 final AtomicInteger dbValue = new AtomicInteger(1);
103
104 final Supplier<Integer> loader = () -> {
105 final int value = dbValue.get();
106 doUpdate.trySignal();
107 try {
108
109 removeCalled.await(250L, TimeUnit.MILLISECONDS);
110 } catch (InterruptedException ie) {
111 throw new AssertionError(ie);
112 }
113 afterGet.trySignal();
114 return value;
115 };
116
117 final JvmCache<Integer, Integer> mycache = createCache("ignored");
118
119 final TestThread blockingGet = new TestThread("blockingGet") {
120 @Override
121 protected void go() throws Exception {
122 assertThat(mycache.get(0, loader), isOneOf(1, 2));
123 removeCalled.await();
124 assertThat(mycache.get(0, loader), is(2));
125 }
126 };
127
128 final TestThread modifyRemoveGet = new TestThread("modifyRemoveGet") {
129 @Override
130 protected void go() throws Exception {
131 doUpdate.await();
132 dbValue.set(2);
133 removeFn.accept(mycache);
134 removeCalled.countDown();
135 assertThat(mycache.get(0, loader), is(2));
136 }
137 };
138
139 TestThread.runTest(blockingGet, modifyRemoveGet);
140 }
141
142 @Test
143 public void detect_illegal_recursion_factory() {
144 thrown.expect(IllegalStateException.class);
145 thrown.expectMessage("Recursive call with key: first");
146
147 final JvmCache<String, String> cache = createCache("abc");
148
149 cache.getBulk(
150 strings1 -> {
151 return cache.getBulk(strings2 -> {
152 return strings2.stream().collect(Collectors.toMap(k -> k, k -> k + "-2"));
153 }, strings1);
154 },
155 "first");
156 }
157 }