blob: f1de625ca7ef603f7977615d1d34bbc1be02cbb0 [file] [log] [blame]
Aaron Kruglikov3e29f662016-07-13 10:18:10 -07001/*
Brian O'Connor0a4e6742016-09-15 23:03:10 -07002 * Copyright 2016-present Open Networking Laboratory
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());
183 assertTrue((firstResult.version() + 1) == secondResult.version());
184 });
185 }).join());
186
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700187 //test removal
188 allKeys.forEach(key -> map.remove(key).thenAccept(
189 result -> assertArrayEquals(
190 allValues.get(allKeys.indexOf(key)), result.value()))
191 .join());
192 map.isEmpty().thenAccept(result -> assertTrue(result));
Jordan Haltermanf6272442017-04-20 02:18:08 -0700193
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700194 //repopulating, this is not mainly for testing
Jordan Haltermanf6272442017-04-20 02:18:08 -0700195 allKeys.forEach(key -> map.put(key, allValues.get(allKeys.indexOf(key))).thenAccept(result -> {
196 assertNull(result);
197 }).join());
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700198
199 //Test various collections of keys, values and entries
Jordan Haltermanf6272442017-04-20 02:18:08 -0700200 map.keySet().thenAccept(keys -> assertTrue(stringArrayCollectionIsEqual(keys, allKeys))).join();
201 map.values().thenAccept(values -> assertTrue(
202 byteArrayCollectionIsEqual(values.stream().map(v -> v.value())
203 .collect(Collectors.toSet()), allValues))).join();
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700204 map.entrySet().thenAccept(entrySet -> {
205 entrySet.forEach(entry -> {
206 assertTrue(allKeys.contains(entry.getKey()));
207 assertTrue(Arrays.equals(entry.getValue().value(),
208 allValues.get(allKeys.indexOf(entry.getKey()))));
209 });
210 }).join();
211 map.clear().join();
212 map.isEmpty().thenAccept(result -> assertTrue(result)).join();
213
214 //test conditional put
Jordan Haltermanf6272442017-04-20 02:18:08 -0700215 allKeys.forEach(key -> map.putIfAbsent(key, allValues.get(allKeys.indexOf(key)))
216 .thenAccept(result -> assertNull(result)).join());
217 allKeys.forEach(key -> map.putIfAbsent(key, null).thenAccept(result ->
218 assertArrayEquals(result.value(), allValues.get(allKeys.indexOf(key)))
219 ).join());
220
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700221 // test alternate removes that specify value or version
Jordan Haltermanf6272442017-04-20 02:18:08 -0700222 allKeys.forEach(key -> map.remove(key, spareValue).thenAccept(result -> assertFalse(result)).join());
223 allKeys.forEach(key -> map.remove(key, allValues.get(allKeys.indexOf(key)))
224 .thenAccept(result -> assertTrue(result)).join());
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700225 map.isEmpty().thenAccept(result -> assertTrue(result)).join();
226 List<Long> versions = Lists.newArrayList();
227
228 //repopulating set for version based removal
Jordan Haltermanf6272442017-04-20 02:18:08 -0700229 allKeys.forEach(key -> map.putAndGet(key, allValues.get(allKeys.indexOf(key)))
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700230 .thenAccept(result -> versions.add(result.version())).join());
Jordan Haltermanf6272442017-04-20 02:18:08 -0700231 allKeys.forEach(key -> map.remove(key, versions.get(0)).thenAccept(result -> {
232 assertTrue(result);
233 versions.remove(0);
234 }).join());
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700235 map.isEmpty().thenAccept(result -> assertTrue(result)).join();
Jordan Haltermanf6272442017-04-20 02:18:08 -0700236
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700237 //Testing all replace both simple (k, v), and complex that consider
238 // previous mapping or version.
Jordan Haltermanf6272442017-04-20 02:18:08 -0700239 allKeys.forEach(key -> map.put(key, allValues.get(allKeys.indexOf(key)))
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700240 .thenAccept(result -> assertNull(result)).join());
Jordan Haltermanf6272442017-04-20 02:18:08 -0700241 allKeys.forEach(key -> map.replace(key, allValues.get(3 - allKeys.indexOf(key)))
242 .thenAccept(result -> assertArrayEquals(allValues.get(allKeys.indexOf(key)), result.value()))
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700243 .join());
Jordan Haltermanf6272442017-04-20 02:18:08 -0700244 allKeys.forEach(key -> map.replace(key, spareValue, allValues.get(allKeys.indexOf(key)))
245 .thenAccept(result -> assertFalse(result)).join());
246 allKeys.forEach(key -> map.replace(key, allValues.get(3 - allKeys.indexOf(key)),
247 allValues.get(allKeys.indexOf(key))).thenAccept(result -> assertTrue(result)).join());
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700248 map.clear().join();
249 map.isEmpty().thenAccept(result -> assertTrue(result)).join();
250 versions.clear();
Jordan Haltermanf6272442017-04-20 02:18:08 -0700251
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700252 //populate for version based replacement
Jordan Haltermanf6272442017-04-20 02:18:08 -0700253 allKeys.forEach(key -> map.putAndGet(key, allValues.get(3 - allKeys.indexOf(key)))
254 .thenAccept(result -> versions.add(result.version())).join());
255 allKeys.forEach(key -> map.replace(key, 0, allValues.get(allKeys.indexOf(key)))
256 .thenAccept(result -> assertFalse(result)).join());
257 allKeys.forEach(key -> map.replace(key, versions.get(0), allValues.get(allKeys.indexOf(key)))
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700258 .thenAccept(result -> {
259 assertTrue(result);
260 versions.remove(0);
261 }).join());
262 }
263
264 @Test
265 public void mapListenerTests() throws Throwable {
266 final byte[] value1 = Tools.getBytesUtf8("value1");
267 final byte[] value2 = Tools.getBytesUtf8("value2");
268 final byte[] value3 = Tools.getBytesUtf8("value3");
269
270 AtomixConsistentTreeMap map = createResource("treeMapListenerTestMap");
271 TestMapEventListener listener = new TestMapEventListener();
272
273 // add listener; insert new value into map and verify an INSERT event
274 // is received.
275 map.addListener(listener).thenCompose(v -> map.put("foo", value1))
276 .join();
277 MapEvent<String, byte[]> event = listener.event();
278 assertNotNull(event);
279 assertEquals(MapEvent.Type.INSERT, event.type());
280 assertTrue(Arrays.equals(value1, event.newValue().value()));
281
282 // remove listener and verify listener is not notified.
283 map.removeListener(listener).thenCompose(v -> map.put("foo", value2))
284 .join();
285 assertFalse(listener.eventReceived());
286
287 // add the listener back and verify UPDATE events are received
288 // correctly
289 map.addListener(listener).thenCompose(v -> map.put("foo", value3))
290 .join();
291 event = listener.event();
292 assertNotNull(event);
293 assertEquals(MapEvent.Type.UPDATE, event.type());
294 assertTrue(Arrays.equals(value3, event.newValue().value()));
295
296 // perform a non-state changing operation and verify no events are
297 // received.
298 map.putIfAbsent("foo", value1).join();
299 assertFalse(listener.eventReceived());
300
301 // verify REMOVE events are received correctly.
302 map.remove("foo").join();
303 event = listener.event();
304 assertNotNull(event);
305 assertEquals(MapEvent.Type.REMOVE, event.type());
306 assertTrue(Arrays.equals(value3, event.oldValue().value()));
307
308 // verify compute methods also generate events.
309 map.computeIf("foo", v -> v == null, (k, v) -> value1).join();
310 event = listener.event();
311 assertNotNull(event);
312 assertEquals(MapEvent.Type.INSERT, event.type());
313 assertTrue(Arrays.equals(value1, event.newValue().value()));
314
315 map.compute("foo", (k, v) -> value2).join();
316 event = listener.event();
317 assertNotNull(event);
318 assertEquals(MapEvent.Type.UPDATE, event.type());
319 assertTrue(Arrays.equals(value2, event.newValue().value()));
320
321 map.computeIf(
322 "foo", v -> Arrays.equals(v, value2), (k, v) -> null).join();
323 event = listener.event();
324 assertNotNull(event);
325 assertEquals(MapEvent.Type.REMOVE, event.type());
326 assertTrue(Arrays.equals(value2, event.oldValue().value()));
327
328 map.removeListener(listener).join();
329 }
330
331 /**
332 * Tests functionality specified in the {@link AtomixConsistentTreeMap}
333 * interface, beyond the functionality provided in
334 * {@link org.onosproject.store.service.AsyncConsistentMap}.
335 */
336 @Test
337 public void treeMapFunctionsTest() {
338 AtomixConsistentTreeMap map = createResource("treeMapFunctionTestMap");
339 //Tests on empty map
340 map.firstKey().thenAccept(result -> assertNull(result)).join();
341 map.lastKey().thenAccept(result -> assertNull(result)).join();
342 map.ceilingEntry(keyOne).thenAccept(result -> assertNull(result))
343 .join();
344 map.floorEntry(keyOne).thenAccept(result -> assertNull(result)).join();
345 map.higherEntry(keyOne).thenAccept(result -> assertNull(result))
346 .join();
347 map.lowerEntry(keyOne).thenAccept(result -> assertNull(result)).join();
348 map.firstEntry().thenAccept(result -> assertNull(result)).join();
349 map.lastEntry().thenAccept(result -> assertNull(result)).join();
350 map.pollFirstEntry().thenAccept(result -> assertNull(result)).join();
351 map.pollLastEntry().thenAccept(result -> assertNull(result)).join();
352 map.lowerKey(keyOne).thenAccept(result -> assertNull(result)).join();
353 map.floorKey(keyOne).thenAccept(result -> assertNull(result)).join();
354 map.ceilingKey(keyOne).thenAccept(result -> assertNull(result))
355 .join();
356 map.higherKey(keyOne).thenAccept(result -> assertNull(result)).join();
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700357
358 // TODO: delete() is not supported
359 //map.delete().join();
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700360
361 allKeys.forEach(key -> map.put(
362 key, allValues.get(allKeys.indexOf(key)))
363 .thenAccept(result -> assertNull(result)).join());
364 //Note ordering keys are in their proper ordering in ascending order
365 //both in naming and in the allKeys list.
366
367 map.firstKey().thenAccept(result -> assertEquals(keyOne, result))
368 .join();
369 map.lastKey().thenAccept(result -> assertEquals(keyFour, result))
370 .join();
371 map.ceilingEntry(keyOne)
372 .thenAccept(result -> {
373 assertEquals(keyOne, result.getKey());
374 assertArrayEquals(valueOne, result.getValue().value());
375 })
376 .join();
377 //adding an additional letter to make keyOne an unacceptable response
378 map.ceilingEntry(keyOne + "a")
379 .thenAccept(result -> {
380 assertEquals(keyTwo, result.getKey());
381 assertArrayEquals(valueTwo, result.getValue().value());
382 })
383 .join();
384 map.ceilingEntry(keyFour + "a")
385 .thenAccept(result -> {
386 assertNull(result);
387 })
388 .join();
389 map.floorEntry(keyTwo).thenAccept(result -> {
390 assertEquals(keyTwo, result.getKey());
391 assertArrayEquals(valueTwo, result.getValue().value());
392 })
393 .join();
394 //shorten the key so it itself is not an acceptable reply
395 map.floorEntry(keyTwo.substring(0, 2)).thenAccept(result -> {
396 assertEquals(keyOne, result.getKey());
397 assertArrayEquals(valueOne, result.getValue().value());
398 })
399 .join();
400 // shorten least key so no acceptable response exists
401 map.floorEntry(keyOne.substring(0, 1)).thenAccept(
402 result -> assertNull(result))
403 .join();
404
405 map.higherEntry(keyTwo).thenAccept(result -> {
406 assertEquals(keyThree, result.getKey());
407 assertArrayEquals(valueThree, result.getValue().value());
408 })
409 .join();
410 map.higherEntry(keyFour).thenAccept(result -> assertNull(result))
411 .join();
412
413 map.lowerEntry(keyFour).thenAccept(result -> {
414 assertEquals(keyThree, result.getKey());
415 assertArrayEquals(valueThree, result.getValue().value());
416 })
417 .join();
418 map.lowerEntry(keyOne).thenAccept(result -> assertNull(result))
419 .join();
420 map.firstEntry().thenAccept(result -> {
421 assertEquals(keyOne, result.getKey());
422 assertArrayEquals(valueOne, result.getValue().value());
423 })
424 .join();
425 map.lastEntry().thenAccept(result -> {
426 assertEquals(keyFour, result.getKey());
427 assertArrayEquals(valueFour, result.getValue().value());
428 })
429 .join();
430 map.pollFirstEntry().thenAccept(result -> {
431 assertEquals(keyOne, result.getKey());
432 assertArrayEquals(valueOne, result.getValue().value());
433 });
434 map.containsKey(keyOne).thenAccept(result -> assertFalse(result))
435 .join();
436 map.size().thenAccept(result -> assertEquals(3, (int) result)).join();
437 map.pollLastEntry().thenAccept(result -> {
438 assertEquals(keyFour, result.getKey());
439 assertArrayEquals(valueFour, result.getValue().value());
440 });
441 map.containsKey(keyFour).thenAccept(result -> assertFalse(result))
442 .join();
443 map.size().thenAccept(result -> assertEquals(2, (int) result)).join();
444
445 //repopulate the missing entries
446 allKeys.forEach(key -> map.put(
447 key, allValues.get(allKeys.indexOf(key)))
448 .thenAccept(result -> {
449 if (key.equals(keyOne) || key.equals(keyFour)) {
450 assertNull(result);
451 } else {
452 assertArrayEquals(allValues.get(allKeys.indexOf(key)),
453 result.value());
454 }
455 })
456 .join());
457 map.lowerKey(keyOne).thenAccept(result -> assertNull(result)).join();
458 map.lowerKey(keyThree).thenAccept(
459 result -> assertEquals(keyTwo, result))
460 .join();
461 map.floorKey(keyThree).thenAccept(
462 result -> assertEquals(keyThree, result))
463 .join();
464 //shortening the key so there is no acceptable response
465 map.floorKey(keyOne.substring(0, 1)).thenAccept(
466 result -> assertNull(result))
467 .join();
468 map.ceilingKey(keyTwo).thenAccept(
469 result -> assertEquals(keyTwo, result))
470 .join();
471 //adding to highest key so there is no acceptable response
472 map.ceilingKey(keyFour + "a")
473 .thenAccept(reslt -> assertNull(reslt))
474 .join();
475 map.higherKey(keyThree).thenAccept(
476 result -> assertEquals(keyFour, result))
477 .join();
478 map.higherKey(keyFour).thenAccept(
479 result -> assertNull(result))
480 .join();
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700481
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700482 // TODO: delete() is not supported
483 //map.delete().join();
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700484 }
485
486 private AtomixConsistentTreeMap createResource(String mapName) {
487 try {
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700488 AtomixConsistentTreeMap map = newPrimitive(mapName);
Aaron Kruglikov3e29f662016-07-13 10:18:10 -0700489 return map;
490 } catch (Throwable e) {
491 throw new RuntimeException(e.toString());
492 }
493 }
494 private static class TestMapEventListener
495 implements MapEventListener<String, byte[]> {
496
497 private final BlockingQueue<MapEvent<String, byte[]>> queue =
498 new ArrayBlockingQueue<>(1);
499
500 @Override
501 public void event(MapEvent<String, byte[]> event) {
502 try {
503 queue.put(event);
504 } catch (InterruptedException e) {
505 Throwables.propagate(e);
506 }
507 }
508
509 public boolean eventReceived() {
510 return !queue.isEmpty();
511 }
512
513 public MapEvent<String, byte[]> event() throws InterruptedException {
514 return queue.take();
515 }
516 }
517
518 /**
519 * Returns two arrays contain the same set of elements,
520 * regardless of order.
521 * @param o1 first collection
522 * @param o2 second collection
523 * @return true if they contain the same elements
524 */
525 private boolean byteArrayCollectionIsEqual(
526 Collection<? extends byte[]> o1, Collection<? extends byte[]> o2) {
527 if (o1 == null || o2 == null || o1.size() != o2.size()) {
528 return false;
529 }
530 for (byte[] array1 : o1) {
531 boolean matched = false;
532 for (byte[] array2 : o2) {
533 if (Arrays.equals(array1, array2)) {
534 matched = true;
535 break;
536 }
537 }
538 if (!matched) {
539 return false;
540 }
541 }
542 return true;
543 }
544
545 /**
546 * Compares two collections of strings returns true if they contain the
547 * same strings, false otherwise.
548 * @param s1 string collection one
549 * @param s2 string collection two
550 * @return true if the two sets contain the same strings
551 */
552 private boolean stringArrayCollectionIsEqual(
553 Collection<? extends String> s1, Collection<? extends String> s2) {
554 if (s1 == null || s2 == null || s1.size() != s2.size()) {
555 return false;
556 }
557 for (String string1 : s1) {
558 boolean matched = false;
559 for (String string2 : s2) {
560 if (string1.equals(string2)) {
561 matched = true;
562 break;
563 }
564 }
565 if (!matched) {
566 return false;
567 }
568 }
569 return true;
570 }
571
572 /**
573 * Inner entry type for testing.
574 * @param <K>
575 * @param <V>
576 */
577 private class InnerEntry<K, V> implements Map.Entry<K, V> {
578 private K key;
579 private V value;
580 public InnerEntry(K key, V value) {
581 this.key = key;
582 this.value = value;
583 }
584
585 @Override
586 public K getKey() {
587 return key;
588 }
589
590 @Override
591 public V getValue() {
592 return value;
593 }
594
595 @Override
596 public V setValue(V value) {
597 V temp = this.value;
598 this.value = value;
599 return temp;
600 }
601
602 @Override
603 public boolean equals(Object o) {
604 if (!(o instanceof InnerEntry)) {
605 return false;
606 }
607 InnerEntry other = (InnerEntry) o;
608 boolean keysEqual = false;
609 boolean valuesEqual = false;
610 if (this.key instanceof byte[]) {
611 if (other.getKey() instanceof byte[]) {
612 keysEqual = Arrays.equals((byte[]) this.key,
613 (byte[]) other.getKey());
614 } else {
615 return false;
616 }
617 } else {
618 keysEqual = this.getKey().equals(other.getKey());
619 }
620
621 if (keysEqual) {
622 if (this.value instanceof byte[]) {
623 if (other.getValue() instanceof byte[]) {
624 return Arrays.equals((byte[]) this.value,
625 (byte[]) other.getValue());
626 } else {
627 return false;
628 }
629 } else {
630 return this.key.equals(other.getKey());
631 }
632 }
633 return false;
634 }
635
636 @Override
637 public int hashCode() {
638 return 0;
639 }
640 }
Ray Milkey88cc3432017-03-30 17:19:08 -0700641}