blob: acb79254c802ab90620695c9b722e9153c7a8d9f [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;
Aaron Kruglikov3e29f662016-07-13 10:18:10 -070021import java.util.concurrent.ArrayBlockingQueue;
22import java.util.concurrent.BlockingQueue;
23import java.util.stream.Collectors;
24
Jordan Halterman2bf177c2017-06-29 01:49:08 -070025import com.google.common.base.Throwables;
26import com.google.common.collect.Lists;
27import io.atomix.protocols.raft.proxy.RaftProxy;
28import io.atomix.protocols.raft.service.RaftService;
29import org.junit.Test;
30import org.onlab.util.Tools;
31import org.onosproject.store.service.MapEvent;
32import org.onosproject.store.service.MapEventListener;
33
Aaron Kruglikov3e29f662016-07-13 10:18:10 -070034import static org.junit.Assert.assertArrayEquals;
35import static org.junit.Assert.assertEquals;
36import static org.junit.Assert.assertFalse;
Jordan Haltermanf6272442017-04-20 02:18:08 -070037import static org.junit.Assert.assertNotEquals;
Aaron Kruglikov3e29f662016-07-13 10:18:10 -070038import static org.junit.Assert.assertNotNull;
39import static org.junit.Assert.assertNull;
40import static org.junit.Assert.assertTrue;
41
42/**
43 * Unit tests for {@link AtomixConsistentTreeMap}.
44 */
Jordan Halterman2bf177c2017-06-29 01:49:08 -070045public class AtomixConsistentTreeMapTest extends AtomixTestBase<AtomixConsistentTreeMap> {
Aaron Kruglikov3e29f662016-07-13 10:18:10 -070046 private final String keyFour = "hello";
47 private final String keyThree = "goodbye";
48 private final String keyTwo = "foo";
49 private final String keyOne = "bar";
50 private final byte[] valueOne = Tools.getBytesUtf8(keyOne);
51 private final byte[] valueTwo = Tools.getBytesUtf8(keyTwo);
52 private final byte[] valueThree = Tools.getBytesUtf8(keyThree);
53 private final byte[] valueFour = Tools.getBytesUtf8(keyFour);
54 private final byte[] spareValue = Tools.getBytesUtf8("spareValue");
55 private final List<String> allKeys = Lists.newArrayList(keyOne, keyTwo,
56 keyThree, keyFour);
57 private final List<byte[]> allValues = Lists.newArrayList(valueOne,
58 valueTwo,
59 valueThree,
60 valueFour);
Aaron Kruglikov3e29f662016-07-13 10:18:10 -070061
Jordan Halterman2bf177c2017-06-29 01:49:08 -070062 @Override
63 protected RaftService createService() {
64 return new AtomixConsistentTreeMapService();
Aaron Kruglikov3e29f662016-07-13 10:18:10 -070065 }
66
67 @Override
Jordan Halterman2bf177c2017-06-29 01:49:08 -070068 protected AtomixConsistentTreeMap createPrimitive(RaftProxy proxy) {
69 return new AtomixConsistentTreeMap(proxy);
Aaron Kruglikov3e29f662016-07-13 10:18:10 -070070 }
71
72 /**
73 * Tests of the functionality associated with the
74 * {@link org.onosproject.store.service.AsyncConsistentMap} interface
75 * except transactions and listeners.
76 */
77 @Test
78 public void testBasicMapOperations() throws Throwable {
79 //Throughout the test there are isEmpty queries, these are intended to
80 //make sure that the previous section has been cleaned up, they serve
81 //the secondary purpose of testing isEmpty but that is not their
82 //primary purpose.
83 AtomixConsistentTreeMap map = createResource("basicTestMap");
84 //test size
85 map.size().thenAccept(result -> assertEquals(0, (int) result)).join();
86 map.isEmpty().thenAccept(result -> assertTrue(result)).join();
Jordan Haltermanf6272442017-04-20 02:18:08 -070087
Aaron Kruglikov3e29f662016-07-13 10:18:10 -070088 //test contains key
89 allKeys.forEach(key -> map.containsKey(key).
90 thenAccept(result -> assertFalse(result)).join());
Jordan Haltermanf6272442017-04-20 02:18:08 -070091
Aaron Kruglikov3e29f662016-07-13 10:18:10 -070092 //test contains value
93 allValues.forEach(value -> map.containsValue(value)
94 .thenAccept(result -> assertFalse(result)).join());
Jordan Haltermanf6272442017-04-20 02:18:08 -070095
Aaron Kruglikov3e29f662016-07-13 10:18:10 -070096 //test get
97 allKeys.forEach(key -> map.get(key).
98 thenAccept(result -> assertNull(result)).join());
99
Jordan Haltermanf6272442017-04-20 02:18:08 -0700100 //test getOrDefault
101 allKeys.forEach(key -> map.getOrDefault(key, null).thenAccept(result -> {
102 assertEquals(0, result.version());
103 assertNull(result.value());
104 }).join());
105
106 allKeys.forEach(key -> map.getOrDefault(key, "bar".getBytes()).thenAccept(result -> {
107 assertEquals(0, result.version());
108 assertArrayEquals("bar".getBytes(), result.value());
109 }).join());
110
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700111 //populate and redo prior three tests
Jordan Haltermanf6272442017-04-20 02:18:08 -0700112 allKeys.forEach(key -> map.put(key, allValues.get(allKeys.indexOf(key)))
113 .thenAccept(result -> assertNull(result)).join());
114
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700115 //test contains key
Jordan Haltermanf6272442017-04-20 02:18:08 -0700116 allKeys.forEach(key -> map.containsKey(key)
117 .thenAccept(result -> assertTrue(result)).join());
118
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700119 //test contains value
120 allValues.forEach(value -> map.containsValue(value)
121 .thenAccept(result -> assertTrue(result)).join());
Jordan Haltermanf6272442017-04-20 02:18:08 -0700122
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700123 //test get
Jordan Haltermanf6272442017-04-20 02:18:08 -0700124 allKeys.forEach(key -> map.get(key).thenAccept(result -> {
125 assertArrayEquals(allValues.get(allKeys.indexOf(key)), result.value());
126 }).join());
127
128 allKeys.forEach(key -> map.getOrDefault(key, null).thenAccept(result -> {
129 assertNotEquals(0, result.version());
130 assertArrayEquals(allValues.get(allKeys.indexOf(key)), result.value());
131 }).join());
132
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700133 //test all compute methods in this section
Jordan Haltermanf6272442017-04-20 02:18:08 -0700134 allKeys.forEach(key -> map.computeIfAbsent(key, v -> allValues.get(allKeys.indexOf(key)))
135 .thenAccept(result -> {
136 assertArrayEquals(allValues.get(allKeys.indexOf(key)), result.value());
137 }).join());
138
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700139 map.size().thenAccept(result -> assertEquals(4, (int) result)).join();
140 map.isEmpty().thenAccept(result -> assertFalse(result)).join();
Jordan Haltermanf6272442017-04-20 02:18:08 -0700141
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700142 allKeys.forEach(key -> map.computeIfPresent(key, (k, v) -> null).
143 thenAccept(result -> assertNull(result)).join());
Jordan Haltermanf6272442017-04-20 02:18:08 -0700144
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700145 map.isEmpty().thenAccept(result -> assertTrue(result)).join();
Jordan Haltermanf6272442017-04-20 02:18:08 -0700146
147 allKeys.forEach(key -> map.compute(key, (k, v) -> allValues.get(allKeys.indexOf(key)))
148 .thenAccept(result -> assertArrayEquals(allValues.get(allKeys.indexOf(key)), result.value())).join());
149
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700150 map.size().thenAccept(result -> assertEquals(4, (int) result)).join();
151 map.isEmpty().thenAccept(result -> assertFalse(result)).join();
Jordan Haltermanf6272442017-04-20 02:18:08 -0700152
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700153 allKeys.forEach(key -> map.computeIf(key,
Jordan Haltermanf6272442017-04-20 02:18:08 -0700154 (k) -> allKeys.indexOf(key) < 2, (k, v) -> null).thenAccept(result -> {
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700155 if (allKeys.indexOf(key) < 2) {
156 assertNull(result);
157 } else {
Jordan Haltermanf6272442017-04-20 02:18:08 -0700158 assertArrayEquals(allValues.get(allKeys.indexOf(key)), result.value());
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700159 }
Jordan Haltermanf6272442017-04-20 02:18:08 -0700160 }).join());
161
162 map.size().thenAccept(result -> assertEquals(2, (int) result)).join();
163 map.isEmpty().thenAccept(result -> assertFalse(result)).join();
164
165 //test simple put
166 allKeys.forEach(key -> map.put(key, allValues.get(allKeys.indexOf(key))).thenAccept(result -> {
167 if (allKeys.indexOf(key) < 2) {
168 assertNull(result);
169 } else {
170 assertArrayEquals(allValues.get(allKeys.indexOf(key)), result.value());
171 }
172 }).join());
173
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700174 map.size().thenAccept(result -> assertEquals(4, (int) result)).join();
175 map.isEmpty().thenAccept(result -> assertFalse(result)).join();
Jordan Haltermanf6272442017-04-20 02:18:08 -0700176
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700177 //test put and get for version retrieval
Jordan Haltermanf6272442017-04-20 02:18:08 -0700178 allKeys.forEach(key -> map.putAndGet(key, allValues.get(allKeys.indexOf(key))).thenAccept(firstResult -> {
179 map.putAndGet(key, allValues.get(allKeys.indexOf(key))).thenAccept(secondResult -> {
180 assertArrayEquals(allValues.get(allKeys.indexOf(key)), firstResult.value());
181 assertArrayEquals(allValues.get(allKeys.indexOf(key)), secondResult.value());
Jordan Haltermanf6272442017-04-20 02:18:08 -0700182 });
183 }).join());
184
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700185 //test removal
186 allKeys.forEach(key -> map.remove(key).thenAccept(
187 result -> assertArrayEquals(
188 allValues.get(allKeys.indexOf(key)), result.value()))
189 .join());
190 map.isEmpty().thenAccept(result -> assertTrue(result));
Jordan Haltermanf6272442017-04-20 02:18:08 -0700191
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700192 //repopulating, this is not mainly for testing
Jordan Haltermanf6272442017-04-20 02:18:08 -0700193 allKeys.forEach(key -> map.put(key, allValues.get(allKeys.indexOf(key))).thenAccept(result -> {
194 assertNull(result);
195 }).join());
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700196
197 //Test various collections of keys, values and entries
Jordan Haltermanf6272442017-04-20 02:18:08 -0700198 map.keySet().thenAccept(keys -> assertTrue(stringArrayCollectionIsEqual(keys, allKeys))).join();
199 map.values().thenAccept(values -> assertTrue(
200 byteArrayCollectionIsEqual(values.stream().map(v -> v.value())
201 .collect(Collectors.toSet()), allValues))).join();
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700202 map.entrySet().thenAccept(entrySet -> {
203 entrySet.forEach(entry -> {
204 assertTrue(allKeys.contains(entry.getKey()));
205 assertTrue(Arrays.equals(entry.getValue().value(),
206 allValues.get(allKeys.indexOf(entry.getKey()))));
207 });
208 }).join();
209 map.clear().join();
210 map.isEmpty().thenAccept(result -> assertTrue(result)).join();
211
212 //test conditional put
Jordan Haltermanf6272442017-04-20 02:18:08 -0700213 allKeys.forEach(key -> map.putIfAbsent(key, allValues.get(allKeys.indexOf(key)))
214 .thenAccept(result -> assertNull(result)).join());
215 allKeys.forEach(key -> map.putIfAbsent(key, null).thenAccept(result ->
216 assertArrayEquals(result.value(), allValues.get(allKeys.indexOf(key)))
217 ).join());
218
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700219 // test alternate removes that specify value or version
Jordan Haltermanf6272442017-04-20 02:18:08 -0700220 allKeys.forEach(key -> map.remove(key, spareValue).thenAccept(result -> assertFalse(result)).join());
221 allKeys.forEach(key -> map.remove(key, allValues.get(allKeys.indexOf(key)))
222 .thenAccept(result -> assertTrue(result)).join());
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700223 map.isEmpty().thenAccept(result -> assertTrue(result)).join();
224 List<Long> versions = Lists.newArrayList();
225
226 //repopulating set for version based removal
Jordan Haltermanf6272442017-04-20 02:18:08 -0700227 allKeys.forEach(key -> map.putAndGet(key, allValues.get(allKeys.indexOf(key)))
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700228 .thenAccept(result -> versions.add(result.version())).join());
Jordan Haltermanf6272442017-04-20 02:18:08 -0700229 allKeys.forEach(key -> map.remove(key, versions.get(0)).thenAccept(result -> {
230 assertTrue(result);
231 versions.remove(0);
232 }).join());
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700233 map.isEmpty().thenAccept(result -> assertTrue(result)).join();
Jordan Haltermanf6272442017-04-20 02:18:08 -0700234
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700235 //Testing all replace both simple (k, v), and complex that consider
236 // previous mapping or version.
Jordan Haltermanf6272442017-04-20 02:18:08 -0700237 allKeys.forEach(key -> map.put(key, allValues.get(allKeys.indexOf(key)))
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700238 .thenAccept(result -> assertNull(result)).join());
Jordan Haltermanf6272442017-04-20 02:18:08 -0700239 allKeys.forEach(key -> map.replace(key, allValues.get(3 - allKeys.indexOf(key)))
240 .thenAccept(result -> assertArrayEquals(allValues.get(allKeys.indexOf(key)), result.value()))
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700241 .join());
Jordan Haltermanf6272442017-04-20 02:18:08 -0700242 allKeys.forEach(key -> map.replace(key, spareValue, allValues.get(allKeys.indexOf(key)))
243 .thenAccept(result -> assertFalse(result)).join());
244 allKeys.forEach(key -> map.replace(key, allValues.get(3 - allKeys.indexOf(key)),
245 allValues.get(allKeys.indexOf(key))).thenAccept(result -> assertTrue(result)).join());
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700246 map.clear().join();
247 map.isEmpty().thenAccept(result -> assertTrue(result)).join();
248 versions.clear();
Jordan Haltermanf6272442017-04-20 02:18:08 -0700249
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700250 //populate for version based replacement
Jordan Haltermanf6272442017-04-20 02:18:08 -0700251 allKeys.forEach(key -> map.putAndGet(key, allValues.get(3 - allKeys.indexOf(key)))
252 .thenAccept(result -> versions.add(result.version())).join());
253 allKeys.forEach(key -> map.replace(key, 0, allValues.get(allKeys.indexOf(key)))
254 .thenAccept(result -> assertFalse(result)).join());
255 allKeys.forEach(key -> map.replace(key, versions.get(0), allValues.get(allKeys.indexOf(key)))
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700256 .thenAccept(result -> {
257 assertTrue(result);
258 versions.remove(0);
259 }).join());
260 }
261
262 @Test
263 public void mapListenerTests() throws Throwable {
264 final byte[] value1 = Tools.getBytesUtf8("value1");
265 final byte[] value2 = Tools.getBytesUtf8("value2");
266 final byte[] value3 = Tools.getBytesUtf8("value3");
267
268 AtomixConsistentTreeMap map = createResource("treeMapListenerTestMap");
269 TestMapEventListener listener = new TestMapEventListener();
270
271 // add listener; insert new value into map and verify an INSERT event
272 // is received.
273 map.addListener(listener).thenCompose(v -> map.put("foo", value1))
274 .join();
275 MapEvent<String, byte[]> event = listener.event();
276 assertNotNull(event);
277 assertEquals(MapEvent.Type.INSERT, event.type());
278 assertTrue(Arrays.equals(value1, event.newValue().value()));
279
280 // remove listener and verify listener is not notified.
281 map.removeListener(listener).thenCompose(v -> map.put("foo", value2))
282 .join();
283 assertFalse(listener.eventReceived());
284
285 // add the listener back and verify UPDATE events are received
286 // correctly
287 map.addListener(listener).thenCompose(v -> map.put("foo", value3))
288 .join();
289 event = listener.event();
290 assertNotNull(event);
291 assertEquals(MapEvent.Type.UPDATE, event.type());
292 assertTrue(Arrays.equals(value3, event.newValue().value()));
293
294 // perform a non-state changing operation and verify no events are
295 // received.
296 map.putIfAbsent("foo", value1).join();
297 assertFalse(listener.eventReceived());
298
299 // verify REMOVE events are received correctly.
300 map.remove("foo").join();
301 event = listener.event();
302 assertNotNull(event);
303 assertEquals(MapEvent.Type.REMOVE, event.type());
304 assertTrue(Arrays.equals(value3, event.oldValue().value()));
305
306 // verify compute methods also generate events.
307 map.computeIf("foo", v -> v == null, (k, v) -> value1).join();
308 event = listener.event();
309 assertNotNull(event);
310 assertEquals(MapEvent.Type.INSERT, event.type());
311 assertTrue(Arrays.equals(value1, event.newValue().value()));
312
313 map.compute("foo", (k, v) -> value2).join();
314 event = listener.event();
315 assertNotNull(event);
316 assertEquals(MapEvent.Type.UPDATE, event.type());
317 assertTrue(Arrays.equals(value2, event.newValue().value()));
318
319 map.computeIf(
320 "foo", v -> Arrays.equals(v, value2), (k, v) -> null).join();
321 event = listener.event();
322 assertNotNull(event);
323 assertEquals(MapEvent.Type.REMOVE, event.type());
324 assertTrue(Arrays.equals(value2, event.oldValue().value()));
325
326 map.removeListener(listener).join();
327 }
328
329 /**
330 * Tests functionality specified in the {@link AtomixConsistentTreeMap}
331 * interface, beyond the functionality provided in
332 * {@link org.onosproject.store.service.AsyncConsistentMap}.
333 */
334 @Test
335 public void treeMapFunctionsTest() {
336 AtomixConsistentTreeMap map = createResource("treeMapFunctionTestMap");
337 //Tests on empty map
338 map.firstKey().thenAccept(result -> assertNull(result)).join();
339 map.lastKey().thenAccept(result -> assertNull(result)).join();
340 map.ceilingEntry(keyOne).thenAccept(result -> assertNull(result))
341 .join();
342 map.floorEntry(keyOne).thenAccept(result -> assertNull(result)).join();
343 map.higherEntry(keyOne).thenAccept(result -> assertNull(result))
344 .join();
345 map.lowerEntry(keyOne).thenAccept(result -> assertNull(result)).join();
346 map.firstEntry().thenAccept(result -> assertNull(result)).join();
347 map.lastEntry().thenAccept(result -> assertNull(result)).join();
348 map.pollFirstEntry().thenAccept(result -> assertNull(result)).join();
349 map.pollLastEntry().thenAccept(result -> assertNull(result)).join();
350 map.lowerKey(keyOne).thenAccept(result -> assertNull(result)).join();
351 map.floorKey(keyOne).thenAccept(result -> assertNull(result)).join();
352 map.ceilingKey(keyOne).thenAccept(result -> assertNull(result))
353 .join();
354 map.higherKey(keyOne).thenAccept(result -> assertNull(result)).join();
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700355
356 // TODO: delete() is not supported
357 //map.delete().join();
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700358
359 allKeys.forEach(key -> map.put(
360 key, allValues.get(allKeys.indexOf(key)))
361 .thenAccept(result -> assertNull(result)).join());
362 //Note ordering keys are in their proper ordering in ascending order
363 //both in naming and in the allKeys list.
364
365 map.firstKey().thenAccept(result -> assertEquals(keyOne, result))
366 .join();
367 map.lastKey().thenAccept(result -> assertEquals(keyFour, result))
368 .join();
369 map.ceilingEntry(keyOne)
370 .thenAccept(result -> {
371 assertEquals(keyOne, result.getKey());
372 assertArrayEquals(valueOne, result.getValue().value());
373 })
374 .join();
375 //adding an additional letter to make keyOne an unacceptable response
376 map.ceilingEntry(keyOne + "a")
377 .thenAccept(result -> {
378 assertEquals(keyTwo, result.getKey());
379 assertArrayEquals(valueTwo, result.getValue().value());
380 })
381 .join();
382 map.ceilingEntry(keyFour + "a")
383 .thenAccept(result -> {
384 assertNull(result);
385 })
386 .join();
387 map.floorEntry(keyTwo).thenAccept(result -> {
388 assertEquals(keyTwo, result.getKey());
389 assertArrayEquals(valueTwo, result.getValue().value());
390 })
391 .join();
392 //shorten the key so it itself is not an acceptable reply
393 map.floorEntry(keyTwo.substring(0, 2)).thenAccept(result -> {
394 assertEquals(keyOne, result.getKey());
395 assertArrayEquals(valueOne, result.getValue().value());
396 })
397 .join();
398 // shorten least key so no acceptable response exists
399 map.floorEntry(keyOne.substring(0, 1)).thenAccept(
400 result -> assertNull(result))
401 .join();
402
403 map.higherEntry(keyTwo).thenAccept(result -> {
404 assertEquals(keyThree, result.getKey());
405 assertArrayEquals(valueThree, result.getValue().value());
406 })
407 .join();
408 map.higherEntry(keyFour).thenAccept(result -> assertNull(result))
409 .join();
410
411 map.lowerEntry(keyFour).thenAccept(result -> {
412 assertEquals(keyThree, result.getKey());
413 assertArrayEquals(valueThree, result.getValue().value());
414 })
415 .join();
416 map.lowerEntry(keyOne).thenAccept(result -> assertNull(result))
417 .join();
418 map.firstEntry().thenAccept(result -> {
419 assertEquals(keyOne, result.getKey());
420 assertArrayEquals(valueOne, result.getValue().value());
421 })
422 .join();
423 map.lastEntry().thenAccept(result -> {
424 assertEquals(keyFour, result.getKey());
425 assertArrayEquals(valueFour, result.getValue().value());
426 })
427 .join();
428 map.pollFirstEntry().thenAccept(result -> {
429 assertEquals(keyOne, result.getKey());
430 assertArrayEquals(valueOne, result.getValue().value());
431 });
432 map.containsKey(keyOne).thenAccept(result -> assertFalse(result))
433 .join();
434 map.size().thenAccept(result -> assertEquals(3, (int) result)).join();
435 map.pollLastEntry().thenAccept(result -> {
436 assertEquals(keyFour, result.getKey());
437 assertArrayEquals(valueFour, result.getValue().value());
438 });
439 map.containsKey(keyFour).thenAccept(result -> assertFalse(result))
440 .join();
441 map.size().thenAccept(result -> assertEquals(2, (int) result)).join();
442
443 //repopulate the missing entries
444 allKeys.forEach(key -> map.put(
445 key, allValues.get(allKeys.indexOf(key)))
446 .thenAccept(result -> {
447 if (key.equals(keyOne) || key.equals(keyFour)) {
448 assertNull(result);
449 } else {
450 assertArrayEquals(allValues.get(allKeys.indexOf(key)),
451 result.value());
452 }
453 })
454 .join());
455 map.lowerKey(keyOne).thenAccept(result -> assertNull(result)).join();
456 map.lowerKey(keyThree).thenAccept(
457 result -> assertEquals(keyTwo, result))
458 .join();
459 map.floorKey(keyThree).thenAccept(
460 result -> assertEquals(keyThree, result))
461 .join();
462 //shortening the key so there is no acceptable response
463 map.floorKey(keyOne.substring(0, 1)).thenAccept(
464 result -> assertNull(result))
465 .join();
466 map.ceilingKey(keyTwo).thenAccept(
467 result -> assertEquals(keyTwo, result))
468 .join();
469 //adding to highest key so there is no acceptable response
470 map.ceilingKey(keyFour + "a")
471 .thenAccept(reslt -> assertNull(reslt))
472 .join();
473 map.higherKey(keyThree).thenAccept(
474 result -> assertEquals(keyFour, result))
475 .join();
476 map.higherKey(keyFour).thenAccept(
477 result -> assertNull(result))
478 .join();
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700479
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700480 // TODO: delete() is not supported
481 //map.delete().join();
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700482 }
483
484 private AtomixConsistentTreeMap createResource(String mapName) {
485 try {
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700486 AtomixConsistentTreeMap map = newPrimitive(mapName);
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700487 return map;
488 } catch (Throwable e) {
489 throw new RuntimeException(e.toString());
490 }
491 }
492 private static class TestMapEventListener
493 implements MapEventListener<String, byte[]> {
494
495 private final BlockingQueue<MapEvent<String, byte[]>> queue =
496 new ArrayBlockingQueue<>(1);
497
498 @Override
499 public void event(MapEvent<String, byte[]> event) {
500 try {
501 queue.put(event);
502 } catch (InterruptedException e) {
503 Throwables.propagate(e);
504 }
505 }
506
507 public boolean eventReceived() {
508 return !queue.isEmpty();
509 }
510
511 public MapEvent<String, byte[]> event() throws InterruptedException {
512 return queue.take();
513 }
514 }
515
516 /**
517 * Returns two arrays contain the same set of elements,
518 * regardless of order.
519 * @param o1 first collection
520 * @param o2 second collection
521 * @return true if they contain the same elements
522 */
523 private boolean byteArrayCollectionIsEqual(
524 Collection<? extends byte[]> o1, Collection<? extends byte[]> o2) {
525 if (o1 == null || o2 == null || o1.size() != o2.size()) {
526 return false;
527 }
528 for (byte[] array1 : o1) {
529 boolean matched = false;
530 for (byte[] array2 : o2) {
531 if (Arrays.equals(array1, array2)) {
532 matched = true;
533 break;
534 }
535 }
536 if (!matched) {
537 return false;
538 }
539 }
540 return true;
541 }
542
543 /**
544 * Compares two collections of strings returns true if they contain the
545 * same strings, false otherwise.
546 * @param s1 string collection one
547 * @param s2 string collection two
548 * @return true if the two sets contain the same strings
549 */
550 private boolean stringArrayCollectionIsEqual(
551 Collection<? extends String> s1, Collection<? extends String> s2) {
552 if (s1 == null || s2 == null || s1.size() != s2.size()) {
553 return false;
554 }
555 for (String string1 : s1) {
556 boolean matched = false;
557 for (String string2 : s2) {
558 if (string1.equals(string2)) {
559 matched = true;
560 break;
561 }
562 }
563 if (!matched) {
564 return false;
565 }
566 }
567 return true;
568 }
Ray Milkey88cc3432017-03-30 17:19:08 -0700569}