/* * 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.consistent.impl; import static java.util.Collections.unmodifiableCollection; import static java.util.Collections.unmodifiableSet; import static org.hamcrest.Matchers.is; import static org.junit.Assert.*; import java.util.Collection; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.onosproject.core.ApplicationId; import org.onosproject.core.DefaultApplicationId; import org.onosproject.store.service.Serializer; import org.onosproject.store.service.Transaction; import org.onosproject.store.service.Versioned; import com.google.common.base.MoreObjects; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import net.kuujo.copycat.Task; import net.kuujo.copycat.cluster.Cluster; import net.kuujo.copycat.resource.ResourceState; /** * */ public class DefaultAsyncConsistentMapTest { private static final ApplicationId APP_ID = new DefaultApplicationId(42, "what"); private static final TestData KEY1A = new TestData("One", "a"); private static final TestData KEY1B = new TestData("One", "b"); private static final TestData VALUE2A = new TestData("Two", "a"); private static final TestData VALUE2B = new TestData("Two", "b"); @Before public void setUp() throws Exception { } @After public void tearDown() throws Exception { } @Test public void testKeySet() throws Exception { DefaultAsyncConsistentMap map; String name = "map_name"; Database database = new TestDatabase(); Serializer serializer = Serializer.forTypes(TestData.class); map = new DefaultAsyncConsistentMap<>(name, APP_ID, database, serializer, false, false, false); map.put(KEY1A, VALUE2A); map.put(KEY1B, VALUE2A); Set set = map.keySet().get(); assertEquals("Should contain 2 keys", 2, set.size()); assertThat(set.contains(KEY1A), is(true)); assertThat(set.contains(KEY1B), is(true)); assertThat(set.contains(new TestData("One", "a")), is(true)); } @Test public void testEntrySet() throws Exception { DefaultAsyncConsistentMap map; String name = "map_name"; Database database = new TestDatabase(); Serializer serializer = Serializer.forTypes(TestData.class); map = new DefaultAsyncConsistentMap<>(name, APP_ID, database, serializer, false, false, false); map.put(KEY1A, VALUE2A); map.put(KEY1B, VALUE2A); assertEquals("Should contain 2 entry", 2, map.entrySet().get().size()); } /** * Object to be used as a test data. * * {@link Object#equals(Object)} use only part of it's fields. * * As a result there can be 2 instances which the * serialized bytes are not-equal but * {@link Object#equals(Object)}-wise they are equal. */ public static class TestData { private final String theKey; @SuppressWarnings("unused") private final String notUsedForEquals; public TestData(String theKey, String notUsedForEquals) { this.theKey = theKey; this.notUsedForEquals = notUsedForEquals; } @Override public int hashCode() { return Objects.hashCode(theKey); } @Override public boolean equals(Object obj) { if (obj instanceof TestData) { TestData that = (TestData) obj; return Objects.equals(this.theKey, that.theKey); } return false; } @Override public String toString() { return MoreObjects.toStringHelper(this) .add("theKey", theKey) .add("notUsedForEquals", notUsedForEquals) .toString(); } } /** * {@link Database} implementation for testing. * * There is only 1 backing Map, {@code mapName} will be ignored. */ public class TestDatabase implements Database { Map> map = new ConcurrentHashMap<>(); @Override public CompletableFuture> maps() { return CompletableFuture.completedFuture(ImmutableSet.of()); } @Override public CompletableFuture> counters() { return CompletableFuture.completedFuture(ImmutableMap.of()); } @Override public CompletableFuture mapSize(String mapName) { return CompletableFuture.completedFuture(map.size()); } @Override public CompletableFuture mapIsEmpty(String mapName) { return CompletableFuture.completedFuture(map.isEmpty()); } @Override public CompletableFuture mapContainsKey(String mapName, String key) { return CompletableFuture.completedFuture(map.containsKey(key)); } @Override public CompletableFuture mapContainsValue(String mapName, byte[] value) { return CompletableFuture.completedFuture(map.containsValue(value)); } @Override public CompletableFuture> mapGet(String mapName, String key) { return CompletableFuture.completedFuture(map.get(key)); } @Override public synchronized CompletableFuture>> mapUpdate(String mapName, String key, Match valueMatch, Match versionMatch, byte[] value) { boolean updated = false; final Versioned oldValue; final Versioned newValue; Versioned old = map.getOrDefault(key, new Versioned(null, 0)); if (valueMatch.matches(old.value()) && versionMatch.matches(old.version())) { updated = true; oldValue = old; newValue = new Versioned<>(value, old.version() + 1); map.put(key, newValue); } else { updated = false; oldValue = old; newValue = old; } return CompletableFuture.completedFuture( Result.ok(new UpdateResult(updated, mapName, key, oldValue, newValue))); } @Override public CompletableFuture> mapClear(String mapName) { throw new UnsupportedOperationException(); } @Override public CompletableFuture> mapKeySet(String mapName) { return CompletableFuture.completedFuture(unmodifiableSet(map.keySet())); } @Override public CompletableFuture>> mapValues(String mapName) { return CompletableFuture.completedFuture(unmodifiableCollection(map.values())); } @Override public CompletableFuture>>> mapEntrySet(String mapName) { return CompletableFuture.completedFuture(unmodifiableSet(map.entrySet())); } @Override public CompletableFuture counterAddAndGet(String counterName, long delta) { throw new UnsupportedOperationException(); } @Override public CompletableFuture counterGetAndAdd(String counterName, long delta) { throw new UnsupportedOperationException(); } @Override public CompletableFuture counterSet(String counterName, long value) { throw new UnsupportedOperationException(); } @Override public CompletableFuture counterCompareAndSet(String counterName, long expectedValue, long update) { throw new UnsupportedOperationException(); } @Override public CompletableFuture counterGet(String counterName) { throw new UnsupportedOperationException(); } @Override public CompletableFuture queueSize(String queueName) { throw new UnsupportedOperationException(); } @Override public CompletableFuture queuePush(String queueName, byte[] entry) { throw new UnsupportedOperationException(); } @Override public CompletableFuture queuePop(String queueName) { throw new UnsupportedOperationException(); } @Override public CompletableFuture queuePeek(String queueName) { throw new UnsupportedOperationException(); } @Override public CompletableFuture prepareAndCommit(Transaction transaction) { throw new UnsupportedOperationException(); } @Override public CompletableFuture prepare(Transaction transaction) { throw new UnsupportedOperationException(); } @Override public CompletableFuture commit(Transaction transaction) { throw new UnsupportedOperationException(); } @Override public CompletableFuture rollback(Transaction transaction) { throw new UnsupportedOperationException(); } @Override public String name() { return "name"; } @Override public ResourceState state() { return ResourceState.HEALTHY; } @Override public Cluster cluster() { throw new UnsupportedOperationException(); } @Override public Database addStartupTask(Task> task) { throw new UnsupportedOperationException(); } @Override public Database addShutdownTask(Task> task) { throw new UnsupportedOperationException(); } @Override public CompletableFuture open() { return CompletableFuture.completedFuture(this); } @Override public boolean isOpen() { return true; } @Override public CompletableFuture close() { return CompletableFuture.completedFuture(null); } @Override public boolean isClosed() { return false; } @Override public void registerConsumer(Consumer consumer) { } @Override public void unregisterConsumer(Consumer consumer) { } } }