/* * 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.map.impl; import com.hazelcast.config.Config; import com.hazelcast.config.MapConfig; import com.hazelcast.config.PartitioningStrategyConfig; import com.hazelcast.core.HazelcastInstance; import com.hazelcast.core.IMap; import com.hazelcast.core.PartitioningStrategy; import com.hazelcast.map.impl.proxy.MapProxyImpl; import com.hazelcast.partition.strategy.StringPartitioningStrategy; import com.hazelcast.test.AssertTask; import com.hazelcast.test.HazelcastParallelClassRunner; import com.hazelcast.test.HazelcastTestSupport; import com.hazelcast.test.annotation.ParallelTest; import com.hazelcast.test.annotation.QuickTest; import com.hazelcast.util.RootCauseMatcher; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.rules.ExpectedException; import org.junit.rules.TestName; import org.junit.runner.RunWith; import java.util.UUID; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; @RunWith(HazelcastParallelClassRunner.class) @Category({QuickTest.class, ParallelTest.class}) public class PartitioningStrategyFactoryTest extends HazelcastTestSupport { @Rule public ExpectedException expectedException = ExpectedException.none(); @Rule public TestName testName = new TestName(); private IMap<String, String> map; private String mapName; private PartitioningStrategyFactory partitioningStrategyFactory; @Before public void setup() { mapName = testName.getMethodName(); HazelcastInstance hazelcastInstance = createHazelcastInstance(); map = hazelcastInstance.getMap(mapName); MapProxyImpl mapProxy = (MapProxyImpl) map; MapService mapService = (MapService) mapProxy.getService(); MapServiceContextImpl mapServiceContext = (MapServiceContextImpl) mapService.getMapServiceContext(); partitioningStrategyFactory = mapServiceContext.partitioningStrategyFactory; } @Test public void whenConfigNull_getPartitioningStrategy_returnsNull() { PartitioningStrategy partitioningStrategy = partitioningStrategyFactory.getPartitioningStrategy(mapName, null); assertNull(partitioningStrategy); } @Test public void whenPartitioningStrategyDefined_getPartitioningStrategy_returnsSameInstance() { PartitioningStrategy configuredPartitioningStrategy = new StringPartitioningStrategy(); PartitioningStrategyConfig cfg = new PartitioningStrategyConfig(configuredPartitioningStrategy); PartitioningStrategy partitioningStrategy = partitioningStrategyFactory.getPartitioningStrategy(mapName, cfg); assertSame(configuredPartitioningStrategy, partitioningStrategy); } @Test public void whenPartitioningStrategyClassDefined_getPartitioningStrategy_returnsNewInstance() { PartitioningStrategyConfig cfg = new PartitioningStrategyConfig(); cfg.setPartitioningStrategyClass("com.hazelcast.partition.strategy.StringPartitioningStrategy"); PartitioningStrategy partitioningStrategy = partitioningStrategyFactory.getPartitioningStrategy(mapName, cfg); assertEquals(StringPartitioningStrategy.class, partitioningStrategy.getClass()); } // when a partitioning strategy has already been cached, then another invocation to obtain the partitioning // strategy for the same map name retrieves the same instance @Test public void whenStrategyForMapAlreadyDefined_getPartitioningStrategy_returnsSameInstance() { PartitioningStrategyConfig cfg = new PartitioningStrategyConfig(); cfg.setPartitioningStrategyClass("com.hazelcast.partition.strategy.StringPartitioningStrategy"); // when we have already obtained the partitioning strategy for a given map name PartitioningStrategy partitioningStrategy = partitioningStrategyFactory.getPartitioningStrategy(mapName, cfg); // then once we get it again with the same arguments, we retrieve the same instance PartitioningStrategy cachedPartitioningStrategy = partitioningStrategyFactory.getPartitioningStrategy(mapName, cfg); assertSame(partitioningStrategy, cachedPartitioningStrategy); } // when an exception is thrown while attempting to instantiate a partitioning strategy // then the exception is rethrown (the same if it is a RuntimeException, otherwise it is peeled, // see ExceptionUtil.rethrow for all the details). @Test public void whenStrategyInstantiationThrowsException_getPartitioningStrategy_rethrowsException() { PartitioningStrategyConfig cfg = new PartitioningStrategyConfig(); cfg.setPartitioningStrategyClass("NonExistentPartitioningStrategy"); // while attempting to get partitioning strategy, ClassNotFound exception will be thrown and wrapped in HazelcastException expectedException.expect(new RootCauseMatcher(ClassNotFoundException.class)); // use a random UUID as map name, to avoid obtaining the PartitioningStrategy from cache. partitioningStrategyFactory.getPartitioningStrategy(UUID.randomUUID().toString(), cfg); } @Test public void whenRemoveInvoked_entryIsRemovedFromCache() { PartitioningStrategyConfig cfg = new PartitioningStrategyConfig(); cfg.setPartitioningStrategyClass("com.hazelcast.partition.strategy.StringPartitioningStrategy"); PartitioningStrategy partitioningStrategy = partitioningStrategyFactory.getPartitioningStrategy(mapName, cfg); partitioningStrategyFactory.removePartitioningStrategyFromCache(mapName); assertFalse(partitioningStrategyFactory.cache.containsKey(mapName)); } @Test public void whenMapDestroyed_entryIsRemovedFromCache() { map.put("a", "b"); // at this point, the PartitioningStrategyFactory#cache should have an entry for this map config assertTrue("Key should exist in cache", partitioningStrategyFactory.cache.containsKey(mapName)); map.destroy(); assertTrueEventually(new AssertTask() { @Override public void run() throws Exception { assertFalse("Key should have been removed from cache", partitioningStrategyFactory.cache.containsKey(mapName)); } }, 20); } @Override protected Config getConfig() { Config config = new Config(); MapConfig mapConfig = new MapConfig(mapName); PartitioningStrategyConfig partitioningStrategyConfig = new PartitioningStrategyConfig(); partitioningStrategyConfig.setPartitioningStrategyClass("com.hazelcast.partition.strategy.StringPartitioningStrategy"); mapConfig.setPartitioningStrategyConfig(partitioningStrategyConfig); config.addMapConfig(mapConfig); return config; } }