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