blob: a630d1a0d0ca58425377890aefa73105201b1ce9 [file] [log] [blame]
HIGUCHI Yuta14e865d2015-11-25 20:42:32 -08001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Madan Jampanif4c88502016-01-21 12:35:36 -080016package org.onosproject.store.primitives.impl;
HIGUCHI Yuta14e865d2015-11-25 20:42:32 -080017
18import static java.util.Collections.unmodifiableCollection;
19import static java.util.Collections.unmodifiableSet;
20import static org.hamcrest.Matchers.is;
Madan Jampanif4c88502016-01-21 12:35:36 -080021import static org.junit.Assert.assertEquals;
22import static org.junit.Assert.assertThat;
HIGUCHI Yuta14e865d2015-11-25 20:42:32 -080023
24import java.util.Collection;
25import java.util.Map;
26import java.util.Map.Entry;
27import java.util.Objects;
28import java.util.Set;
29import java.util.concurrent.CompletableFuture;
30import java.util.concurrent.ConcurrentHashMap;
31import java.util.function.Consumer;
32
Madan Jampanif4c88502016-01-21 12:35:36 -080033import net.kuujo.copycat.Task;
34import net.kuujo.copycat.cluster.Cluster;
35import net.kuujo.copycat.resource.ResourceState;
36
HIGUCHI Yuta14e865d2015-11-25 20:42:32 -080037import org.junit.After;
38import org.junit.Before;
39import org.junit.Test;
Madan Jampanif2f086c2016-01-13 16:15:39 -080040import org.onlab.util.Match;
HIGUCHI Yuta14e865d2015-11-25 20:42:32 -080041import org.onosproject.core.ApplicationId;
42import org.onosproject.core.DefaultApplicationId;
43import org.onosproject.store.service.Serializer;
44import org.onosproject.store.service.Transaction;
45import org.onosproject.store.service.Versioned;
46
47import com.google.common.base.MoreObjects;
48import com.google.common.collect.ImmutableMap;
49import com.google.common.collect.ImmutableSet;
HIGUCHI Yuta1c8493c2015-12-08 16:16:55 -080050import com.google.common.collect.Maps;
51
HIGUCHI Yuta14e865d2015-11-25 20:42:32 -080052/**
53 *
54 */
55public class DefaultAsyncConsistentMapTest {
56
57 private static final ApplicationId APP_ID = new DefaultApplicationId(42, "what");
58
59 private static final TestData KEY1A = new TestData("One", "a");
60 private static final TestData KEY1B = new TestData("One", "b");
61
62 private static final TestData VALUE2A = new TestData("Two", "a");
63 private static final TestData VALUE2B = new TestData("Two", "b");
64
65 @Before
66 public void setUp() throws Exception {
67 }
68
69 @After
70 public void tearDown() throws Exception {
71 }
72
73 @Test
74 public void testKeySet() throws Exception {
75 DefaultAsyncConsistentMap<TestData, TestData> map;
76 String name = "map_name";
77 Database database = new TestDatabase();
78 Serializer serializer = Serializer.forTypes(TestData.class);
79
80 map = new DefaultAsyncConsistentMap<>(name, APP_ID, database, serializer,
81 false, false, false);
82 map.put(KEY1A, VALUE2A);
83 map.put(KEY1B, VALUE2A);
84
85 Set<TestData> set = map.keySet().get();
86 assertEquals("Should contain 2 keys",
87 2, set.size());
88 assertThat(set.contains(KEY1A), is(true));
89 assertThat(set.contains(KEY1B), is(true));
90 assertThat(set.contains(new TestData("One", "a")), is(true));
91 }
92
93 @Test
94 public void testEntrySet() throws Exception {
95 DefaultAsyncConsistentMap<TestData, TestData> map;
96 String name = "map_name";
97 Database database = new TestDatabase();
98 Serializer serializer = Serializer.forTypes(TestData.class);
99
100 map = new DefaultAsyncConsistentMap<>(name, APP_ID, database, serializer,
101 false, false, false);
102 map.put(KEY1A, VALUE2A);
103 map.put(KEY1B, VALUE2A);
104
105 assertEquals("Should contain 2 entry",
106 2,
107 map.entrySet().get().size());
108 }
109
110 /**
111 * Object to be used as a test data.
112 *
113 * {@link Object#equals(Object)} use only part of it's fields.
114 *
115 * As a result there can be 2 instances which the
116 * serialized bytes are not-equal but
117 * {@link Object#equals(Object)}-wise they are equal.
118 */
119 public static class TestData {
120
121 private final String theKey;
122
123 @SuppressWarnings("unused")
124 private final String notUsedForEquals;
125
126 public TestData(String theKey, String notUsedForEquals) {
127 this.theKey = theKey;
128 this.notUsedForEquals = notUsedForEquals;
129 }
130
131 @Override
132 public int hashCode() {
133 return Objects.hashCode(theKey);
134 }
135
136 @Override
137 public boolean equals(Object obj) {
138 if (obj instanceof TestData) {
139 TestData that = (TestData) obj;
140 return Objects.equals(this.theKey, that.theKey);
141 }
142 return false;
143 }
144
145 @Override
146 public String toString() {
147 return MoreObjects.toStringHelper(this)
148 .add("theKey", theKey)
149 .add("notUsedForEquals", notUsedForEquals)
150 .toString();
151 }
152 }
153
154 /**
155 * {@link Database} implementation for testing.
156 *
157 * There is only 1 backing Map, {@code mapName} will be ignored.
158 */
159 public class TestDatabase implements Database {
160
161 Map<String, Versioned<byte[]>> map = new ConcurrentHashMap<>();
162
163 @Override
164 public CompletableFuture<Set<String>> maps() {
165 return CompletableFuture.completedFuture(ImmutableSet.of());
166 }
167
168 @Override
169 public CompletableFuture<Map<String, Long>> counters() {
170 return CompletableFuture.completedFuture(ImmutableMap.of());
171 }
172
173 @Override
174 public CompletableFuture<Integer> mapSize(String mapName) {
175 return CompletableFuture.completedFuture(map.size());
176 }
177
178 @Override
179 public CompletableFuture<Boolean> mapIsEmpty(String mapName) {
180 return CompletableFuture.completedFuture(map.isEmpty());
181 }
182
183 @Override
184 public CompletableFuture<Boolean> mapContainsKey(String mapName,
185 String key) {
186 return CompletableFuture.completedFuture(map.containsKey(key));
187 }
188
189 @Override
190 public CompletableFuture<Boolean> mapContainsValue(String mapName,
191 byte[] value) {
HIGUCHI Yuta1c8493c2015-12-08 16:16:55 -0800192 return CompletableFuture.completedFuture(Maps.transformValues(map, Versioned::value)
193 .containsValue(value));
HIGUCHI Yuta14e865d2015-11-25 20:42:32 -0800194 }
195
196 @Override
197 public CompletableFuture<Versioned<byte[]>> mapGet(String mapName,
198 String key) {
199 return CompletableFuture.completedFuture(map.get(key));
200 }
201
202 @Override
203 public synchronized CompletableFuture<Result<UpdateResult<String, byte[]>>> mapUpdate(String mapName,
204 String key,
205 Match<byte[]> valueMatch,
206 Match<Long> versionMatch,
207 byte[] value) {
208
209 boolean updated = false;
210 final Versioned<byte[]> oldValue;
211 final Versioned<byte[]> newValue;
212
213 Versioned<byte[]> old = map.getOrDefault(key, new Versioned<byte[]>(null, 0));
214 if (valueMatch.matches(old.value()) && versionMatch.matches(old.version())) {
215 updated = true;
216 oldValue = old;
217 newValue = new Versioned<>(value, old.version() + 1);
218 map.put(key, newValue);
219 } else {
220 updated = false;
221 oldValue = old;
222 newValue = old;
223 }
224 return CompletableFuture.completedFuture(
225 Result.ok(new UpdateResult<String, byte[]>(updated,
226 mapName, key, oldValue, newValue)));
227 }
228
229 @Override
230 public CompletableFuture<Result<Void>> mapClear(String mapName) {
231 throw new UnsupportedOperationException();
232 }
233
234 @Override
235 public CompletableFuture<Set<String>> mapKeySet(String mapName) {
236 return CompletableFuture.completedFuture(unmodifiableSet(map.keySet()));
237 }
238
239 @Override
240 public CompletableFuture<Collection<Versioned<byte[]>>> mapValues(String mapName) {
241 return CompletableFuture.completedFuture(unmodifiableCollection(map.values()));
242 }
243
244 @Override
245 public CompletableFuture<Set<Entry<String, Versioned<byte[]>>>> mapEntrySet(String mapName) {
246 return CompletableFuture.completedFuture(unmodifiableSet(map.entrySet()));
247 }
248
249 @Override
250 public CompletableFuture<Long> counterAddAndGet(String counterName,
251 long delta) {
252 throw new UnsupportedOperationException();
253 }
254
255 @Override
256 public CompletableFuture<Long> counterGetAndAdd(String counterName,
257 long delta) {
258 throw new UnsupportedOperationException();
259 }
260
261 @Override
262 public CompletableFuture<Void> counterSet(String counterName,
263 long value) {
264 throw new UnsupportedOperationException();
265 }
266
267 @Override
268 public CompletableFuture<Boolean> counterCompareAndSet(String counterName,
269 long expectedValue,
270 long update) {
271 throw new UnsupportedOperationException();
272 }
273
274 @Override
275 public CompletableFuture<Long> counterGet(String counterName) {
276 throw new UnsupportedOperationException();
277 }
278
279 @Override
280 public CompletableFuture<Long> queueSize(String queueName) {
281 throw new UnsupportedOperationException();
282 }
283
284 @Override
285 public CompletableFuture<Void> queuePush(String queueName,
286 byte[] entry) {
287 throw new UnsupportedOperationException();
288 }
289
290 @Override
291 public CompletableFuture<byte[]> queuePop(String queueName) {
292 throw new UnsupportedOperationException();
293 }
294
295 @Override
296 public CompletableFuture<byte[]> queuePeek(String queueName) {
297 throw new UnsupportedOperationException();
298 }
299
300 @Override
301 public CompletableFuture<CommitResponse> prepareAndCommit(Transaction transaction) {
302 throw new UnsupportedOperationException();
303 }
304
305 @Override
306 public CompletableFuture<Boolean> prepare(Transaction transaction) {
307 throw new UnsupportedOperationException();
308 }
309
310 @Override
311 public CompletableFuture<CommitResponse> commit(Transaction transaction) {
312 throw new UnsupportedOperationException();
313 }
314
315 @Override
316 public CompletableFuture<Boolean> rollback(Transaction transaction) {
317 throw new UnsupportedOperationException();
318 }
319
320 @Override
321 public String name() {
322 return "name";
323 }
324
325 @Override
326 public ResourceState state() {
327 return ResourceState.HEALTHY;
328 }
329
330 @Override
331 public Cluster cluster() {
332 throw new UnsupportedOperationException();
333 }
334
335 @Override
336 public Database addStartupTask(Task<CompletableFuture<Void>> task) {
337 throw new UnsupportedOperationException();
338 }
339
340 @Override
341 public Database addShutdownTask(Task<CompletableFuture<Void>> task) {
342 throw new UnsupportedOperationException();
343 }
344
345 @Override
346 public CompletableFuture<Database> open() {
347 return CompletableFuture.completedFuture(this);
348 }
349
350 @Override
351 public boolean isOpen() {
352 return true;
353 }
354
355 @Override
356 public CompletableFuture<Void> close() {
357 return CompletableFuture.completedFuture(null);
358 }
359
360 @Override
361 public boolean isClosed() {
362 return false;
363 }
364
365 @Override
366 public void registerConsumer(Consumer<StateMachineUpdate> consumer) {
367 }
368
369 @Override
370 public void unregisterConsumer(Consumer<StateMachineUpdate> consumer) {
371 }
372 }
373
374}