Unit test for the gossip intent store

This change also implements a unit test harness for the
EventuallyConsistentMap that is intended to be reusable
to test other stores.

Change-Id: I2257da9b19412b97a3aa0f127be7263a7732b852
diff --git a/core/api/src/test/java/org/onosproject/cluster/ClusterServiceAdapter.java b/core/api/src/test/java/org/onosproject/cluster/ClusterServiceAdapter.java
index 87052ba..b88b5ff 100644
--- a/core/api/src/test/java/org/onosproject/cluster/ClusterServiceAdapter.java
+++ b/core/api/src/test/java/org/onosproject/cluster/ClusterServiceAdapter.java
@@ -18,19 +18,25 @@
 import java.util.Set;
 
 import org.joda.time.DateTime;
+import org.onlab.packet.IpAddress;
+
+import com.google.common.collect.ImmutableSet;
 
 /**
  * Test adapter for the cluster service.
  */
 public class ClusterServiceAdapter implements ClusterService {
+    ControllerNode local = new DefaultControllerNode(new NodeId("local"),
+            IpAddress.valueOf("127.0.0.1"));
+
     @Override
     public ControllerNode getLocalNode() {
-        return null;
+        return local;
     }
 
     @Override
     public Set<ControllerNode> getNodes() {
-        return null;
+        return ImmutableSet.of(local);
     }
 
     @Override
diff --git a/core/api/src/test/java/org/onosproject/net/intent/PartitionServiceAdapter.java b/core/api/src/test/java/org/onosproject/net/intent/PartitionServiceAdapter.java
new file mode 100644
index 0000000..ffb2635
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/net/intent/PartitionServiceAdapter.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.net.intent;
+
+import org.onosproject.cluster.NodeId;
+
+import static org.junit.Assert.*;
+
+/**
+ * Testing adapter for the partition service.
+ */
+public class PartitionServiceAdapter implements PartitionService {
+    @Override
+    public boolean isMine(Key intentKey) {
+        return true;
+    }
+
+    @Override
+    public NodeId getLeader(Key intentKey) {
+        return null;
+    }
+
+    @Override
+    public void addListener(PartitionEventListener listener) {
+
+    }
+
+    @Override
+    public void removeListener(PartitionEventListener listener) {
+
+    }
+}
diff --git a/core/api/src/test/java/org/onosproject/store/service/EventuallyConsistentMapAdapter.java b/core/api/src/test/java/org/onosproject/store/service/EventuallyConsistentMapAdapter.java
new file mode 100644
index 0000000..07f5fb4
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/store/service/EventuallyConsistentMapAdapter.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.service;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.BiFunction;
+
+/**
+ * Testing adapter for EventuallyConsistentMap.
+ */
+public class EventuallyConsistentMapAdapter<K, V> implements EventuallyConsistentMap<K, V> {
+    @Override
+    public int size() {
+        return 0;
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return false;
+    }
+
+    @Override
+    public boolean containsKey(K key) {
+        return false;
+    }
+
+    @Override
+    public boolean containsValue(V value) {
+        return false;
+    }
+
+    @Override
+    public V get(K key) {
+        return null;
+    }
+
+    @Override
+    public void put(K key, V value) {
+
+    }
+
+    @Override
+    public V remove(K key) {
+        return null;
+    }
+
+    @Override
+    public void remove(K key, V value) {
+
+    }
+
+    @Override
+    public V compute(K key, BiFunction<K, V, V> recomputeFunction) {
+        return null;
+    }
+
+    @Override
+    public void putAll(Map<? extends K, ? extends V> m) {
+
+    }
+
+    @Override
+    public void clear() {
+
+    }
+
+    @Override
+    public Set<K> keySet() {
+        return null;
+    }
+
+    @Override
+    public Collection<V> values() {
+        return null;
+    }
+
+    @Override
+    public Set<Map.Entry<K, V>> entrySet() {
+        return null;
+    }
+
+    @Override
+    public void addListener(EventuallyConsistentMapListener<K, V> listener) {
+
+    }
+
+    @Override
+    public void removeListener(EventuallyConsistentMapListener<K, V> listener) {
+
+    }
+
+    @Override
+    public void destroy() {
+
+    }
+}
diff --git a/core/api/src/test/java/org/onosproject/store/service/StorageServiceAdapter.java b/core/api/src/test/java/org/onosproject/store/service/StorageServiceAdapter.java
new file mode 100644
index 0000000..ec04e33
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/store/service/StorageServiceAdapter.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.service;
+
+/**
+ * Adapter for the storage service.
+ */
+public class StorageServiceAdapter implements StorageService {
+    @Override
+    public <K, V> EventuallyConsistentMapBuilder<K, V> eventuallyConsistentMapBuilder() {
+        return null;
+    }
+
+    @Override
+    public <K, V> ConsistentMapBuilder<K, V> consistentMapBuilder() {
+        return null;
+    }
+
+    @Override
+    public <E> DistributedSetBuilder<E> setBuilder() {
+        return null;
+    }
+
+    @Override
+    public <E> DistributedQueueBuilder<E> queueBuilder() {
+        return null;
+    }
+
+    @Override
+    public AtomicCounterBuilder atomicCounterBuilder() {
+        return null;
+    }
+
+    @Override
+    public <V> AtomicValueBuilder<V> atomicValueBuilder() {
+        return null;
+    }
+
+    @Override
+    public TransactionContextBuilder transactionContextBuilder() {
+        return null;
+    }
+}
diff --git a/core/api/src/test/java/org/onosproject/store/service/TestEventuallyConsistentMap.java b/core/api/src/test/java/org/onosproject/store/service/TestEventuallyConsistentMap.java
new file mode 100644
index 0000000..5ee44c4
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/store/service/TestEventuallyConsistentMap.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.service;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.function.BiFunction;
+
+import org.onlab.util.KryoNamespace;
+import org.onosproject.cluster.NodeId;
+import org.onosproject.store.Timestamp;
+
+import static org.onosproject.store.service.EventuallyConsistentMapEvent.Type.*;
+
+/**
+ * Testing version of an Eventually Consistent Map.
+ */
+
+public final class TestEventuallyConsistentMap<K, V> extends EventuallyConsistentMapAdapter<K, V> {
+
+    private final HashMap<K, V> map;
+    private final String mapName;
+    private final List<EventuallyConsistentMapListener<K, V>> listeners;
+    private final BiFunction<K, V, Collection<NodeId>> peerUpdateFunction;
+
+    private TestEventuallyConsistentMap(String mapName,
+                                        BiFunction<K, V, Collection<NodeId>> peerUpdateFunction) {
+        map = new HashMap<>();
+        listeners = new LinkedList<>();
+        this.mapName = mapName;
+        this.peerUpdateFunction = peerUpdateFunction;
+    }
+
+    /**
+     * Notify all listeners of an event.
+     */
+    private void notifyListeners(EventuallyConsistentMapEvent<K, V> event) {
+        listeners.forEach(
+                listener -> listener.event(event)
+        );
+    }
+
+    @Override
+    public int size() {
+        return map.size();
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return map.isEmpty();
+    }
+
+    @Override
+    public boolean containsKey(K key) {
+        return map.containsKey(key);
+    }
+
+    @Override
+    public boolean containsValue(V value) {
+        return map.containsValue(value);
+    }
+
+    @Override
+    public V get(K key) {
+        return map.get(key);
+    }
+
+    @Override
+    public void put(K key, V value) {
+        map.put(key, value);
+        EventuallyConsistentMapEvent<K, V> addEvent =
+                new EventuallyConsistentMapEvent<>(mapName, PUT, key, value);
+        notifyListeners(addEvent);
+        peerUpdateFunction.apply(key, value);
+    }
+
+    @Override
+    public V remove(K key) {
+        V result = map.remove(key);
+        if (result != null) {
+            EventuallyConsistentMapEvent<K, V> removeEvent =
+                    new EventuallyConsistentMapEvent<>(mapName, REMOVE,
+                            key, map.get(key));
+            notifyListeners(removeEvent);
+        }
+        return result;
+    }
+
+    @Override
+    public void remove(K key, V value) {
+        boolean removed = map.remove(key, value);
+        if (removed) {
+            EventuallyConsistentMapEvent<K, V> removeEvent =
+                    new EventuallyConsistentMapEvent<>(mapName, REMOVE, key, value);
+            notifyListeners(removeEvent);
+        }
+    }
+
+    @Override
+    public V compute(K key, BiFunction<K, V, V> recomputeFunction) {
+        return map.compute(key, recomputeFunction);
+    }
+
+    @Override
+    public void putAll(Map<? extends K, ? extends V> m) {
+        map.putAll(m);
+    }
+
+    @Override
+    public void clear() {
+        map.clear();
+    }
+
+    @Override
+    public Set<K> keySet() {
+        return map.keySet();
+    }
+
+    @Override
+    public Collection<V> values() {
+        return map.values();
+    }
+
+    @Override
+    public Set<Map.Entry<K, V>> entrySet() {
+        return map.entrySet();
+    }
+
+    public static <K, V> Builder<K, V> builder() {
+        return new Builder<>();
+    }
+
+    @Override
+    public void addListener(EventuallyConsistentMapListener<K, V> listener) {
+        listeners.add(listener);
+    }
+
+    @Override
+    public void removeListener(EventuallyConsistentMapListener<K, V> listener) {
+        listeners.remove(listener);
+    }
+
+    public static class Builder<K, V> implements EventuallyConsistentMapBuilder<K, V> {
+        private String name;
+        private BiFunction<K, V, Collection<NodeId>> peerUpdateFunction;
+
+        @Override
+        public EventuallyConsistentMapBuilder<K, V> withName(String name) {
+            this.name = name;
+            return this;
+        }
+
+        @Override
+        public EventuallyConsistentMapBuilder<K, V> withSerializer(KryoNamespace.Builder serializerBuilder) {
+            return this;
+        }
+
+        @Override
+        public EventuallyConsistentMapBuilder<K, V>
+        withTimestampProvider(BiFunction<K, V, Timestamp> timestampProvider) {
+            return this;
+        }
+
+        @Override
+        public EventuallyConsistentMapBuilder<K, V> withEventExecutor(ExecutorService executor) {
+            return this;
+        }
+
+        @Override
+        public EventuallyConsistentMapBuilder<K, V> withCommunicationExecutor(ExecutorService executor) {
+            return this;
+        }
+
+        @Override
+        public EventuallyConsistentMapBuilder<K, V> withBackgroundExecutor(ScheduledExecutorService executor) {
+            return this;
+        }
+
+        @Override
+        public EventuallyConsistentMapBuilder<K, V>
+        withPeerUpdateFunction(BiFunction<K, V, Collection<NodeId>> peerUpdateFunction) {
+            this.peerUpdateFunction = peerUpdateFunction;
+            return this;
+        }
+
+        @Override
+        public EventuallyConsistentMapBuilder<K, V> withTombstonesDisabled() {
+            return this;
+        }
+
+        @Override
+        public EventuallyConsistentMapBuilder<K, V> withAntiEntropyPeriod(long period, TimeUnit unit) {
+            return this;
+        }
+
+        @Override
+        public EventuallyConsistentMapBuilder<K, V> withFasterConvergence() {
+            return this;
+        }
+
+        @Override
+        public EventuallyConsistentMapBuilder<K, V> withPersistence() {
+            return this;
+        }
+
+        @Override
+        public EventuallyConsistentMap<K, V> build() {
+            if (name == null) {
+                name = "test";
+            }
+            return new TestEventuallyConsistentMap<>(name, peerUpdateFunction);
+        }
+    }
+
+}
+
diff --git a/core/api/src/test/java/org/onosproject/store/service/TestStorageService.java b/core/api/src/test/java/org/onosproject/store/service/TestStorageService.java
new file mode 100644
index 0000000..d79796c
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/store/service/TestStorageService.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.service;
+
+public class TestStorageService extends StorageServiceAdapter {
+
+
+    @Override
+    public <K, V> EventuallyConsistentMapBuilder<K, V> eventuallyConsistentMapBuilder() {
+        return TestEventuallyConsistentMap.builder();
+    }
+
+    @Override
+    public <K, V> ConsistentMapBuilder<K, V> consistentMapBuilder() {
+        throw new UnsupportedOperationException("consistentMapBuilder");
+    }
+
+    @Override
+    public <E> DistributedSetBuilder<E> setBuilder() {
+        throw new UnsupportedOperationException("setBuilder");
+    }
+
+    @Override
+    public <E> DistributedQueueBuilder<E> queueBuilder() {
+        throw new UnsupportedOperationException("queueBuilder");
+    }
+
+    @Override
+    public AtomicCounterBuilder atomicCounterBuilder() {
+        throw new UnsupportedOperationException("atomicCounterBuilder");
+    }
+
+    @Override
+    public <V> AtomicValueBuilder<V> atomicValueBuilder() {
+        throw new UnsupportedOperationException("atomicValueBuilder");
+    }
+
+    @Override
+    public TransactionContextBuilder transactionContextBuilder() {
+        throw new UnsupportedOperationException("transactionContextBuilder");
+    }
+}