[AETHER-72] Add bulk update to ConsistentMultimap
Change-Id: I61e9f0c2ed5ab368777c64b6fb4aa2c8dd31d081
diff --git a/core/api/src/test/java/org/onosproject/store/primitives/DefaultConsistentMultimapTest.java b/core/api/src/test/java/org/onosproject/store/primitives/DefaultConsistentMultimapTest.java
new file mode 100644
index 0000000..61a175a
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/store/primitives/DefaultConsistentMultimapTest.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.store.primitives;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
+import org.junit.Test;
+import org.onosproject.store.service.AsyncConsistentMultimapAdapter;
+import org.onosproject.store.service.ConsistentMultimap;
+import org.onosproject.store.service.Versioned;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.is;
+
+/**
+ * Tests for DefaultConsistentMultiMap.
+ */
+public class DefaultConsistentMultimapTest {
+
+ private static final String KEY1 = "AAA";
+ private static final String VALUE1 = "111";
+ private static final String KEY2 = "BBB";
+ private static final String VALUE2 = "222";
+ private static final String KEY3 = "CCC";
+ private static final String VALUE3 = "333";
+ private static final String KEY4 = "DDD";
+ private static final String VALUE4 = "444";
+ private final List<String> allKeys = Lists.newArrayList(KEY1, KEY2,
+ KEY3, KEY4);
+ private final List<String> allValues = Lists.newArrayList(VALUE1, VALUE2,
+ VALUE3, VALUE4);
+
+ /**
+ * Tests the behavior of public APIs of the default consistent multi-map
+ * implementation.
+ */
+ @Test
+ public void testBehavior() {
+ // Initialize the map
+ Multimap<String, String> baseMap = HashMultimap.create();
+ AsyncConsistentMultimapMock<String, String> asyncMultiMap = new AsyncConsistentMultimapMock<>(baseMap);
+ ConsistentMultimap<String, String> newMap = new DefaultConsistentMultimap<>(asyncMultiMap, 69);
+
+ // Verify is empty
+ assertThat(newMap.size(), is(0));
+ assertThat(newMap.isEmpty(), is(true));
+
+ // Test multi put
+ Map<String, Collection<? extends String>> mapping = Maps.newHashMap();
+ // First build the mappings having each key a different mapping
+ allKeys.forEach(key -> {
+ switch (key) {
+ case KEY1:
+ mapping.put(key, Lists.newArrayList(allValues.subList(0, 1)));
+ break;
+ case KEY2:
+ mapping.put(key, Lists.newArrayList(allValues.subList(0, 2)));
+ break;
+ case KEY3:
+ mapping.put(key, Lists.newArrayList(allValues.subList(0, 3)));
+ break;
+ default:
+ mapping.put(key, Lists.newArrayList(allValues.subList(0, 4)));
+ break;
+ }
+ });
+ // Success
+ assertThat(newMap.putAll(mapping), is(true));
+ // Failure
+ assertThat(newMap.putAll(mapping), is(false));
+ // Verify operation
+ assertThat(newMap.size(), is(10));
+ assertThat(newMap.isEmpty(), is(false));
+ // verify mapping is ok
+
+ allKeys.forEach(key -> {
+ List<String> actual = Lists.newArrayList(Versioned.valueOrNull(newMap.get(key)));
+ switch (key) {
+ case KEY1:
+ assertThat(actual, containsInAnyOrder(allValues.subList(0, 1).toArray()));
+ break;
+ case KEY2:
+ assertThat(actual, containsInAnyOrder(allValues.subList(0, 2).toArray()));
+ break;
+ case KEY3:
+ assertThat(actual, containsInAnyOrder(allValues.subList(0, 3).toArray()));
+ break;
+ default:
+ assertThat(actual, containsInAnyOrder(allValues.subList(0, 4).toArray()));
+ break;
+ }
+ });
+ // Success
+ assertThat(newMap.removeAll(mapping), is(true));
+ // Failure
+ assertThat(newMap.removeAll(mapping), is(false));
+ // Verify operation
+ assertThat(newMap.size(), is(0));
+ assertThat(newMap.isEmpty(), is(true));
+ }
+
+ public static class AsyncConsistentMultimapMock<K, V> extends AsyncConsistentMultimapAdapter<K, V> {
+ private final Multimap<K, V> baseMap;
+ private static final int DEFAULT_CREATION_TIME = 0;
+ private static final int DEFAULT_VERSION = 0;
+
+ AsyncConsistentMultimapMock(Multimap<K, V> newBaseMap) {
+ baseMap = newBaseMap;
+ }
+
+ Versioned<Collection<? extends V>> makeVersioned(Collection<? extends V> v) {
+ return new Versioned<>(v, DEFAULT_VERSION, DEFAULT_CREATION_TIME);
+ }
+
+ @Override
+ public CompletableFuture<Integer> size() {
+ return CompletableFuture.completedFuture(baseMap.size());
+ }
+
+ @Override
+ public CompletableFuture<Boolean> isEmpty() {
+ return CompletableFuture.completedFuture(baseMap.isEmpty());
+ }
+
+ @Override
+ public CompletableFuture<Boolean> putAll(Map<K, Collection<? extends V>> mapping) {
+ CompletableFuture<Boolean> result = CompletableFuture.completedFuture(false);
+ for (Map.Entry<K, Collection<? extends V>> entry : mapping.entrySet()) {
+ if (baseMap.putAll(entry.getKey(), entry.getValue())) {
+ result = CompletableFuture.completedFuture(true);
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public CompletableFuture<Versioned<Collection<? extends V>>> get(K key) {
+ return CompletableFuture.completedFuture(makeVersioned(baseMap.get(key)));
+ }
+
+ @Override
+ public CompletableFuture<Boolean> removeAll(Map<K, Collection<? extends V>> mapping) {
+ CompletableFuture<Boolean> result = CompletableFuture.completedFuture(false);
+ for (Map.Entry<K, Collection<? extends V>> entry : mapping.entrySet()) {
+ for (V value : entry.getValue()) {
+ if (baseMap.remove(entry.getKey(), value)) {
+ result = CompletableFuture.completedFuture(true);
+ }
+ }
+ }
+ return result;
+ }
+ }
+}