/* * Copyright (c) 2008-2017, Hazelcast, Inc. All Rights Reserved. * * 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 com.hazelcast.multimap; import com.hazelcast.config.Config; import com.hazelcast.config.MultiMapConfig; import com.hazelcast.core.HazelcastException; import com.hazelcast.core.HazelcastInstance; import com.hazelcast.core.MultiMap; import com.hazelcast.mapreduce.aggregation.Aggregations; import com.hazelcast.mapreduce.aggregation.Supplier; import com.hazelcast.test.HazelcastParallelClassRunner; import com.hazelcast.test.HazelcastTestSupport; import com.hazelcast.test.TestHazelcastInstanceFactory; import com.hazelcast.test.annotation.ParallelTest; import com.hazelcast.test.annotation.QuickTest; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Random; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @RunWith(HazelcastParallelClassRunner.class) @Category({QuickTest.class, ParallelTest.class}) public class MultiMapTest extends HazelcastTestSupport { /** * idGen is not set while replicating */ @Test public void testIssue5220() { String name = randomString(); TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory(3); HazelcastInstance instance1 = factory.newHazelcastInstance(); MultiMap<Object, Object> mm1 = instance1.getMultiMap(name); // populate multimap while instance1 is owner // records will have ids from 0 to 10 for (int i = 0; i < 10; i++) { mm1.put("ping-address", "instance1-" + i); } HazelcastInstance instance2 = factory.newHazelcastInstance(); MultiMap<Object, Object> mm2 = instance2.getMultiMap(name); // now the second instance is the owner // if idGen is not set while replicating // these entries will have ids from 0 to 10 too for (int i = 0; i < 10; i++) { mm2.put("ping-address", "instance2-" + i); } HazelcastInstance instance3 = factory.newHazelcastInstance(); MultiMap<Object, Object> mm3 = instance3.getMultiMap(name); // since remove iterates all items and check equals it will remove correct item from owner-side // but for the backup we just sent the recordId. if idGen is not set while replicating // we may end up removing instance1's items for (int i = 0; i < 10; i++) { mm2.remove("ping-address", "instance2-" + i); } instance2.getLifecycleService().terminate(); for (int i = 0; i < 10; i++) { mm1.remove("ping-address", "instance1-" + i); } instance1.shutdown(); assertEquals(0, mm3.size()); } /** * ConcurrentModificationExceptions */ @Test public void testIssue1882() { String mmName = "mm"; TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory(2); final Config config = new Config(); final MultiMapConfig multiMapConfig = config.getMultiMapConfig(mmName); multiMapConfig.setValueCollectionType(MultiMapConfig.ValueCollectionType.LIST); final HazelcastInstance instance1 = factory.newHazelcastInstance(config); final HazelcastInstance instance2 = factory.newHazelcastInstance(config); final String key = generateKeyOwnedBy(instance1); final MultiMap<Object, Object> mm1 = instance1.getMultiMap("mm"); mm1.put(key, 1); mm1.put(key, 2); final AtomicBoolean running = new AtomicBoolean(true); new Thread() { @Override public void run() { int count = 3; while (running.get()) { mm1.put(key, count++); } } }.start(); for (int i = 0; i < 10; i++) { mm1.get(key); } } @Test public void testPutGetRemoveWhileCollectionTypeSet() throws InterruptedException { Config config = new Config(); final String name = "defMM"; config.getMultiMapConfig(name).setValueCollectionType(MultiMapConfig.ValueCollectionType.SET); final int insCount = 4; TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory(insCount); final HazelcastInstance[] instances = factory.newInstances(config); assertTrue(getMultiMap(instances, name).put("key1", "key1_value1")); assertTrue(getMultiMap(instances, name).put("key1", "key1_value2")); assertTrue(getMultiMap(instances, name).put("key2", "key2_value1")); assertFalse(getMultiMap(instances, name).put("key2", "key2_value1")); assertEquals(getMultiMap(instances, name).valueCount("key1"), 2); assertEquals(getMultiMap(instances, name).valueCount("key2"), 1); assertEquals(getMultiMap(instances, name).size(), 3); Collection coll = getMultiMap(instances, name).get("key2"); assertEquals(coll.size(), 1); Iterator iter = coll.iterator(); Object o = iter.next(); assertEquals(o, "key2_value1"); assertTrue(getMultiMap(instances, name).remove("key1", "key1_value1")); assertFalse(getMultiMap(instances, name).remove("key1", "key1_value1")); assertTrue(getMultiMap(instances, name).remove("key1", "key1_value2")); coll = getMultiMap(instances, name).get("key1"); assertEquals(coll.size(), 0); coll = getMultiMap(instances, name).remove("key2"); assertEquals(coll.size(), 1); iter = coll.iterator(); o = iter.next(); assertEquals(o, "key2_value1"); } @Test public void testContainsKey() { TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory(1); MultiMap multiMap = getMultiMap(factory.newInstances(), randomString()); assertFalse(multiMap.containsKey("test")); multiMap.put("test", "test"); assertTrue(multiMap.containsKey("test")); multiMap.remove("test"); assertFalse(multiMap.containsKey("test")); } @Test(expected = NullPointerException.class) public void testGet_whenNullKey() { TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory(1); MultiMap multiMap = getMultiMap(factory.newInstances(), randomString()); multiMap.get(null); } @Test(expected = NullPointerException.class) public void testPut_whenNullKey() { TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory(1); MultiMap multiMap = getMultiMap(factory.newInstances(), randomString()); multiMap.put(null, "someVal"); } @Test(expected = NullPointerException.class) public void testPut_whenNullValue() { TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory(1); MultiMap multiMap = getMultiMap(factory.newInstances(), randomString()); multiMap.put("someVal", null); } @Test(expected = NullPointerException.class) public void testContainsKey_whenNullKey() throws InterruptedException { TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory(1); MultiMap multiMap = getMultiMap(factory.newInstances(), randomString()); multiMap.containsKey(null); } @Test(expected = NullPointerException.class) public void testContainsValue_whenNullKey() throws InterruptedException { TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory(1); MultiMap multiMap = getMultiMap(factory.newInstances(), randomString()); multiMap.containsValue(null); } @Test(expected = NullPointerException.class) public void testContainsEntry_whenNullKey() throws InterruptedException { TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory(1); MultiMap multiMap = getMultiMap(factory.newInstances(), randomString()); multiMap.containsEntry(null, "someVal"); } @Test(expected = NullPointerException.class) public void testContainsEntry_whenNullValue() throws InterruptedException { TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory(1); MultiMap multiMap = getMultiMap(factory.newInstances(), randomString()); multiMap.containsEntry("someVal", null); } @Test public void testPutGetRemoveWhileCollectionTypeList() throws InterruptedException { Config config = new Config(); final String name = "defMM"; config.getMultiMapConfig(name).setValueCollectionType(MultiMapConfig.ValueCollectionType.LIST); final int insCount = 4; TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory(insCount); final HazelcastInstance[] instances = factory.newInstances(config); assertTrue(getMultiMap(instances, name).put("key1", "key1_value1")); assertTrue(getMultiMap(instances, name).put("key1", "key1_value2")); assertTrue(getMultiMap(instances, name).put("key2", "key2_value1")); assertTrue(getMultiMap(instances, name).put("key2", "key2_value1")); assertEquals(getMultiMap(instances, name).valueCount("key1"), 2); assertEquals(getMultiMap(instances, name).valueCount("key2"), 2); assertEquals(getMultiMap(instances, name).size(), 4); Collection coll = getMultiMap(instances, name).get("key1"); assertEquals(coll.size(), 2); Iterator iter = coll.iterator(); assertEquals(iter.next(), "key1_value1"); assertEquals(iter.next(), "key1_value2"); assertTrue(getMultiMap(instances, name).remove("key1", "key1_value1")); assertFalse(getMultiMap(instances, name).remove("key1", "key1_value1")); assertTrue(getMultiMap(instances, name).remove("key1", "key1_value2")); coll = getMultiMap(instances, name).get("key1"); assertEquals(coll.size(), 0); coll = getMultiMap(instances, name).remove("key2"); assertEquals(coll.size(), 2); iter = coll.iterator(); assertEquals(iter.next(), "key2_value1"); assertEquals(iter.next(), "key2_value1"); } /** * test localKeySet, keySet, entrySet, values, contains, containsKey and containsValue methods */ @Test public void testCollectionInterfaceMethods() { Config config = new Config(); final String name = "defMM"; config.getMultiMapConfig(name).setValueCollectionType(MultiMapConfig.ValueCollectionType.LIST); final int insCount = 4; TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory(insCount); final HazelcastInstance[] instances = factory.newInstances(config); getMultiMap(instances, name).put("key1", "key1_val1"); getMultiMap(instances, name).put("key1", "key1_val2"); getMultiMap(instances, name).put("key1", "key1_val3"); getMultiMap(instances, name).put("key2", "key2_val1"); getMultiMap(instances, name).put("key2", "key2_val2"); getMultiMap(instances, name).put("key3", "key3_val1"); getMultiMap(instances, name).put("key3", "key3_val2"); getMultiMap(instances, name).put("key3", "key3_val3"); getMultiMap(instances, name).put("key3", "key3_val4"); assertTrue(getMultiMap(instances, name).containsKey("key3")); assertTrue(getMultiMap(instances, name).containsValue("key3_val4")); Set totalKeySet = new HashSet(); Set localKeySet = instances[0].getMultiMap(name).localKeySet(); totalKeySet.addAll(localKeySet); localKeySet = instances[1].getMultiMap(name).localKeySet(); totalKeySet.addAll(localKeySet); localKeySet = instances[2].getMultiMap(name).localKeySet(); totalKeySet.addAll(localKeySet); localKeySet = instances[3].getMultiMap(name).localKeySet(); totalKeySet.addAll(localKeySet); assertEquals(3, totalKeySet.size()); Set keySet = getMultiMap(instances, name).keySet(); assertEquals(keySet.size(), 3); for (Object key : keySet) { assertContains(totalKeySet, key); } Set<Map.Entry> entrySet = getMultiMap(instances, name).entrySet(); assertEquals(entrySet.size(), 9); for (Map.Entry entry : entrySet) { String key = (String) entry.getKey(); String val = (String) entry.getValue(); assertTrue(val.startsWith(key)); } Collection values = getMultiMap(instances, name).values(); assertEquals(values.size(), 9); assertTrue(getMultiMap(instances, name).containsKey("key2")); assertFalse(getMultiMap(instances, name).containsKey("key4")); assertTrue(getMultiMap(instances, name).containsEntry("key3", "key3_val3")); assertFalse(getMultiMap(instances, name).containsEntry("key3", "key3_val7")); assertFalse(getMultiMap(instances, name).containsEntry("key2", "key3_val3")); assertTrue(getMultiMap(instances, name).containsValue("key2_val2")); assertFalse(getMultiMap(instances, name).containsValue("key2_val4")); } // it must throw ClassCastException wrapped by HazelcastException @Test(expected = HazelcastException.class) public void testAggregateMultiMap_differentDataTypes() { TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory(1); MultiMap<Object, Object> multiMap = getMultiMap(factory.newInstances(), randomString()); multiMap.put(1, "fail"); multiMap.put(2, 75); Integer aggregate = multiMap.aggregate(Supplier.all(), Aggregations.integerAvg()); assertEquals(50, aggregate.intValue()); } @Test public void testAggregateMultiMap() { TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory(1); MultiMap<Object, Object> multiMap = getMultiMap(factory.newInstances(), randomString()); Integer aggregate = multiMap.aggregate(Supplier.all(), Aggregations.integerAvg()); assertEquals(0, aggregate.intValue()); multiMap.put(1, 25); multiMap.put(2, 75); aggregate = multiMap.aggregate(Supplier.all(), Aggregations.integerAvg()); assertEquals(50, aggregate.intValue()); } private MultiMap getMultiMap(HazelcastInstance[] instances, String name) { final Random rnd = new Random(); return instances[rnd.nextInt(instances.length)].getMultiMap(name); } }