blob: 122673b23927b58ed65c1d5a8bc5ad6b673af465 [file] [log] [blame]
Aaron Kruglikov3e29f662016-07-13 10:18:10 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Aaron Kruglikov3e29f662016-07-13 10:18:10 -07003 *
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.primitives.resources.impl;
17
Aaron Kruglikov3e29f662016-07-13 10:18:10 -070018import java.util.Arrays;
19import java.util.Collection;
20import java.util.List;
21import java.util.Map;
22import java.util.concurrent.ArrayBlockingQueue;
23import java.util.concurrent.BlockingQueue;
24import java.util.stream.Collectors;
25
Jordan Halterman2bf177c2017-06-29 01:49:08 -070026import com.google.common.base.Throwables;
27import com.google.common.collect.Lists;
28import io.atomix.protocols.raft.proxy.RaftProxy;
29import io.atomix.protocols.raft.service.RaftService;
30import org.junit.Test;
31import org.onlab.util.Tools;
32import org.onosproject.store.service.MapEvent;
33import org.onosproject.store.service.MapEventListener;
34
Aaron Kruglikov3e29f662016-07-13 10:18:10 -070035import static org.junit.Assert.assertArrayEquals;
36import static org.junit.Assert.assertEquals;
37import static org.junit.Assert.assertFalse;
Jordan Haltermanf6272442017-04-20 02:18:08 -070038import static org.junit.Assert.assertNotEquals;
Aaron Kruglikov3e29f662016-07-13 10:18:10 -070039import static org.junit.Assert.assertNotNull;
40import static org.junit.Assert.assertNull;
41import static org.junit.Assert.assertTrue;
42
43/**
44 * Unit tests for {@link AtomixConsistentTreeMap}.
45 */
Jordan Halterman2bf177c2017-06-29 01:49:08 -070046public class AtomixConsistentTreeMapTest extends AtomixTestBase<AtomixConsistentTreeMap> {
Aaron Kruglikov3e29f662016-07-13 10:18:10 -070047 private final String keyFour = "hello";
48 private final String keyThree = "goodbye";
49 private final String keyTwo = "foo";
50 private final String keyOne = "bar";
51 private final byte[] valueOne = Tools.getBytesUtf8(keyOne);
52 private final byte[] valueTwo = Tools.getBytesUtf8(keyTwo);
53 private final byte[] valueThree = Tools.getBytesUtf8(keyThree);
54 private final byte[] valueFour = Tools.getBytesUtf8(keyFour);
55 private final byte[] spareValue = Tools.getBytesUtf8("spareValue");
56 private final List<String> allKeys = Lists.newArrayList(keyOne, keyTwo,
57 keyThree, keyFour);
58 private final List<byte[]> allValues = Lists.newArrayList(valueOne,
59 valueTwo,
60 valueThree,
61 valueFour);
Aaron Kruglikov3e29f662016-07-13 10:18:10 -070062
Jordan Halterman2bf177c2017-06-29 01:49:08 -070063 @Override
64 protected RaftService createService() {
65 return new AtomixConsistentTreeMapService();
Aaron Kruglikov3e29f662016-07-13 10:18:10 -070066 }
67
68 @Override
Jordan Halterman2bf177c2017-06-29 01:49:08 -070069 protected AtomixConsistentTreeMap createPrimitive(RaftProxy proxy) {
70 return new AtomixConsistentTreeMap(proxy);
Aaron Kruglikov3e29f662016-07-13 10:18:10 -070071 }
72
73 /**
74 * Tests of the functionality associated with the
75 * {@link org.onosproject.store.service.AsyncConsistentMap} interface
76 * except transactions and listeners.
77 */
78 @Test
79 public void testBasicMapOperations() throws Throwable {
80 //Throughout the test there are isEmpty queries, these are intended to
81 //make sure that the previous section has been cleaned up, they serve
82 //the secondary purpose of testing isEmpty but that is not their
83 //primary purpose.
84 AtomixConsistentTreeMap map = createResource("basicTestMap");
85 //test size
86 map.size().thenAccept(result -> assertEquals(0, (int) result)).join();
87 map.isEmpty().thenAccept(result -> assertTrue(result)).join();
Jordan Haltermanf6272442017-04-20 02:18:08 -070088
Aaron Kruglikov3e29f662016-07-13 10:18:10 -070089 //test contains key
90 allKeys.forEach(key -> map.containsKey(key).
91 thenAccept(result -> assertFalse(result)).join());
Jordan Haltermanf6272442017-04-20 02:18:08 -070092
Aaron Kruglikov3e29f662016-07-13 10:18:10 -070093 //test contains value
94 allValues.forEach(value -> map.containsValue(value)
95 .thenAccept(result -> assertFalse(result)).join());
Jordan Haltermanf6272442017-04-20 02:18:08 -070096
Aaron Kruglikov3e29f662016-07-13 10:18:10 -070097 //test get
98 allKeys.forEach(key -> map.get(key).
99 thenAccept(result -> assertNull(result)).join());
100
Jordan Haltermanf6272442017-04-20 02:18:08 -0700101 //test getOrDefault
102 allKeys.forEach(key -> map.getOrDefault(key, null).thenAccept(result -> {
103 assertEquals(0, result.version());
104 assertNull(result.value());
105 }).join());
106
107 allKeys.forEach(key -> map.getOrDefault(key, "bar".getBytes()).thenAccept(result -> {
108 assertEquals(0, result.version());
109 assertArrayEquals("bar".getBytes(), result.value());
110 }).join());
111
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700112 //populate and redo prior three tests
Jordan Haltermanf6272442017-04-20 02:18:08 -0700113 allKeys.forEach(key -> map.put(key, allValues.get(allKeys.indexOf(key)))
114 .thenAccept(result -> assertNull(result)).join());
115
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700116 //test contains key
Jordan Haltermanf6272442017-04-20 02:18:08 -0700117 allKeys.forEach(key -> map.containsKey(key)
118 .thenAccept(result -> assertTrue(result)).join());
119
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700120 //test contains value
121 allValues.forEach(value -> map.containsValue(value)
122 .thenAccept(result -> assertTrue(result)).join());
Jordan Haltermanf6272442017-04-20 02:18:08 -0700123
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700124 //test get
Jordan Haltermanf6272442017-04-20 02:18:08 -0700125 allKeys.forEach(key -> map.get(key).thenAccept(result -> {
126 assertArrayEquals(allValues.get(allKeys.indexOf(key)), result.value());
127 }).join());
128
129 allKeys.forEach(key -> map.getOrDefault(key, null).thenAccept(result -> {
130 assertNotEquals(0, result.version());
131 assertArrayEquals(allValues.get(allKeys.indexOf(key)), result.value());
132 }).join());
133
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700134 //test all compute methods in this section
Jordan Haltermanf6272442017-04-20 02:18:08 -0700135 allKeys.forEach(key -> map.computeIfAbsent(key, v -> allValues.get(allKeys.indexOf(key)))
136 .thenAccept(result -> {
137 assertArrayEquals(allValues.get(allKeys.indexOf(key)), result.value());
138 }).join());
139
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700140 map.size().thenAccept(result -> assertEquals(4, (int) result)).join();
141 map.isEmpty().thenAccept(result -> assertFalse(result)).join();
Jordan Haltermanf6272442017-04-20 02:18:08 -0700142
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700143 allKeys.forEach(key -> map.computeIfPresent(key, (k, v) -> null).
144 thenAccept(result -> assertNull(result)).join());
Jordan Haltermanf6272442017-04-20 02:18:08 -0700145
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700146 map.isEmpty().thenAccept(result -> assertTrue(result)).join();
Jordan Haltermanf6272442017-04-20 02:18:08 -0700147
148 allKeys.forEach(key -> map.compute(key, (k, v) -> allValues.get(allKeys.indexOf(key)))
149 .thenAccept(result -> assertArrayEquals(allValues.get(allKeys.indexOf(key)), result.value())).join());
150
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700151 map.size().thenAccept(result -> assertEquals(4, (int) result)).join();
152 map.isEmpty().thenAccept(result -> assertFalse(result)).join();
Jordan Haltermanf6272442017-04-20 02:18:08 -0700153
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700154 allKeys.forEach(key -> map.computeIf(key,
Jordan Haltermanf6272442017-04-20 02:18:08 -0700155 (k) -> allKeys.indexOf(key) < 2, (k, v) -> null).thenAccept(result -> {
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700156 if (allKeys.indexOf(key) < 2) {
157 assertNull(result);
158 } else {
Jordan Haltermanf6272442017-04-20 02:18:08 -0700159 assertArrayEquals(allValues.get(allKeys.indexOf(key)), result.value());
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700160 }
Jordan Haltermanf6272442017-04-20 02:18:08 -0700161 }).join());
162
163 map.size().thenAccept(result -> assertEquals(2, (int) result)).join();
164 map.isEmpty().thenAccept(result -> assertFalse(result)).join();
165
166 //test simple put
167 allKeys.forEach(key -> map.put(key, allValues.get(allKeys.indexOf(key))).thenAccept(result -> {
168 if (allKeys.indexOf(key) < 2) {
169 assertNull(result);
170 } else {
171 assertArrayEquals(allValues.get(allKeys.indexOf(key)), result.value());
172 }
173 }).join());
174
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700175 map.size().thenAccept(result -> assertEquals(4, (int) result)).join();
176 map.isEmpty().thenAccept(result -> assertFalse(result)).join();
Jordan Haltermanf6272442017-04-20 02:18:08 -0700177
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700178 //test put and get for version retrieval
Jordan Haltermanf6272442017-04-20 02:18:08 -0700179 allKeys.forEach(key -> map.putAndGet(key, allValues.get(allKeys.indexOf(key))).thenAccept(firstResult -> {
180 map.putAndGet(key, allValues.get(allKeys.indexOf(key))).thenAccept(secondResult -> {
181 assertArrayEquals(allValues.get(allKeys.indexOf(key)), firstResult.value());
182 assertArrayEquals(allValues.get(allKeys.indexOf(key)), secondResult.value());
Jordan Haltermanf6272442017-04-20 02:18:08 -0700183 });
184 }).join());
185
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700186 //test removal
187 allKeys.forEach(key -> map.remove(key).thenAccept(
188 result -> assertArrayEquals(
189 allValues.get(allKeys.indexOf(key)), result.value()))
190 .join());
191 map.isEmpty().thenAccept(result -> assertTrue(result));
Jordan Haltermanf6272442017-04-20 02:18:08 -0700192
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700193 //repopulating, this is not mainly for testing
Jordan Haltermanf6272442017-04-20 02:18:08 -0700194 allKeys.forEach(key -> map.put(key, allValues.get(allKeys.indexOf(key))).thenAccept(result -> {
195 assertNull(result);
196 }).join());
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700197
198 //Test various collections of keys, values and entries
Jordan Haltermanf6272442017-04-20 02:18:08 -0700199 map.keySet().thenAccept(keys -> assertTrue(stringArrayCollectionIsEqual(keys, allKeys))).join();
200 map.values().thenAccept(values -> assertTrue(
201 byteArrayCollectionIsEqual(values.stream().map(v -> v.value())
202 .collect(Collectors.toSet()), allValues))).join();
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700203 map.entrySet().thenAccept(entrySet -> {
204 entrySet.forEach(entry -> {
205 assertTrue(allKeys.contains(entry.getKey()));
206 assertTrue(Arrays.equals(entry.getValue().value(),
207 allValues.get(allKeys.indexOf(entry.getKey()))));
208 });
209 }).join();
210 map.clear().join();
211 map.isEmpty().thenAccept(result -> assertTrue(result)).join();
212
213 //test conditional put
Jordan Haltermanf6272442017-04-20 02:18:08 -0700214 allKeys.forEach(key -> map.putIfAbsent(key, allValues.get(allKeys.indexOf(key)))
215 .thenAccept(result -> assertNull(result)).join());
216 allKeys.forEach(key -> map.putIfAbsent(key, null).thenAccept(result ->
217 assertArrayEquals(result.value(), allValues.get(allKeys.indexOf(key)))
218 ).join());
219
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700220 // test alternate removes that specify value or version
Jordan Haltermanf6272442017-04-20 02:18:08 -0700221 allKeys.forEach(key -> map.remove(key, spareValue).thenAccept(result -> assertFalse(result)).join());
222 allKeys.forEach(key -> map.remove(key, allValues.get(allKeys.indexOf(key)))
223 .thenAccept(result -> assertTrue(result)).join());
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700224 map.isEmpty().thenAccept(result -> assertTrue(result)).join();
225 List<Long> versions = Lists.newArrayList();
226
227 //repopulating set for version based removal
Jordan Haltermanf6272442017-04-20 02:18:08 -0700228 allKeys.forEach(key -> map.putAndGet(key, allValues.get(allKeys.indexOf(key)))
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700229 .thenAccept(result -> versions.add(result.version())).join());
Jordan Haltermanf6272442017-04-20 02:18:08 -0700230 allKeys.forEach(key -> map.remove(key, versions.get(0)).thenAccept(result -> {
231 assertTrue(result);
232 versions.remove(0);
233 }).join());
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700234 map.isEmpty().thenAccept(result -> assertTrue(result)).join();
Jordan Haltermanf6272442017-04-20 02:18:08 -0700235
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700236 //Testing all replace both simple (k, v), and complex that consider
237 // previous mapping or version.
Jordan Haltermanf6272442017-04-20 02:18:08 -0700238 allKeys.forEach(key -> map.put(key, allValues.get(allKeys.indexOf(key)))
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700239 .thenAccept(result -> assertNull(result)).join());
Jordan Haltermanf6272442017-04-20 02:18:08 -0700240 allKeys.forEach(key -> map.replace(key, allValues.get(3 - allKeys.indexOf(key)))
241 .thenAccept(result -> assertArrayEquals(allValues.get(allKeys.indexOf(key)), result.value()))
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700242 .join());
Jordan Haltermanf6272442017-04-20 02:18:08 -0700243 allKeys.forEach(key -> map.replace(key, spareValue, allValues.get(allKeys.indexOf(key)))
244 .thenAccept(result -> assertFalse(result)).join());
245 allKeys.forEach(key -> map.replace(key, allValues.get(3 - allKeys.indexOf(key)),
246 allValues.get(allKeys.indexOf(key))).thenAccept(result -> assertTrue(result)).join());
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700247 map.clear().join();
248 map.isEmpty().thenAccept(result -> assertTrue(result)).join();
249 versions.clear();
Jordan Haltermanf6272442017-04-20 02:18:08 -0700250
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700251 //populate for version based replacement
Jordan Haltermanf6272442017-04-20 02:18:08 -0700252 allKeys.forEach(key -> map.putAndGet(key, allValues.get(3 - allKeys.indexOf(key)))
253 .thenAccept(result -> versions.add(result.version())).join());
254 allKeys.forEach(key -> map.replace(key, 0, allValues.get(allKeys.indexOf(key)))
255 .thenAccept(result -> assertFalse(result)).join());
256 allKeys.forEach(key -> map.replace(key, versions.get(0), allValues.get(allKeys.indexOf(key)))
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700257 .thenAccept(result -> {
258 assertTrue(result);
259 versions.remove(0);
260 }).join());
261 }
262
263 @Test
264 public void mapListenerTests() throws Throwable {
265 final byte[] value1 = Tools.getBytesUtf8("value1");
266 final byte[] value2 = Tools.getBytesUtf8("value2");
267 final byte[] value3 = Tools.getBytesUtf8("value3");
268
269 AtomixConsistentTreeMap map = createResource("treeMapListenerTestMap");
270 TestMapEventListener listener = new TestMapEventListener();
271
272 // add listener; insert new value into map and verify an INSERT event
273 // is received.
274 map.addListener(listener).thenCompose(v -> map.put("foo", value1))
275 .join();
276 MapEvent<String, byte[]> event = listener.event();
277 assertNotNull(event);
278 assertEquals(MapEvent.Type.INSERT, event.type());
279 assertTrue(Arrays.equals(value1, event.newValue().value()));
280
281 // remove listener and verify listener is not notified.
282 map.removeListener(listener).thenCompose(v -> map.put("foo", value2))
283 .join();
284 assertFalse(listener.eventReceived());
285
286 // add the listener back and verify UPDATE events are received
287 // correctly
288 map.addListener(listener).thenCompose(v -> map.put("foo", value3))
289 .join();
290 event = listener.event();
291 assertNotNull(event);
292 assertEquals(MapEvent.Type.UPDATE, event.type());
293 assertTrue(Arrays.equals(value3, event.newValue().value()));
294
295 // perform a non-state changing operation and verify no events are
296 // received.
297 map.putIfAbsent("foo", value1).join();
298 assertFalse(listener.eventReceived());
299
300 // verify REMOVE events are received correctly.
301 map.remove("foo").join();
302 event = listener.event();
303 assertNotNull(event);
304 assertEquals(MapEvent.Type.REMOVE, event.type());
305 assertTrue(Arrays.equals(value3, event.oldValue().value()));
306
307 // verify compute methods also generate events.
308 map.computeIf("foo", v -> v == null, (k, v) -> value1).join();
309 event = listener.event();
310 assertNotNull(event);
311 assertEquals(MapEvent.Type.INSERT, event.type());
312 assertTrue(Arrays.equals(value1, event.newValue().value()));
313
314 map.compute("foo", (k, v) -> value2).join();
315 event = listener.event();
316 assertNotNull(event);
317 assertEquals(MapEvent.Type.UPDATE, event.type());
318 assertTrue(Arrays.equals(value2, event.newValue().value()));
319
320 map.computeIf(
321 "foo", v -> Arrays.equals(v, value2), (k, v) -> null).join();
322 event = listener.event();
323 assertNotNull(event);
324 assertEquals(MapEvent.Type.REMOVE, event.type());
325 assertTrue(Arrays.equals(value2, event.oldValue().value()));
326
327 map.removeListener(listener).join();
328 }
329
330 /**
331 * Tests functionality specified in the {@link AtomixConsistentTreeMap}
332 * interface, beyond the functionality provided in
333 * {@link org.onosproject.store.service.AsyncConsistentMap}.
334 */
335 @Test
336 public void treeMapFunctionsTest() {
337 AtomixConsistentTreeMap map = createResource("treeMapFunctionTestMap");
338 //Tests on empty map
339 map.firstKey().thenAccept(result -> assertNull(result)).join();
340 map.lastKey().thenAccept(result -> assertNull(result)).join();
341 map.ceilingEntry(keyOne).thenAccept(result -> assertNull(result))
342 .join();
343 map.floorEntry(keyOne).thenAccept(result -> assertNull(result)).join();
344 map.higherEntry(keyOne).thenAccept(result -> assertNull(result))
345 .join();
346 map.lowerEntry(keyOne).thenAccept(result -> assertNull(result)).join();
347 map.firstEntry().thenAccept(result -> assertNull(result)).join();
348 map.lastEntry().thenAccept(result -> assertNull(result)).join();
349 map.pollFirstEntry().thenAccept(result -> assertNull(result)).join();
350 map.pollLastEntry().thenAccept(result -> assertNull(result)).join();
351 map.lowerKey(keyOne).thenAccept(result -> assertNull(result)).join();
352 map.floorKey(keyOne).thenAccept(result -> assertNull(result)).join();
353 map.ceilingKey(keyOne).thenAccept(result -> assertNull(result))
354 .join();
355 map.higherKey(keyOne).thenAccept(result -> assertNull(result)).join();
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700356
357 // TODO: delete() is not supported
358 //map.delete().join();
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700359
360 allKeys.forEach(key -> map.put(
361 key, allValues.get(allKeys.indexOf(key)))
362 .thenAccept(result -> assertNull(result)).join());
363 //Note ordering keys are in their proper ordering in ascending order
364 //both in naming and in the allKeys list.
365
366 map.firstKey().thenAccept(result -> assertEquals(keyOne, result))
367 .join();
368 map.lastKey().thenAccept(result -> assertEquals(keyFour, result))
369 .join();
370 map.ceilingEntry(keyOne)
371 .thenAccept(result -> {
372 assertEquals(keyOne, result.getKey());
373 assertArrayEquals(valueOne, result.getValue().value());
374 })
375 .join();
376 //adding an additional letter to make keyOne an unacceptable response
377 map.ceilingEntry(keyOne + "a")
378 .thenAccept(result -> {
379 assertEquals(keyTwo, result.getKey());
380 assertArrayEquals(valueTwo, result.getValue().value());
381 })
382 .join();
383 map.ceilingEntry(keyFour + "a")
384 .thenAccept(result -> {
385 assertNull(result);
386 })
387 .join();
388 map.floorEntry(keyTwo).thenAccept(result -> {
389 assertEquals(keyTwo, result.getKey());
390 assertArrayEquals(valueTwo, result.getValue().value());
391 })
392 .join();
393 //shorten the key so it itself is not an acceptable reply
394 map.floorEntry(keyTwo.substring(0, 2)).thenAccept(result -> {
395 assertEquals(keyOne, result.getKey());
396 assertArrayEquals(valueOne, result.getValue().value());
397 })
398 .join();
399 // shorten least key so no acceptable response exists
400 map.floorEntry(keyOne.substring(0, 1)).thenAccept(
401 result -> assertNull(result))
402 .join();
403
404 map.higherEntry(keyTwo).thenAccept(result -> {
405 assertEquals(keyThree, result.getKey());
406 assertArrayEquals(valueThree, result.getValue().value());
407 })
408 .join();
409 map.higherEntry(keyFour).thenAccept(result -> assertNull(result))
410 .join();
411
412 map.lowerEntry(keyFour).thenAccept(result -> {
413 assertEquals(keyThree, result.getKey());
414 assertArrayEquals(valueThree, result.getValue().value());
415 })
416 .join();
417 map.lowerEntry(keyOne).thenAccept(result -> assertNull(result))
418 .join();
419 map.firstEntry().thenAccept(result -> {
420 assertEquals(keyOne, result.getKey());
421 assertArrayEquals(valueOne, result.getValue().value());
422 })
423 .join();
424 map.lastEntry().thenAccept(result -> {
425 assertEquals(keyFour, result.getKey());
426 assertArrayEquals(valueFour, result.getValue().value());
427 })
428 .join();
429 map.pollFirstEntry().thenAccept(result -> {
430 assertEquals(keyOne, result.getKey());
431 assertArrayEquals(valueOne, result.getValue().value());
432 });
433 map.containsKey(keyOne).thenAccept(result -> assertFalse(result))
434 .join();
435 map.size().thenAccept(result -> assertEquals(3, (int) result)).join();
436 map.pollLastEntry().thenAccept(result -> {
437 assertEquals(keyFour, result.getKey());
438 assertArrayEquals(valueFour, result.getValue().value());
439 });
440 map.containsKey(keyFour).thenAccept(result -> assertFalse(result))
441 .join();
442 map.size().thenAccept(result -> assertEquals(2, (int) result)).join();
443
444 //repopulate the missing entries
445 allKeys.forEach(key -> map.put(
446 key, allValues.get(allKeys.indexOf(key)))
447 .thenAccept(result -> {
448 if (key.equals(keyOne) || key.equals(keyFour)) {
449 assertNull(result);
450 } else {
451 assertArrayEquals(allValues.get(allKeys.indexOf(key)),
452 result.value());
453 }
454 })
455 .join());
456 map.lowerKey(keyOne).thenAccept(result -> assertNull(result)).join();
457 map.lowerKey(keyThree).thenAccept(
458 result -> assertEquals(keyTwo, result))
459 .join();
460 map.floorKey(keyThree).thenAccept(
461 result -> assertEquals(keyThree, result))
462 .join();
463 //shortening the key so there is no acceptable response
464 map.floorKey(keyOne.substring(0, 1)).thenAccept(
465 result -> assertNull(result))
466 .join();
467 map.ceilingKey(keyTwo).thenAccept(
468 result -> assertEquals(keyTwo, result))
469 .join();
470 //adding to highest key so there is no acceptable response
471 map.ceilingKey(keyFour + "a")
472 .thenAccept(reslt -> assertNull(reslt))
473 .join();
474 map.higherKey(keyThree).thenAccept(
475 result -> assertEquals(keyFour, result))
476 .join();
477 map.higherKey(keyFour).thenAccept(
478 result -> assertNull(result))
479 .join();
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700480
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700481 // TODO: delete() is not supported
482 //map.delete().join();
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700483 }
484
485 private AtomixConsistentTreeMap createResource(String mapName) {
486 try {
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700487 AtomixConsistentTreeMap map = newPrimitive(mapName);
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700488 return map;
489 } catch (Throwable e) {
490 throw new RuntimeException(e.toString());
491 }
492 }
493 private static class TestMapEventListener
494 implements MapEventListener<String, byte[]> {
495
496 private final BlockingQueue<MapEvent<String, byte[]>> queue =
497 new ArrayBlockingQueue<>(1);
498
499 @Override
500 public void event(MapEvent<String, byte[]> event) {
501 try {
502 queue.put(event);
503 } catch (InterruptedException e) {
504 Throwables.propagate(e);
505 }
506 }
507
508 public boolean eventReceived() {
509 return !queue.isEmpty();
510 }
511
512 public MapEvent<String, byte[]> event() throws InterruptedException {
513 return queue.take();
514 }
515 }
516
517 /**
518 * Returns two arrays contain the same set of elements,
519 * regardless of order.
520 * @param o1 first collection
521 * @param o2 second collection
522 * @return true if they contain the same elements
523 */
524 private boolean byteArrayCollectionIsEqual(
525 Collection<? extends byte[]> o1, Collection<? extends byte[]> o2) {
526 if (o1 == null || o2 == null || o1.size() != o2.size()) {
527 return false;
528 }
529 for (byte[] array1 : o1) {
530 boolean matched = false;
531 for (byte[] array2 : o2) {
532 if (Arrays.equals(array1, array2)) {
533 matched = true;
534 break;
535 }
536 }
537 if (!matched) {
538 return false;
539 }
540 }
541 return true;
542 }
543
544 /**
545 * Compares two collections of strings returns true if they contain the
546 * same strings, false otherwise.
547 * @param s1 string collection one
548 * @param s2 string collection two
549 * @return true if the two sets contain the same strings
550 */
551 private boolean stringArrayCollectionIsEqual(
552 Collection<? extends String> s1, Collection<? extends String> s2) {
553 if (s1 == null || s2 == null || s1.size() != s2.size()) {
554 return false;
555 }
556 for (String string1 : s1) {
557 boolean matched = false;
558 for (String string2 : s2) {
559 if (string1.equals(string2)) {
560 matched = true;
561 break;
562 }
563 }
564 if (!matched) {
565 return false;
566 }
567 }
568 return true;
569 }
570
571 /**
572 * Inner entry type for testing.
573 * @param <K>
574 * @param <V>
575 */
576 private class InnerEntry<K, V> implements Map.Entry<K, V> {
577 private K key;
578 private V value;
579 public InnerEntry(K key, V value) {
580 this.key = key;
581 this.value = value;
582 }
583
584 @Override
585 public K getKey() {
586 return key;
587 }
588
589 @Override
590 public V getValue() {
591 return value;
592 }
593
594 @Override
595 public V setValue(V value) {
596 V temp = this.value;
597 this.value = value;
598 return temp;
599 }
600
601 @Override
602 public boolean equals(Object o) {
603 if (!(o instanceof InnerEntry)) {
604 return false;
605 }
606 InnerEntry other = (InnerEntry) o;
607 boolean keysEqual = false;
608 boolean valuesEqual = false;
609 if (this.key instanceof byte[]) {
610 if (other.getKey() instanceof byte[]) {
611 keysEqual = Arrays.equals((byte[]) this.key,
612 (byte[]) other.getKey());
613 } else {
614 return false;
615 }
616 } else {
617 keysEqual = this.getKey().equals(other.getKey());
618 }
619
620 if (keysEqual) {
621 if (this.value instanceof byte[]) {
622 if (other.getValue() instanceof byte[]) {
623 return Arrays.equals((byte[]) this.value,
624 (byte[]) other.getValue());
625 } else {
626 return false;
627 }
628 } else {
629 return this.key.equals(other.getKey());
630 }
631 }
632 return false;
633 }
634
635 @Override
636 public int hashCode() {
637 return 0;
638 }
639 }
Ray Milkey88cc3432017-03-30 17:19:08 -0700640}