Jonathan Hart

Unit tests for EventuallyConsistentMapImpl.

Most functionality is tested here, except for the anti-entropy code.

ONOS-859.

Change-Id: Ib9e83518f8a91d599364106bc0f7d869e62f5133
......@@ -15,12 +15,13 @@
*/
package org.onosproject.store.cluster.messaging;
import java.io.IOException;
import org.onosproject.cluster.NodeId;
import com.google.common.base.MoreObjects;
import org.onlab.util.ByteArraySizeHashPrinter;
import org.onosproject.cluster.NodeId;
import com.google.common.base.MoreObjects;
import java.io.IOException;
import java.util.Arrays;
import java.util.Objects;
// TODO: Should payload type be ByteBuffer?
/**
......@@ -79,7 +80,7 @@ public class ClusterMessage {
* @throws IOException when I/O exception of some sort has occurred
*/
public void respond(byte[] data) throws IOException {
throw new IllegalStateException("One can only repond to message recived from others.");
throw new IllegalStateException("One can only respond to message received from others.");
}
@Override
......@@ -90,4 +91,22 @@ public class ClusterMessage {
.add("payload", ByteArraySizeHashPrinter.of(payload))
.toString();
}
@Override
public boolean equals(Object o) {
if (!(o instanceof ClusterMessage)) {
return false;
}
ClusterMessage that = (ClusterMessage) o;
return Objects.equals(this.sender, that.sender) &&
Objects.equals(this.subject, that.subject) &&
Arrays.equals(this.payload, that.payload);
}
@Override
public int hashCode() {
return Objects.hash(sender, subject, payload);
}
}
......
......@@ -15,6 +15,10 @@
*/
package org.onosproject.store.impl;
import com.google.common.base.MoreObjects;
import java.util.Objects;
/**
* Event object signalling that the map was modified.
*/
......@@ -68,4 +72,30 @@ public class EventuallyConsistentMapEvent<K, V> {
public V value() {
return value;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof EventuallyConsistentMapEvent)) {
return false;
}
EventuallyConsistentMapEvent that = (EventuallyConsistentMapEvent) o;
return Objects.equals(this.type, that.type) &&
Objects.equals(this.key, that.key) &&
Objects.equals(this.value, that.value);
}
@Override
public int hashCode() {
return Objects.hash(type, key, value);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("type", type)
.add("key", key)
.add("value", value)
.toString();
}
}
......
......@@ -16,6 +16,7 @@
package org.onosproject.store.impl;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableList;
import org.apache.commons.lang3.RandomUtils;
import org.onlab.util.KryoNamespace;
import org.onosproject.cluster.ClusterService;
......@@ -33,11 +34,11 @@ import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
......@@ -290,13 +291,15 @@ public class EventuallyConsistentMapImpl<K, V>
}
}
notifyPeers(new InternalPutEvent<>(updates));
if (!updates.isEmpty()) {
notifyPeers(new InternalPutEvent<>(updates));
for (PutEntry<K, V> entry : updates) {
EventuallyConsistentMapEvent<K, V> externalEvent =
new EventuallyConsistentMapEvent<>(
EventuallyConsistentMapEvent.Type.PUT, entry.key(), entry.value());
notifyListeners(externalEvent);
for (PutEntry<K, V> entry : updates) {
EventuallyConsistentMapEvent<K, V> externalEvent = new EventuallyConsistentMapEvent<>(
EventuallyConsistentMapEvent.Type.PUT, entry.key(),
entry.value());
notifyListeners(externalEvent);
}
}
}
......@@ -314,13 +317,16 @@ public class EventuallyConsistentMapImpl<K, V>
}
}
notifyPeers(new InternalRemoveEvent<>(removed));
if (!removed.isEmpty()) {
notifyPeers(new InternalRemoveEvent<>(removed));
for (RemoveEntry<K> entry : removed) {
EventuallyConsistentMapEvent<K, V> externalEvent =
new EventuallyConsistentMapEvent<>(
EventuallyConsistentMapEvent.Type.REMOVE, entry.key(), null);
notifyListeners(externalEvent);
for (RemoveEntry<K> entry : removed) {
EventuallyConsistentMapEvent<K, V> externalEvent
= new EventuallyConsistentMapEvent<>(
EventuallyConsistentMapEvent.Type.REMOVE, entry.key(),
null);
notifyListeners(externalEvent);
}
}
}
......@@ -370,8 +376,11 @@ public class EventuallyConsistentMapImpl<K, V>
executor.shutdown();
backgroundExecutor.shutdown();
listeners.clear();
clusterCommunicator.removeSubscriber(updateMessageSubject);
clusterCommunicator.removeSubscriber(removeMessageSubject);
clusterCommunicator.removeSubscriber(antiEntropyAdvertisementSubject);
}
private void notifyListeners(EventuallyConsistentMapEvent<K, V> event) {
......@@ -430,6 +439,23 @@ public class EventuallyConsistentMapImpl<K, V>
public V setValue(V value) {
throw new UnsupportedOperationException();
}
@Override
public boolean equals(Object o) {
if (!(o instanceof Map.Entry)) {
return false;
}
Map.Entry that = (Map.Entry) o;
return Objects.equals(this.key, that.getKey()) &&
Objects.equals(this.value, that.getValue());
}
@Override
public int hashCode() {
return Objects.hash(key, value);
}
}
private final class SendAdvertisementTask implements Runnable {
......@@ -728,12 +754,11 @@ public class EventuallyConsistentMapImpl<K, V>
}
}
private static final class InternalPutEvent<K, V> {
static final class InternalPutEvent<K, V> {
private final List<PutEntry<K, V>> entries;
public InternalPutEvent(K key, V value, Timestamp timestamp) {
entries = Collections
.singletonList(new PutEntry<>(key, value, timestamp));
entries = ImmutableList.of(new PutEntry<>(key, value, timestamp));
}
public InternalPutEvent(List<PutEntry<K, V>> entries) {
......@@ -751,7 +776,7 @@ public class EventuallyConsistentMapImpl<K, V>
}
}
private static final class PutEntry<K, V> {
static final class PutEntry<K, V> {
private final K key;
private final V value;
private final Timestamp timestamp;
......@@ -791,12 +816,11 @@ public class EventuallyConsistentMapImpl<K, V>
}
}
private static final class InternalRemoveEvent<K> {
static final class InternalRemoveEvent<K> {
private final List<RemoveEntry<K>> entries;
public InternalRemoveEvent(K key, Timestamp timestamp) {
entries = Collections.singletonList(
new RemoveEntry<>(key, timestamp));
entries = ImmutableList.of(new RemoveEntry<>(key, timestamp));
}
public InternalRemoveEvent(List<RemoveEntry<K>> entries) {
......@@ -814,7 +838,7 @@ public class EventuallyConsistentMapImpl<K, V>
}
}
private static final class RemoveEntry<K> {
static final class RemoveEntry<K> {
private final K key;
private final Timestamp timestamp;
......