Allow programmatic module sharding configuration 26/85326/12
authorTibor Král <tibor.kral@pantheon.tech>
Tue, 22 Oct 2019 16:24:21 +0000 (18:24 +0200)
committerRobert Varga <nite@hq.sk>
Mon, 20 Jan 2020 11:02:14 +0000 (11:02 +0000)
Adds the option to create Configuration without the need for
module-shards.conf file. Current version only accepts a path
to the module-shards.conf. The file is later loaded and
deserialized into a Config object. This patch provides the
option to pass the Config object directly.

Change-Id: Ibeb666bd5f01d7ae972d26453046c959749a0656
Signed-off-by: Tibor Král <tibor.kral@pantheon.tech>
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/config/AbstractModuleShardConfigProvider.java [new file with mode: 0644]
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/config/FileModuleShardConfigProvider.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/config/HybridModuleShardConfigProvider.java [new file with mode: 0644]
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/config/ConfigurationImplBaseTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/config/ConfigurationImplFileTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/config/ConfigurationImplHybridTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/config/ConfigurationImplTest.java

diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/config/AbstractModuleShardConfigProvider.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/config/AbstractModuleShardConfigProvider.java
new file mode 100644 (file)
index 0000000..af112fb
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2019 PANTHEON.tech, s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.cluster.datastore.config;
+
+import static java.util.Objects.requireNonNull;
+
+import com.typesafe.config.Config;
+import com.typesafe.config.ConfigFactory;
+import com.typesafe.config.ConfigObject;
+import java.io.File;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import org.opendaylight.controller.cluster.access.concepts.MemberName;
+import org.opendaylight.controller.cluster.datastore.shardstrategy.ShardStrategyFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+abstract class AbstractModuleShardConfigProvider implements ModuleShardConfigProvider {
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractModuleShardConfigProvider.class);
+
+    static final Config loadConfigFromPath(final String configPath) {
+        final File configFile = new File(configPath);
+        Config config = null;
+        if (configFile.exists()) {
+            LOG.info("Config file exists - reading config from it");
+            config = ConfigFactory.parseFile(configFile);
+        } else {
+            LOG.warn("Reading Config from resource");
+            config = ConfigFactory.load(configPath);
+        }
+        return config;
+    }
+
+    static final void readModulesConfig(final Config modulesConfig,
+            final Map<String, ModuleConfig.Builder> moduleConfigMap, final Configuration configuration) {
+        for (final ConfigObject o : modulesConfig.getObjectList("modules")) {
+            final ConfigObjectWrapper wrapper = new ConfigObjectWrapper(o);
+
+            final String moduleName = wrapper.stringValue("name");
+            final ModuleConfig.Builder builder = moduleConfigMap.computeIfAbsent(moduleName, ModuleConfig::builder);
+
+            builder.nameSpace(wrapper.stringValue("namespace"));
+            builder.shardStrategy(ShardStrategyFactory.newShardStrategyInstance(moduleName,
+                    wrapper.stringValue("shard-strategy"), configuration));
+        }
+    }
+
+    static final Map<String, ModuleConfig.Builder> readModuleShardsConfig(final Config moduleShardsConfig) {
+        final Map<String, ModuleConfig.Builder> moduleConfigMap = new HashMap<>();
+        for (final ConfigObject moduleShardConfigObject : moduleShardsConfig.getObjectList("module-shards")) {
+            final String moduleName = moduleShardConfigObject.get("name").unwrapped().toString();
+            final ModuleConfig.Builder builder = ModuleConfig.builder(moduleName);
+
+            for (final ConfigObject shard : moduleShardConfigObject.toConfig().getObjectList("shards")) {
+                final String shardName = shard.get("name").unwrapped().toString();
+                final List<MemberName> replicas = shard.toConfig().getStringList("replicas").stream()
+                        .map(MemberName::forName).collect(Collectors.toList());
+                builder.shardConfig(shardName, replicas);
+            }
+
+            moduleConfigMap.put(moduleName, builder);
+        }
+
+        return moduleConfigMap;
+    }
+
+    private static final class ConfigObjectWrapper {
+        private final ConfigObject configObject;
+
+        ConfigObjectWrapper(final ConfigObject configObject) {
+            this.configObject = requireNonNull(configObject);
+        }
+
+        String stringValue(final String name) {
+            return configObject.get(name).unwrapped().toString();
+        }
+    }
+}
index ba28e5d..adafa54 100644 (file)
@@ -8,26 +8,14 @@
 package org.opendaylight.controller.cluster.datastore.config;
 
 import com.typesafe.config.Config;
-import com.typesafe.config.ConfigFactory;
-import com.typesafe.config.ConfigObject;
-import java.io.File;
-import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
-import java.util.stream.Collectors;
-import org.opendaylight.controller.cluster.access.concepts.MemberName;
-import org.opendaylight.controller.cluster.datastore.shardstrategy.ShardStrategyFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
  * Implementation of ModuleShardConfigProvider that reads the module and shard configuration from files.
  *
  * @author Thomas Pantelis
  */
-public class FileModuleShardConfigProvider implements ModuleShardConfigProvider {
-    private static final Logger LOG = LoggerFactory.getLogger(FileModuleShardConfigProvider.class);
-
+public class FileModuleShardConfigProvider extends AbstractModuleShardConfigProvider {
     private final String moduleShardsConfigPath;
     private final String modulesConfigPath;
 
@@ -38,84 +26,11 @@ public class FileModuleShardConfigProvider implements ModuleShardConfigProvider
 
     @Override
     public Map<String, ModuleConfig.Builder> retrieveModuleConfigs(final Configuration configuration) {
-        final File moduleShardsFile = new File(moduleShardsConfigPath);
-        final File modulesFile = new File(modulesConfigPath);
-
-        Config moduleShardsConfig = null;
-        if (moduleShardsFile.exists()) {
-            LOG.info("module shards config file exists - reading config from it");
-            moduleShardsConfig = ConfigFactory.parseFile(moduleShardsFile);
-        } else {
-            LOG.warn("module shards configuration read from resource");
-            moduleShardsConfig = ConfigFactory.load(moduleShardsConfigPath);
-        }
-
-        Config modulesConfig = null;
-        if (modulesFile.exists()) {
-            LOG.info("modules config file exists - reading config from it");
-            modulesConfig = ConfigFactory.parseFile(modulesFile);
-        } else {
-            LOG.warn("modules configuration read from resource");
-            modulesConfig = ConfigFactory.load(modulesConfigPath);
-        }
+        Config moduleShardsConfig = loadConfigFromPath(moduleShardsConfigPath);
+        Config modulesConfig = loadConfigFromPath(modulesConfigPath);
 
         final Map<String, ModuleConfig.Builder> moduleConfigMap = readModuleShardsConfig(moduleShardsConfig);
         readModulesConfig(modulesConfig, moduleConfigMap, configuration);
-
-        return moduleConfigMap;
-    }
-
-    private static void readModulesConfig(final Config modulesConfig,
-            final Map<String, ModuleConfig.Builder> moduleConfigMap, final Configuration configuration) {
-        final List<? extends ConfigObject> modulesConfigObjectList = modulesConfig.getObjectList("modules");
-
-        for (final ConfigObject o : modulesConfigObjectList) {
-            final ConfigObjectWrapper wrapper = new ConfigObjectWrapper(o);
-
-            final String moduleName = wrapper.stringValue("name");
-            final ModuleConfig.Builder builder = moduleConfigMap.computeIfAbsent(moduleName, ModuleConfig::builder);
-
-            builder.nameSpace(wrapper.stringValue("namespace"));
-            builder.shardStrategy(ShardStrategyFactory.newShardStrategyInstance(moduleName,
-                    wrapper.stringValue("shard-strategy"), configuration));
-        }
-    }
-
-    private static Map<String, ModuleConfig.Builder> readModuleShardsConfig(final Config moduleShardsConfig) {
-        final List<? extends ConfigObject> moduleShardsConfigObjectList =
-            moduleShardsConfig.getObjectList("module-shards");
-
-        final Map<String, ModuleConfig.Builder> moduleConfigMap = new HashMap<>();
-        for (final ConfigObject moduleShardConfigObject : moduleShardsConfigObjectList) {
-            final String moduleName = moduleShardConfigObject.get("name").unwrapped().toString();
-            final ModuleConfig.Builder builder = ModuleConfig.builder(moduleName);
-
-            final List<? extends ConfigObject> shardsConfigObjectList =
-                moduleShardConfigObject.toConfig().getObjectList("shards");
-
-            for (final ConfigObject shard : shardsConfigObjectList) {
-                final String shardName = shard.get("name").unwrapped().toString();
-                final List<MemberName> replicas = shard.toConfig().getStringList("replicas").stream()
-                        .map(MemberName::forName).collect(Collectors.toList());
-                builder.shardConfig(shardName, replicas);
-            }
-
-            moduleConfigMap.put(moduleName, builder);
-        }
-
         return moduleConfigMap;
     }
-
-    private static class ConfigObjectWrapper {
-
-        private final ConfigObject configObject;
-
-        ConfigObjectWrapper(final ConfigObject configObject) {
-            this.configObject = configObject;
-        }
-
-        public String stringValue(final String name) {
-            return configObject.get(name).unwrapped().toString();
-        }
-    }
 }
diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/config/HybridModuleShardConfigProvider.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/config/HybridModuleShardConfigProvider.java
new file mode 100644 (file)
index 0000000..02c2f2b
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2019 PANTHEON.tech, s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.cluster.datastore.config;
+
+import static java.util.Objects.requireNonNull;
+
+import com.typesafe.config.Config;
+import java.util.Map;
+
+public class HybridModuleShardConfigProvider extends AbstractModuleShardConfigProvider {
+    private final Config moduleShardsConfig;
+    private final String modulesConfigPath;
+
+    public HybridModuleShardConfigProvider(final Config moduleShardsConfig, final String modulesConfigPath) {
+        this.moduleShardsConfig = requireNonNull(moduleShardsConfig, "ModuleShardsConfig can't be null");
+        this.modulesConfigPath = modulesConfigPath;
+    }
+
+    @Override
+    public Map<String, ModuleConfig.Builder> retrieveModuleConfigs(final Configuration configuration) {
+        Config modulesConfig = loadConfigFromPath(modulesConfigPath);
+
+        final Map<String, ModuleConfig.Builder> moduleConfigMap = readModuleShardsConfig(this.moduleShardsConfig);
+        readModulesConfig(modulesConfig, moduleConfigMap, configuration);
+        return moduleConfigMap;
+    }
+}
diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/config/ConfigurationImplBaseTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/config/ConfigurationImplBaseTest.java
new file mode 100644 (file)
index 0000000..0eb752c
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2014, 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.cluster.datastore.config;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import com.google.common.collect.ImmutableSortedSet;
+import com.google.common.collect.Sets;
+import java.net.URI;
+import java.util.Collection;
+import java.util.Set;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.cluster.access.concepts.MemberName;
+import org.opendaylight.controller.cluster.datastore.shardstrategy.ModuleShardStrategy;
+import org.opendaylight.controller.cluster.datastore.shardstrategy.ShardStrategy;
+
+public abstract class ConfigurationImplBaseTest {
+    private static final MemberName MEMBER_1 = MemberName.forName("member-1");
+    private static final MemberName MEMBER_2 = MemberName.forName("member-2");
+    private static final MemberName MEMBER_3 = MemberName.forName("member-3");
+    private static final MemberName MEMBER_4 = MemberName.forName("member-4");
+    private static final MemberName MEMBER_5 = MemberName.forName("member-5");
+    private static final MemberName MEMBER_100 = MemberName.forName("member-100");
+
+    private ConfigurationImpl configuration;
+
+    @Before
+    public void setup() {
+        this.configuration = createConfiguration();
+    }
+
+    public abstract ConfigurationImpl createConfiguration();
+
+    @Test
+    public void testConstructor() {
+        Assert.assertNotNull(configuration);
+    }
+
+    @Test
+    public void testGetMemberShardNames() {
+        Collection<String> memberShardNames = configuration.getMemberShardNames(MEMBER_1);
+        assertEquals("getMemberShardNames", ImmutableSortedSet.of("people-1", "cars-1", "test-1", "default"),
+                ImmutableSortedSet.copyOf(memberShardNames));
+
+        memberShardNames = configuration.getMemberShardNames(MEMBER_2);
+        assertEquals("getMemberShardNames", ImmutableSortedSet.of("default"),
+                ImmutableSortedSet.copyOf(memberShardNames));
+
+        memberShardNames = configuration.getMemberShardNames(MEMBER_100);
+        assertEquals("getMemberShardNames size", 0, memberShardNames.size());
+    }
+
+    @Test
+    public void testGetMembersFromShardName() {
+        Collection<MemberName> members = configuration.getMembersFromShardName("default");
+        assertEquals("getMembersFromShardName", ImmutableSortedSet.of(MEMBER_1, MEMBER_2, MEMBER_3),
+                ImmutableSortedSet.copyOf(members));
+
+        members = configuration.getMembersFromShardName("cars-1");
+        assertEquals("getMembersFromShardName", ImmutableSortedSet.of(MEMBER_1),
+                ImmutableSortedSet.copyOf(members));
+
+        // Try to find a shard which is not present
+
+        members = configuration.getMembersFromShardName("foobar");
+        assertEquals("getMembersFromShardName size", 0, members.size());
+    }
+
+    @Test
+    public void testGetAllShardNames() {
+        Set<String> allShardNames = configuration.getAllShardNames();
+        assertEquals("getAllShardNames", ImmutableSortedSet.of("people-1", "cars-1", "test-1", "default"),
+                ImmutableSortedSet.copyOf(allShardNames));
+    }
+
+    @Test
+    public void testGetModuleNameFromNameSpace() {
+        String moduleName = configuration.getModuleNameFromNameSpace(
+                "urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test:cars");
+        assertEquals("getModuleNameFromNameSpace", "cars", moduleName);
+
+        moduleName = configuration.getModuleNameFromNameSpace(
+                "urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test");
+        assertEquals("getModuleNameFromNameSpace", "test", moduleName);
+
+        moduleName = configuration.getModuleNameFromNameSpace("non-existent");
+        assertNull("getModuleNameFromNameSpace - expected null", moduleName);
+    }
+
+    @Test
+    public void testGetStrategyForModule() {
+        ShardStrategy strategy = configuration.getStrategyForModule("cars");
+        assertNotNull("getStrategyForModule null", strategy);
+        assertEquals("getStrategyForModule type", ModuleShardStrategy.class, strategy.getClass());
+
+        strategy = configuration.getStrategyForModule("people");
+        assertNotNull("getStrategyForModule null", strategy);
+        assertEquals("getStrategyForModule type", ModuleShardStrategy.class, strategy.getClass());
+
+        strategy = configuration.getStrategyForModule("default");
+        assertNull("getStrategyForModule - expected null", strategy);
+
+        strategy = configuration.getStrategyForModule("non-existent");
+        assertNull("getStrategyForModule - expected null", strategy);
+    }
+
+    @Test
+    public void testGetShardNameForModule() {
+        String shardName = configuration.getShardNameForModule("cars");
+        assertEquals("getShardNameForModule", "cars-1", shardName);
+
+        shardName = configuration.getShardNameForModule("people");
+        assertEquals("getShardNameForModule", "people-1", shardName);
+
+        shardName = configuration.getShardNameForModule("non-existent");
+        assertNull("getShardNameForModule - expected null", shardName);
+    }
+
+    @Test
+    public void testAddModuleShardConfiguration() throws Exception {
+        URI namespace = new URI("urn:opendaylight:test:oven");
+        String moduleName = "oven";
+        String shardName = "oven-shard";
+        String shardStrategyName = ModuleShardStrategy.NAME;
+        Collection<MemberName> shardMemberNames = ImmutableSortedSet.of(MEMBER_1, MEMBER_4, MEMBER_5);
+
+        configuration.addModuleShardConfiguration(new ModuleShardConfiguration(namespace, moduleName, shardName,
+                shardStrategyName, shardMemberNames));
+
+        assertEquals("getMemberShardNames", ImmutableSortedSet.of("people-1", "cars-1", "test-1", "default", shardName),
+                ImmutableSortedSet.copyOf(configuration.getMemberShardNames(MEMBER_1)));
+        assertEquals("getMemberShardNames", ImmutableSortedSet.of(shardName),
+                ImmutableSortedSet.copyOf(configuration.getMemberShardNames(MEMBER_4)));
+        assertEquals("getMemberShardNames", ImmutableSortedSet.of(shardName),
+                ImmutableSortedSet.copyOf(configuration.getMemberShardNames(MEMBER_5)));
+        assertEquals("getMembersFromShardName", shardMemberNames,
+                ImmutableSortedSet.copyOf(configuration.getMembersFromShardName(shardName)));
+        assertEquals("getShardNameForModule", shardName, configuration.getShardNameForModule(moduleName));
+        assertEquals("getModuleNameFromNameSpace", moduleName,
+                configuration.getModuleNameFromNameSpace(namespace.toASCIIString()));
+        assertEquals("getAllShardNames", ImmutableSortedSet.of("people-1", "cars-1", "test-1", "default", shardName),
+                ImmutableSortedSet.copyOf(configuration.getAllShardNames()));
+
+        ShardStrategy strategy = configuration.getStrategyForModule("cars");
+        assertNotNull("getStrategyForModule null", strategy);
+        assertEquals("getStrategyForModule type", ModuleShardStrategy.class, strategy.getClass());
+    }
+
+    @Test
+    public void testGetUniqueMemberNamesForAllShards() {
+        assertEquals("getUniqueMemberNamesForAllShards", Sets.newHashSet(MEMBER_1, MEMBER_2, MEMBER_3),
+                configuration.getUniqueMemberNamesForAllShards());
+    }
+
+    @Test
+    public void testAddMemberReplicaForShard() {
+        configuration.addMemberReplicaForShard("people-1", MEMBER_2);
+        String shardName = configuration.getShardNameForModule("people");
+        assertEquals("ModuleShardName", "people-1", shardName);
+        ShardStrategy shardStrategy = configuration.getStrategyForModule("people");
+        assertEquals("ModuleStrategy", ModuleShardStrategy.class, shardStrategy.getClass());
+        Collection<MemberName> members = configuration.getMembersFromShardName("people-1");
+        assertEquals("Members", ImmutableSortedSet.of(MEMBER_1, MEMBER_2),
+                ImmutableSortedSet.copyOf(members));
+
+        configuration.addMemberReplicaForShard("non-existent", MEMBER_2);
+        Set<String> shardNames = configuration.getAllShardNames();
+        assertEquals("ShardNames", ImmutableSortedSet.of("people-1", "cars-1", "test-1", "default"),
+                ImmutableSortedSet.copyOf(shardNames));
+    }
+
+    @Test
+    public void testRemoveMemberReplicaForShard() {
+        configuration.removeMemberReplicaForShard("default", MEMBER_2);
+        String shardName = configuration.getShardNameForModule("default");
+        assertEquals("ModuleShardName", "default", shardName);
+        ShardStrategy shardStrategy = configuration.getStrategyForModule("default");
+        assertNull("ModuleStrategy", shardStrategy);
+        Collection<MemberName> members = configuration.getMembersFromShardName("default");
+        assertEquals("Members", ImmutableSortedSet.of(MEMBER_1, MEMBER_3),
+                ImmutableSortedSet.copyOf(members));
+
+        configuration.removeMemberReplicaForShard("non-existent", MEMBER_2);
+        Set<String> shardNames = configuration.getAllShardNames();
+        assertEquals("ShardNames", ImmutableSortedSet.of("people-1", "cars-1", "test-1", "default"),
+                ImmutableSortedSet.copyOf(shardNames));
+    }
+}
diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/config/ConfigurationImplFileTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/config/ConfigurationImplFileTest.java
new file mode 100644 (file)
index 0000000..3c2ad7d
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2014, 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.cluster.datastore.config;
+
+public class ConfigurationImplFileTest extends ConfigurationImplBaseTest {
+
+    @Override
+    public ConfigurationImpl createConfiguration() {
+        return new ConfigurationImpl("module-shards.conf", "modules.conf");
+    }
+}
diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/config/ConfigurationImplHybridTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/config/ConfigurationImplHybridTest.java
new file mode 100644 (file)
index 0000000..2174e07
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2019 PANTHEON.tech, s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.cluster.datastore.config;
+
+import com.typesafe.config.Config;
+import com.typesafe.config.ConfigFactory;
+import java.util.List;
+import org.junit.Test;
+
+public class ConfigurationImplHybridTest extends ConfigurationImplBaseTest {
+
+    @Override
+    public ConfigurationImpl createConfiguration() {
+        Config moduleShardsConf = generateModuleShards(List.of(
+                generateShard("default", "default", List.of("member-1", "member-2", "member-3")),
+                generateShard("people", "people-1", List.of("member-1")),
+                generateShard("cars", "cars-1", List.of("member-1")),
+                generateShard("test", "test-1", List.of("member-1"))
+        ));
+        return new ConfigurationImpl(new HybridModuleShardConfigProvider(moduleShardsConf, "modules.conf"));
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testNullModuleShardsConf() {
+        new HybridModuleShardConfigProvider(null, "modules.conf");
+    }
+
+    private static Config generateModuleShards(final List<String> shards) {
+        String moduleShardsContent = String.format("module-shards = [%n%s]", String.join(",\n", shards));
+        return ConfigFactory.parseString(moduleShardsContent);
+    }
+
+    private static String generateShard(final String name, final String shardsName, final List<String> replicas) {
+        return "    {"
+                + "        name = \"" + name + "\"\n"
+                + "        shards = [\n"
+                + "            {\n"
+                + "                name=\"" + shardsName + "\"\n"
+                + "                replicas = " + replicas
+                + "                \n"
+                + "            }\n"
+                + "        ]\n"
+                + "    }";
+    }
+}

©2013 OpenDaylight, A Linux Foundation Collaborative Project. All Rights Reserved.
OpenDaylight is a registered trademark of The OpenDaylight Project, Inc.
Linux Foundation and OpenDaylight are registered trademarks of the Linux Foundation.
Linux is a registered trademark of Linus Torvalds.