/* * $Id$ * * Janus platform is an open-source multiagent platform. * More details on http://www.janusproject.io * * Copyright (C) 2014-2015 Sebastian RODRIGUEZ, Nicolas GAUD, Stéphane GALLAND. * * 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 io.janusproject.tests.kernel.services.hazelcast; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.UUID; import com.google.common.base.Supplier; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; import com.google.common.collect.Multimaps; import com.google.common.collect.Multiset; import com.google.common.collect.testing.google.MultimapTestSuiteBuilder; import com.hazelcast.config.Config; import com.hazelcast.core.Hazelcast; import com.hazelcast.core.HazelcastInstance; import com.hazelcast.core.MultiMap; import io.janusproject.kernel.services.hazelcast.HazelcastDMultiMapView; import io.janusproject.services.distributeddata.DMapListener; import io.janusproject.tests.testutils.AbstractJanusTest; import io.janusproject.tests.testutils.HzMultiMapMock; import io.janusproject.util.DataViewDelegate.Delegator; import org.junit.After; import org.junit.Assume; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; import org.mockito.ArgumentCaptor; import io.sarl.tests.api.Nullable; /** * @author $Author: sgalland$ * @version $FullVersion$ * @mavengroupid $GroupId$ * @mavenartifactid $ArtifactId$ */ @RunWith(Suite.class) @SuiteClasses({ HazelcastDMultiMapViewTest.BackedCollectionTests.class, HazelcastDMultiMapViewTest.SimplifiedMultiMapOperationTests.class, HazelcastDMultiMapViewTest.ViewTests.class, HazelcastDMultiMapViewTest.SpecificDMultiMapFunctionTests.class, HazelcastDMultiMapViewTest.ListeningFeatureTests.class }) @SuppressWarnings("all") public class HazelcastDMultiMapViewTest { /** * @author $Author: sgalland$ * @version $FullVersion$ * @mavengroupid $GroupId$ * @mavenartifactid $ArtifactId$ */ public static class BackedCollectionTests extends AbstractJanusTest { @Nullable private Config config; @Nullable private HazelcastInstance hazelcast; @Nullable private MultiMap<String, String> multimap; @Nullable private HazelcastDMultiMapView view; @Before public void setUp() { System.setProperty("hazelcast.logging.type", "none"); this.config = new Config(); this.hazelcast = Hazelcast.newHazelcastInstance(config); this.multimap = this.hazelcast.getMultiMap("janus-test-" + UUID.randomUUID().toString()); this.view = new HazelcastDMultiMapView<>(this.multimap); this.view.put("a", "va"); this.view.put("b", "vb"); } @After public void tearDown() { this.hazelcast.shutdown(); } @Test public void removeAll_replyList() { // This call should not fail: the internal cast to List is working. assertNotNull(this.view.removeAll("a")); } @Test public void replaceValues_replyList() { // This call should not fail: the internal cast to List is working. assertNotNull(this.view.replaceValues("a", Collections.singleton("vaa"))); } @Test public void get_replyList() { // This call should not fail: the internal cast to List is working. assertNotNull(this.view.get("a")); } @Test public void entries_replyList() { // This call should not fail: the internal cast to List is working. assertTrue(((Delegator<?>) this.view.entries()).getDelegatedObject() instanceof Set<?>); } @Test public void isBackedCollection() { assertFalse(this.view.isBackedCollection()); } @Test public void changesPropagation() { Assume.assumeTrue("The collection is not backing the changes to the underlying collection", this.view.isBackedCollection()); assertTrue(this.view.keySet().remove("b")); assertEquals(1, this.multimap.size()); assertTrue(this.multimap.containsKey("a")); assertTrue(this.multimap.containsValue("va")); } @Test public void noChangesPropagation() { Assume.assumeFalse("The collection is backing the changes to the underlying collection", this.view.isBackedCollection()); assertTrue(this.view.keySet().remove("b")); assertEquals(2, this.multimap.size()); assertTrue(this.multimap.containsKey("a")); assertTrue(this.multimap.containsValue("va")); assertTrue(this.multimap.containsKey("b")); assertTrue(this.multimap.containsValue("vb")); } } /** * This unit test is partly inspired by {@link MultimapTestSuiteBuilder}, but this last builder is not used since it assumes * that the replied collections are backed up to the source map. But this is not the case for the Hazelcast collection, see * {@link BackedCollectionTests}. * * @author $Author: sgalland$ * @version $FullVersion$ * @mavengroupid $GroupId$ * @mavenartifactid $ArtifactId$ */ public static class SimplifiedMultiMapOperationTests extends AbstractJanusTest { @Nullable private MultiMap<String, String> map; @Nullable private HazelcastDMultiMapView<String, String> view; @Before public void setUp() { this.map = new HzMultiMapMock<>(UUID.randomUUID().toString()); this.map.put("a", "va1"); this.map.put("a", "va2"); this.map.put("b", "vb"); this.view = new HazelcastDMultiMapView<>(this.map); } @Test public void size() { assertEquals(3, this.view.size()); this.view.clear(); assertEquals(0, this.view.size()); } @Test public void isEmpty() { assertFalse(this.view.isEmpty()); this.view.clear(); assertTrue(this.view.isEmpty()); } @Test public void containsKey() { assertTrue(this.view.containsKey("a")); assertTrue(this.view.containsKey("b")); assertFalse(this.view.containsKey("c")); } @Test public void containsValue() { assertTrue(this.view.containsValue("va1")); assertTrue(this.view.containsValue("va2")); assertTrue(this.view.containsValue("vb")); assertFalse(this.view.containsValue("vc")); } @Test public void containsEntry() { assertTrue(this.view.containsEntry("a", "va1")); assertTrue(this.view.containsEntry("a", "va2")); assertTrue(this.view.containsEntry("b", "vb")); assertFalse(this.view.containsEntry("b", "vc")); assertFalse(this.view.containsEntry("c", "va1")); } @Test public void put() { this.view.put("c", "vc"); assertTrue(this.view.containsEntry("a", "va1")); assertTrue(this.view.containsEntry("a", "va2")); assertTrue(this.view.containsEntry("b", "vb")); assertTrue(this.view.containsEntry("c", "vc")); assertFalse(this.view.containsEntry("b", "vc")); assertFalse(this.view.containsEntry("c", "va1")); } @Test public void remove() { this.view.remove("a", "va2"); assertTrue(this.view.containsEntry("a", "va1")); assertFalse(this.view.containsEntry("a", "va2")); assertTrue(this.view.containsEntry("b", "vb")); assertFalse(this.view.containsEntry("b", "vc")); assertFalse(this.view.containsEntry("c", "va1")); } @Test public void putAllKIterable() { this.view.putAll("c", Arrays.asList("vc1", "vc2")); assertTrue(this.view.containsEntry("a", "va1")); assertTrue(this.view.containsEntry("a", "va2")); assertTrue(this.view.containsEntry("b", "vb")); assertFalse(this.view.containsEntry("b", "vc")); assertTrue(this.view.containsEntry("c", "vc1")); assertTrue(this.view.containsEntry("c", "vc2")); } @Test public void putAllMultimap() { Supplier<List<String>> supplier = new Supplier<List<String>>() { @Override public List<String> get() { return Lists.newArrayList(); } }; Multimap<String, String> m = Multimaps.newListMultimap(new HashMap<String, Collection<String>>(), supplier); m.put("c", "vc1"); m.put("c", "vc2"); this.view.putAll(m); assertTrue(this.view.containsEntry("a", "va1")); assertTrue(this.view.containsEntry("a", "va2")); assertTrue(this.view.containsEntry("b", "vb")); assertFalse(this.view.containsEntry("b", "vc")); assertTrue(this.view.containsEntry("c", "vc1")); assertTrue(this.view.containsEntry("c", "vc2")); } @Test public void replaceValues() { this.view.replaceValues("b", Arrays.asList("n1", "n2")); assertTrue(this.view.containsEntry("a", "va1")); assertTrue(this.view.containsEntry("a", "va2")); assertFalse(this.view.containsEntry("b", "vb")); assertTrue(this.view.containsEntry("b", "n1")); assertTrue(this.view.containsEntry("b", "n2")); } @Test public void removeAll() { this.view.removeAll("a"); assertFalse(this.view.containsEntry("a", "va1")); assertFalse(this.view.containsEntry("a", "va2")); assertTrue(this.view.containsEntry("b", "vb")); assertFalse(this.view.containsEntry("b", "vc")); assertFalse(this.view.containsEntry("c", "va1")); } @Test public void clear() { this.view.clear(); assertFalse(this.view.containsEntry("a", "va1")); assertFalse(this.view.containsEntry("a", "va2")); assertFalse(this.view.containsEntry("b", "vb")); assertFalse(this.view.containsEntry("b", "vc")); assertFalse(this.view.containsEntry("c", "va1")); } @Test public void get() { assertContains(this.view.get("a"), "va1", "va2"); assertContains(this.view.get("b"), "vb"); assertContains(this.view.get("c")); } @Test public void keySet() { Set<String> keys = this.view.keySet(); assertContains(keys, "a", "b"); } @Test public void keys() { Multiset<String> keys = this.view.keys(); assertContains(keys, "a", "a", "b"); } @Test public void values() { Collection<String> values = this.view.values(); assertContains(values, "va1", "va2", "vb"); } @Test public void entries() { Collection<Entry<String, String>> entries = this.view.entries(); assertContains(entries, Maps.immutableEntry("a", "va1"), Maps.immutableEntry("a", "va2"), Maps.immutableEntry("b", "vb")); } @Test public void asMap() { Map<String, Collection<String>> map = this.view.asMap(); Collection<String> values; values = map.get("a"); assertEquals(2, values.size()); assertTrue(values.contains("va1")); assertTrue(values.contains("va2")); values = map.get("b"); assertEquals(1, values.size()); assertTrue(values.contains("vb")); values = map.get("c"); assertNull(values); } } /** * @author $Author: sgalland$ * @version $FullVersion$ * @mavengroupid $GroupId$ * @mavenartifactid $ArtifactId$ */ public static class ViewTests extends AbstractJanusTest { @Nullable private MultiMap<String, String> map; @Nullable private HazelcastDMultiMapView<String, String> view; @Before public void setUp() { this.map = new HzMultiMapMock<>(UUID.randomUUID().toString()); this.view = new HazelcastDMultiMapView<>(this.map); } @Test public void put() { String newKey = UUID.randomUUID().toString(); String newValue = UUID.randomUUID().toString(); this.map.put(newKey, newValue); // assertEquals(1, this.view.size()); Collection<String> col = this.view.get(newKey); assertNotNull(col); assertEquals(1, col.size()); assertSame(newValue, col.iterator().next()); } } /** * @author $Author: sgalland$ * @version $FullVersion$ * @mavengroupid $GroupId$ * @mavenartifactid $ArtifactId$ */ public static class SpecificDMultiMapFunctionTests extends AbstractJanusTest { @Nullable private MultiMap<String, String> map; @Nullable private HazelcastDMultiMapView<String, String> view; @Before public void setUp() { this.map = new HzMultiMapMock<>(UUID.randomUUID().toString()); this.view = new HazelcastDMultiMapView<>(this.map); } @Test public void valueCount_empty() { assertEquals(0, this.view.valueCount("abc")); } @Test public void valueCount_oneKey_oneValue() { this.view.put("abc", "vABC"); assertEquals(1, this.view.valueCount("abc")); } @Test public void valueCount_oneKey_twoValues() { this.view.put("abc", "vABC"); this.view.put("abc", "vABC2"); assertEquals(2, this.view.valueCount("abc")); } @Test public void valueCount_oneKey_threeValues() { this.view.put("abc", "vABC"); this.view.put("abc", "vABC2"); this.view.put("abc", "vABC3"); assertEquals(3, this.view.valueCount("abc")); } @Test public void valueCount_twoKeys_oneValue() { this.view.put("abc", "vABC"); this.view.put("def", "vDEF"); assertEquals(1, this.view.valueCount("abc")); } @Test public void valueCount_twoKeys_twoValues() { this.view.put("abc", "vABC"); this.view.put("abc", "vABC2"); this.view.put("def", "vDEF"); this.view.put("def", "vDEF2"); assertEquals(2, this.view.valueCount("abc")); } @Test public void valueCount_twoKeys_threeValues() { this.view.put("abc", "vABC"); this.view.put("abc", "vABC2"); this.view.put("abc", "vABC2"); this.view.put("def", "vDEF"); this.view.put("def", "vDEF2"); this.view.put("def", "vDEF2"); assertEquals(2, this.view.valueCount("abc")); } } /** * @author $Author: sgalland$ * @version $FullVersion$ * @mavengroupid $GroupId$ * @mavenartifactid $ArtifactId$ */ public static class ListeningFeatureTests extends AbstractJanusTest { @Nullable private DMapListener<String, String> listener; @Nullable private MultiMap<String, String> map; @Nullable private HazelcastDMultiMapView<String, String> view; @Before public void setUp() { this.listener = mock(DMapListener.class); this.map = new HzMultiMapMock<>(UUID.randomUUID().toString()); this.view = new HazelcastDMultiMapView<>(this.map); } @Test public void entryAdded_withoutListener() { this.view.put("abc", "vABC"); verifyZeroInteractions(this.listener); } @Test public void entryAdded_removeListener() { this.view.addDMapListener(this.listener); this.view.removeDMapListener(this.listener); this.view.put("abc", "vABC"); verifyZeroInteractions(this.listener); } @Test public void entryAdded_withListener() { this.view.addDMapListener(this.listener); this.view.put("abc", "vABC"); ArgumentCaptor<String> arg0 = ArgumentCaptor.forClass(String.class); ArgumentCaptor<String> arg1 = ArgumentCaptor.forClass(String.class); verify(this.listener, times(1)).entryAdded(arg0.capture(), arg1.capture()); assertEquals("abc", arg0.getValue()); assertEquals("vABC", arg1.getValue()); } @Test public void entryUpdated_withoutListener() { this.view.put("abc", "vABC"); this.view.put("abc", "vABC2"); verifyZeroInteractions(this.listener); } @Test public void entryUpdated_removeListener() { this.view.put("abc", "vABC"); this.view.addDMapListener(this.listener); this.view.removeDMapListener(this.listener); this.view.put("abc", "vABC2"); verifyZeroInteractions(this.listener); } @Test public void entryUpdated_withListener() { this.view.put("abc", "vABC"); this.view.addDMapListener(this.listener); this.view.put("abc", "vABC2"); ArgumentCaptor<String> arg0 = ArgumentCaptor.forClass(String.class); ArgumentCaptor<String> arg1 = ArgumentCaptor.forClass(String.class); verify(this.listener, times(1)).entryAdded(arg0.capture(), arg1.capture()); assertEquals("abc", arg0.getValue()); assertEquals("vABC2", arg1.getValue()); } @Test public void entryRemoved_withListener() { this.view.put("abc", "vABC"); this.view.removeAll("abc"); verifyZeroInteractions(this.listener); } @Test public void entryRemoved_removeListener() { this.view.put("abc", "vABC"); this.view.addDMapListener(this.listener); this.view.removeDMapListener(this.listener); this.view.removeAll("abc"); verifyZeroInteractions(this.listener); } @Test public void entryRemoved_withoutListener() { this.view.put("abc", "vABC"); this.view.addDMapListener(this.listener); this.view.removeAll("abc"); ArgumentCaptor<String> arg0 = ArgumentCaptor.forClass(String.class); ArgumentCaptor<String> arg1 = ArgumentCaptor.forClass(String.class); verify(this.listener, times(1)).entryRemoved(arg0.capture(), arg1.capture()); assertEquals("abc", arg0.getValue()); assertEquals("vABC", arg1.getValue()); } @Test public void mapCleared_withListener() { this.view.put("abc", "vABC"); this.view.clear(); verifyZeroInteractions(this.listener); } @Test public void mapCleared_removeListener() { this.view.put("abc", "vABC"); this.view.addDMapListener(this.listener); this.view.removeDMapListener(this.listener); this.view.clear(); verifyZeroInteractions(this.listener); } @Test public void mapCleared_withoutListener() { this.view.put("abc", "vABC"); this.view.addDMapListener(this.listener); this.view.clear(); ArgumentCaptor<Boolean> arg0 = ArgumentCaptor.forClass(Boolean.class); verify(this.listener, times(1)).mapCleared(arg0.capture()); assertFalse(arg0.getValue()); } } }