You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by ji...@apache.org on 2016/12/13 22:36:11 UTC

[1/2] geode git commit: GEODE-2196: restore the system properties correctly in each vm

Repository: geode
Updated Branches:
  refs/heads/feature/GEODE-2196 [created] a43941c74


GEODE-2196: restore the system properties correctly in each vm


Project: http://git-wip-us.apache.org/repos/asf/geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/geode/commit/dc11cfa2
Tree: http://git-wip-us.apache.org/repos/asf/geode/tree/dc11cfa2
Diff: http://git-wip-us.apache.org/repos/asf/geode/diff/dc11cfa2

Branch: refs/heads/feature/GEODE-2196
Commit: dc11cfa29462c5f1c8f2d344078bbc047fb64841
Parents: 5d2f0f6
Author: Jinmei Liao <ji...@pivotal.io>
Authored: Mon Dec 12 08:48:50 2016 -0800
Committer: Jinmei Liao <ji...@pivotal.io>
Committed: Mon Dec 12 10:51:18 2016 -0800

----------------------------------------------------------------------
 .../internal/DistributionConfig.java            |   2 +-
 .../internal/DistributionConfigImpl.java        |   2 +-
 .../org/apache/geode/internal/JarDeployer.java  |   3 +-
 .../configuration/ClusterConfigDUnitTest.java   | 243 +++++++++++++++++++
 .../DistributedRestoreSystemProperties.java     |   4 +-
 .../dunit/rules/LocatorServerStartupRule.java   |   7 +-
 6 files changed, 255 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/geode/blob/dc11cfa2/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionConfig.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionConfig.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionConfig.java
index 5eb070d..c2a395d 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionConfig.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionConfig.java
@@ -384,7 +384,7 @@ public interface DistributionConfig extends Config, LogConfig {
    * Default will be the current working directory as determined by
    * <code>System.getProperty("user.dir")</code>.
    */
-  File DEFAULT_DEPLOY_WORKING_DIR = new File(".");
+  File DEFAULT_DEPLOY_WORKING_DIR = new File(System.getProperty("user.dir"));
 
   /**
    * Returns the value of the {@link ConfigurationProperties#USER_COMMAND_PACKAGES} property

http://git-wip-us.apache.org/repos/asf/geode/blob/dc11cfa2/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionConfigImpl.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionConfigImpl.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionConfigImpl.java
index 0c6603d..fa6d13f 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionConfigImpl.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionConfigImpl.java
@@ -124,7 +124,7 @@ public class DistributionConfigImpl extends AbstractDistributionConfig implement
    */
   private File logFile = DEFAULT_LOG_FILE;
 
-  protected File deployWorkingDir = DEFAULT_DEPLOY_WORKING_DIR;
+  protected File deployWorkingDir = new File(System.getProperty("user.dir"));
 
   /**
    * The level at which log messages are logged

http://git-wip-us.apache.org/repos/asf/geode/blob/dc11cfa2/geode-core/src/main/java/org/apache/geode/internal/JarDeployer.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/JarDeployer.java b/geode-core/src/main/java/org/apache/geode/internal/JarDeployer.java
index f6a6e8e..e7afeda 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/JarDeployer.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/JarDeployer.java
@@ -623,7 +623,8 @@ public class JarDeployer implements Serializable {
     if (exception != null) {
       throw new IOException("Unable to write to deploy directory", exception);
     }
-    throw new IOException("Unable to write to deploy directory");
+    throw new IOException(
+        "Unable to write to deploy directory: " + this.deployDirectory.getCanonicalPath());
   }
 
   private byte[] getJarContent(File jarFile) throws IOException {

http://git-wip-us.apache.org/repos/asf/geode/blob/dc11cfa2/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigDUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigDUnitTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigDUnitTest.java
new file mode 100644
index 0000000..418999a
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigDUnitTest.java
@@ -0,0 +1,243 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You 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.apache.geode.management.internal.configuration;
+
+import static org.apache.geode.distributed.ConfigurationProperties.CLUSTER_CONFIGURATION_DIR;
+import static org.apache.geode.distributed.ConfigurationProperties.ENABLE_CLUSTER_CONFIGURATION;
+import static org.apache.geode.distributed.ConfigurationProperties.GROUPS;
+import static org.apache.geode.distributed.ConfigurationProperties.LOAD_CLUSTER_CONFIGURATION_FROM_DIR;
+import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS;
+import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE_SIZE_LIMIT;
+import static org.apache.geode.distributed.ConfigurationProperties.USE_CLUSTER_CONFIGURATION;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.apache.geode.cache.Cache;
+import org.apache.geode.distributed.internal.InternalLocator;
+import org.apache.geode.distributed.internal.SharedConfiguration;
+import org.apache.geode.internal.ClassPathLoader;
+import org.apache.geode.internal.JarClassLoader;
+import org.apache.geode.management.internal.configuration.domain.Configuration;
+import org.apache.geode.management.internal.configuration.utils.ZipUtils;
+import org.apache.geode.test.dunit.internal.JUnit4DistributedTestCase;
+import org.apache.geode.test.dunit.rules.LocatorServerStartupRule;
+import org.apache.geode.test.dunit.rules.Member;
+import org.apache.geode.test.junit.categories.DistributedTest;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Properties;
+
+@Category(DistributedTest.class)
+public class ClusterConfigDUnitTest extends JUnit4DistributedTestCase {
+  private static final String EXPORTED_CLUSTER_CONFIG_ZIP_FILENAME = "cluster_config.zip";
+  private static final String[] CONFIG_NAMES = new String[] {"cluster", "group1", "group2"};
+
+  private static final ExpectedConfig NO_GROUP =
+      new ExpectedConfig().maxLogFileSize("5000").regions("regionForCluster").jars("cluster.jar");
+
+  private static final ExpectedConfig GROUP1 = new ExpectedConfig().maxLogFileSize("6000")
+      .regions("regionForCluster", "regionForGroup1").jars("cluster.jar", "group1.jar");
+
+  private static final ExpectedConfig GROUP2 = new ExpectedConfig().maxLogFileSize("7000")
+      .regions("regionForCluster", "regionForGroup2").jars("cluster.jar", "group2.jar");
+
+  private static final ExpectedConfig GROUP1_AND_2 = new ExpectedConfig().maxLogFileSize("7000")
+      .regions("regionForCluster", "regionForGroup1", "regionForGroup2")
+      .jars("cluster.jar", "group1.jar", "group2.jar");
+
+
+  private String locatorString;
+
+  @Rule
+  public LocatorServerStartupRule lsRule = new LocatorServerStartupRule();
+
+  @Before
+  public void setupFirstLocatorWithClusterConfigFromDirectory() throws Exception {
+    File locatorDir = lsRule.getRootFolder().newFolder("locator-0");
+
+    // The unzip should yield a cluster config directory structure like:
+    // tempFolder/locator-0/cluster_config/cluster/cluster.xml
+    // tempFolder/locator-0/cluster_config/cluster/cluster.properties
+    // tempFolder/locator-0/cluster_config/cluster/cluster.jar
+    // tempFolder/locator-0/cluster_config/group1/ {group1.xml, group1.properties, group1.jar}
+    // tempFolder/locator-0/cluster_config/group2/ ...
+    ZipUtils.unzip(getClass().getResource(EXPORTED_CLUSTER_CONFIG_ZIP_FILENAME).getPath(),
+        locatorDir.getCanonicalPath());
+
+    Properties locatorProps = new Properties();
+    locatorProps.setProperty(ENABLE_CLUSTER_CONFIGURATION, "true");
+    locatorProps.setProperty(LOAD_CLUSTER_CONFIGURATION_FROM_DIR, "true");
+    locatorProps.setProperty(CLUSTER_CONFIGURATION_DIR, locatorDir.getCanonicalPath());
+
+    Member firstLocator = lsRule.startLocatorVM(0, locatorProps);
+    locatorString = "localhost[" + firstLocator.getPort() + "]";
+
+    verifyLocatorConfigExistsInFileSystem(firstLocator.getWorkingDir());
+    firstLocator.invoke(this::verifyLocatorConfigExistsInInternalRegion);
+  }
+
+  @Test
+  public void secondLocatorLoadsClusterConfigFromFirstLocator() throws IOException {
+    Properties secondLocatorProps = new Properties();
+    secondLocatorProps.setProperty(LOCATORS, locatorString);
+    secondLocatorProps.setProperty(ENABLE_CLUSTER_CONFIGURATION, "true");
+    Member secondLocator = lsRule.startLocatorVM(1, secondLocatorProps);
+
+    verifyLocatorConfig(secondLocator);
+  }
+
+  @Test
+  public void serverWithZeroOrOneGroupsLoadCorrectConfigFromLocator() throws Exception {
+    Properties serverProps = new Properties();
+    serverProps.setProperty(LOCATORS, locatorString);
+    serverProps.setProperty(USE_CLUSTER_CONFIGURATION, "true");
+
+    Member serverWithNoGroup = lsRule.startServerVM(1, serverProps);
+    verifyServerConfig(NO_GROUP, serverWithNoGroup);
+
+    serverProps.setProperty(GROUPS, "group1");
+    Member serverForGroup1 = lsRule.startServerVM(2, serverProps);
+    verifyServerConfig(GROUP1, serverForGroup1);
+
+    serverProps.setProperty(GROUPS, "group2");
+    Member serverForGroup2 = lsRule.startServerVM(3, serverProps);
+    verifyServerConfig(GROUP2, serverForGroup2);
+  }
+
+  @Test
+  public void oneServerWithMultipleGroupsLoadsCorrectConfigFromLocator() throws Exception {
+    Properties serverProps = new Properties();
+    serverProps.setProperty(LOCATORS, locatorString);
+    serverProps.setProperty(USE_CLUSTER_CONFIGURATION, "true");
+    serverProps.setProperty(GROUPS, "group1,group2");
+    Member serverWithNoGroup = lsRule.startServerVM(1, serverProps);
+
+    serverWithNoGroup.invoke(() -> this.verifyServerConfig(GROUP1_AND_2, serverWithNoGroup));
+  }
+
+  private void verifyLocatorConfig(Member locator) {
+    verifyLocatorConfigExistsInFileSystem(locator.getWorkingDir());
+    locator.invoke(this::verifyLocatorConfigExistsInInternalRegion);
+  }
+
+  private void verifyServerConfig(ExpectedConfig expectedConfig, Member server)
+      throws ClassNotFoundException {
+    verifyServerJarFilesExistInFileSystem(server.getWorkingDir(), expectedConfig.jars);
+    server.invoke(() -> this.verifyServerConfigInMemory(expectedConfig));
+  }
+
+  private void verifyLocatorConfigExistsInFileSystem(File workingDir) {
+    File clusterConfigDir = new File(workingDir, "cluster_config");
+    assertThat(clusterConfigDir).exists();
+
+    for (String configName : CONFIG_NAMES) {
+      File configDir = new File(clusterConfigDir, configName);
+      assertThat(configDir).exists();
+
+      File jar = new File(configDir, configName + ".jar");
+      File properties = new File(configDir, configName + ".properties");
+      File xml = new File(configDir, configName + ".xml");
+      assertThat(configDir.listFiles()).contains(jar, properties, xml);
+    }
+  }
+
+  private void verifyLocatorConfigExistsInInternalRegion() throws Exception {
+    InternalLocator internalLocator = LocatorServerStartupRule.locatorStarter.locator;
+    SharedConfiguration sc = internalLocator.getSharedConfiguration();
+
+    for (String configName : CONFIG_NAMES) {
+      Configuration config = sc.getConfiguration(configName);
+      assertThat(config).isNotNull();
+    }
+  }
+
+  private void verifyServerConfigInMemory(ExpectedConfig expectedConfig)
+      throws ClassNotFoundException {
+    Cache cache = LocatorServerStartupRule.serverStarter.cache;
+    for (String region : expectedConfig.regions) {
+      assertThat(cache.getRegion(region)).isNotNull();
+    }
+    Properties props = cache.getDistributedSystem().getProperties();
+    assertThat(props.getProperty(LOG_FILE_SIZE_LIMIT)).isEqualTo(expectedConfig.maxLogFileSize);
+
+    for (String jar : expectedConfig.jars) {
+      JarClassLoader jarClassLoader = findJarClassLoader(jar);
+      assertThat(jarClassLoader).isNotNull();
+      assertThat(jarClassLoader.loadClass(nameOfClassContainedInJar(jar))).isNotNull();
+    }
+  }
+
+  private void verifyServerJarFilesExistInFileSystem(File workingDir, String[] jarNames) {
+    assertThat(workingDir.listFiles()).isNotEmpty();
+
+    for (String jarName : jarNames) {
+      assertThat(workingDir.listFiles()).filteredOn((File file) -> file.getName().contains(jarName))
+          .isNotEmpty();
+    }
+  }
+
+  private String nameOfClassContainedInJar(String jarName) {
+    switch (jarName) {
+      case "cluster.jar":
+        return "Cluster";
+      case "group1.jar":
+        return "Group1";
+      case "group2.jar":
+        return "Group2";
+      default:
+        throw new IllegalArgumentException(
+            EXPORTED_CLUSTER_CONFIG_ZIP_FILENAME + " does not contain a jar named " + jarName);
+    }
+  }
+
+  private JarClassLoader findJarClassLoader(final String jarName) {
+    Collection<ClassLoader> classLoaders = ClassPathLoader.getLatest().getClassLoaders();
+    for (ClassLoader classLoader : classLoaders) {
+      if (classLoader instanceof JarClassLoader
+          && ((JarClassLoader) classLoader).getJarName().equals(jarName)) {
+        return (JarClassLoader) classLoader;
+      }
+    }
+    return null;
+  }
+
+  private static class ExpectedConfig implements Serializable {
+    public String maxLogFileSize;
+    public String[] regions;
+    public String[] jars;
+
+    public ExpectedConfig maxLogFileSize(String maxLogFileSize) {
+      this.maxLogFileSize = maxLogFileSize;
+      return this;
+    }
+
+    public ExpectedConfig regions(String... regions) {
+      this.regions = regions;
+      return this;
+    }
+
+    public ExpectedConfig jars(String... jars) {
+      this.jars = jars;
+      return this;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/dc11cfa2/geode-core/src/test/java/org/apache/geode/test/dunit/rules/DistributedRestoreSystemProperties.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/test/dunit/rules/DistributedRestoreSystemProperties.java b/geode-core/src/test/java/org/apache/geode/test/dunit/rules/DistributedRestoreSystemProperties.java
index 221b52a..6b9102e 100755
--- a/geode-core/src/test/java/org/apache/geode/test/dunit/rules/DistributedRestoreSystemProperties.java
+++ b/geode-core/src/test/java/org/apache/geode/test/dunit/rules/DistributedRestoreSystemProperties.java
@@ -44,7 +44,7 @@ public class DistributedRestoreSystemProperties extends RestoreSystemProperties
   }
 
   @Override
-  protected void before() throws Throwable {
+  public void before() throws Throwable {
     super.before();
     this.invoker.remoteInvokeInEveryVMAndLocator(new SerializableRunnable() {
       @Override
@@ -56,7 +56,7 @@ public class DistributedRestoreSystemProperties extends RestoreSystemProperties
   }
 
   @Override
-  protected void after() {
+  public void after() {
     super.after();
     this.invoker.remoteInvokeInEveryVMAndLocator(new SerializableRunnable() {
       @Override

http://git-wip-us.apache.org/repos/asf/geode/blob/dc11cfa2/geode-core/src/test/java/org/apache/geode/test/dunit/rules/LocatorServerStartupRule.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/test/dunit/rules/LocatorServerStartupRule.java b/geode-core/src/test/java/org/apache/geode/test/dunit/rules/LocatorServerStartupRule.java
index c56f7ab..b096cbb 100644
--- a/geode-core/src/test/java/org/apache/geode/test/dunit/rules/LocatorServerStartupRule.java
+++ b/geode-core/src/test/java/org/apache/geode/test/dunit/rules/LocatorServerStartupRule.java
@@ -52,11 +52,15 @@ public class LocatorServerStartupRule extends ExternalResource implements Serial
    */
   public static LocatorStarterRule locatorStarter;
 
+  private DistributedRestoreSystemProperties restoreSystemProperties =
+      new DistributedRestoreSystemProperties();
+
   private TemporaryFolder temporaryFolder = new SerializableTemporaryFolder();
   private Member[] members;
 
   @Before
-  public void before() throws IOException {
+  public void before() throws Throwable {
+    restoreSystemProperties.before();
     temporaryFolder.create();
     Invoke.invokeInEveryVM("Stop each VM", this::stop);
     members = new Member[4];
@@ -64,6 +68,7 @@ public class LocatorServerStartupRule extends ExternalResource implements Serial
 
   @After
   public void after() {
+    restoreSystemProperties.after();
     temporaryFolder.delete();
     Invoke.invokeInEveryVM("Stop each VM", this::stop);
   }


[2/2] geode git commit: GEODE-2196: add more tests to cover import cluster-configuration and deploy

Posted by ji...@apache.org.
GEODE-2196: add more tests to cover import cluster-configuration and deploy


Project: http://git-wip-us.apache.org/repos/asf/geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/geode/commit/a43941c7
Tree: http://git-wip-us.apache.org/repos/asf/geode/tree/a43941c7
Diff: http://git-wip-us.apache.org/repos/asf/geode/diff/a43941c7

Branch: refs/heads/feature/GEODE-2196
Commit: a43941c745c0a1553dfb88c2f2d3087358d676e9
Parents: dc11cfa
Author: Jinmei Liao <ji...@pivotal.io>
Authored: Fri Dec 9 16:31:24 2016 -0800
Committer: Jinmei Liao <ji...@pivotal.io>
Committed: Tue Dec 13 14:35:00 2016 -0800

----------------------------------------------------------------------
 .../internal/SharedConfiguration.java           |  64 +--
 ...ortSharedConfigurationArtifactsFunction.java |   3 +-
 .../ConnectToLocatorSSLDUnitTest.java           |  15 +-
 .../configuration/ClusterConfigDUnitTest.java   | 472 +++++++++++++++----
 .../security/DeployCommandsSecurityTest.java    |   1 -
 .../dunit/rules/GfshShellConnectionRule.java    |  24 +-
 .../dunit/rules/LocatorServerStartupRule.java   |   1 -
 .../internal/configuration/cluster.jar          | Bin 0 -> 617 bytes
 .../internal/configuration/cluster_config.zip   | Bin 4666 -> 4172 bytes
 .../internal/configuration/group1.jar           | Bin 0 -> 617 bytes
 .../internal/configuration/group2.jar           | Bin 0 -> 617 bytes
 11 files changed, 443 insertions(+), 137 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/geode/blob/a43941c7/geode-core/src/main/java/org/apache/geode/distributed/internal/SharedConfiguration.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/SharedConfiguration.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/SharedConfiguration.java
index a45e843..3119823 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/SharedConfiguration.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/SharedConfiguration.java
@@ -14,40 +14,13 @@
  */
 package org.apache.geode.distributed.internal;
 
-import static org.apache.geode.distributed.ConfigurationProperties.*;
-
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileWriter;
-import java.io.FilenameFilter;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.sql.Timestamp;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Properties;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicReference;
-
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactoryConfigurationError;
-import javax.xml.xpath.XPathExpressionException;
+import static org.apache.geode.distributed.ConfigurationProperties.CLUSTER_CONFIGURATION_DIR;
+import static org.apache.geode.distributed.ConfigurationProperties.SECURITY_MANAGER;
+import static org.apache.geode.distributed.ConfigurationProperties.SECURITY_POST_PROCESSOR;
 
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.io.FilenameUtils;
 import org.apache.commons.io.filefilter.DirectoryFileFilter;
-import org.apache.logging.log4j.Logger;
-import org.w3c.dom.Document;
-import org.xml.sax.SAXException;
-
 import org.apache.geode.CancelException;
 import org.apache.geode.cache.AttributesFactory;
 import org.apache.geode.cache.Cache;
@@ -82,6 +55,33 @@ import org.apache.geode.management.internal.configuration.messages.Configuration
 import org.apache.geode.management.internal.configuration.messages.SharedConfigurationStatusResponse;
 import org.apache.geode.management.internal.configuration.utils.XmlUtils;
 import org.apache.geode.management.internal.configuration.utils.ZipUtils;
+import org.apache.logging.log4j.Logger;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileWriter;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.sql.Timestamp;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactoryConfigurationError;
+import javax.xml.xpath.XPathExpressionException;
 
 @SuppressWarnings({"deprecation", "unchecked"})
 public class SharedConfiguration {
@@ -617,9 +617,9 @@ public class SharedConfiguration {
     if (configDirFile.exists()) {
       String configDirFileName2 = CLUSTER_CONFIG_ARTIFACTS_DIR_NAME
           + new SimpleDateFormat("yyyyMMddhhmm").format(new Date()) + "." + System.nanoTime();
-      File configDirFile2 = new File(FilenameUtils.concat(configDirFileName2, configDirFileName2));
+      File configDirFile2 = new File(configDirFile.getParent(), configDirFileName2);
       try {
-        FileUtils.moveDirectoryToDirectory(configDirFile, configDirFile2, true);
+        FileUtils.moveDirectory(configDirFile, configDirFile2);
       } catch (IOException e) {
         logger.info(e);
       }

http://git-wip-us.apache.org/repos/asf/geode/blob/a43941c7/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ImportSharedConfigurationArtifactsFunction.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ImportSharedConfigurationArtifactsFunction.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ImportSharedConfigurationArtifactsFunction.java
index 883a036..2ddeda6 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ImportSharedConfigurationArtifactsFunction.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ImportSharedConfigurationArtifactsFunction.java
@@ -14,7 +14,6 @@
  */
 package org.apache.geode.management.internal.cli.functions;
 
-import java.io.File;
 import org.apache.commons.io.FileUtils;
 import org.apache.geode.cache.execute.FunctionAdapter;
 import org.apache.geode.cache.execute.FunctionContext;
@@ -25,6 +24,8 @@ import org.apache.geode.management.internal.cli.CliUtil;
 import org.apache.geode.management.internal.cli.i18n.CliStrings;
 import org.apache.geode.management.internal.configuration.utils.ZipUtils;
 
+import java.io.File;
+
 /******
  * This function copies the zipped shared configuration, renames the existing shared configuration
  * directory and unzips the shared configuration.

http://git-wip-us.apache.org/repos/asf/geode/blob/a43941c7/geode-core/src/test/java/org/apache/geode/management/ConnectToLocatorSSLDUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/ConnectToLocatorSSLDUnitTest.java b/geode-core/src/test/java/org/apache/geode/management/ConnectToLocatorSSLDUnitTest.java
index 142ce17..df08640 100644
--- a/geode-core/src/test/java/org/apache/geode/management/ConnectToLocatorSSLDUnitTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/ConnectToLocatorSSLDUnitTest.java
@@ -92,19 +92,8 @@ public class ConnectToLocatorSSLDUnitTest extends JUnit4DistributedTestCase {
     GfshShellConnectionRule gfshConnector = new GfshShellConnectionRule(
         lsRule.getMember(0).getPort(), GfshShellConnectionRule.PortType.locator);
 
-    // when we connect too soon, we would get "Failed to retrieve RMIServer stub:
-    // javax.naming.CommunicationException [Root exception is java.rmi.NoSuchObjectException: no
-    // such object in table]" Exception.
-    // Tried to wait on jmx connector server being ready, but it doesn't work.
-    // Add the retry logic here to try at most 10 times for connection.
-    for (int i = 0; i < 10; i++) {
-      gfshConnector.connect(CliStrings.CONNECT__SECURITY_PROPERTIES,
-          securityPropsFile.getCanonicalPath());
-      if (gfshConnector.isConnected()) {
-        break;
-      }
-      Thread.currentThread().sleep(3000);
-    }
+    gfshConnector.connect(CliStrings.CONNECT__SECURITY_PROPERTIES,
+        securityPropsFile.getCanonicalPath());
 
     assertTrue(gfshConnector.isConnected());
     gfshConnector.close();

http://git-wip-us.apache.org/repos/asf/geode/blob/a43941c7/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigDUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigDUnitTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigDUnitTest.java
index 418999a..a0445d4 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigDUnitTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigDUnitTest.java
@@ -15,6 +15,8 @@
 
 package org.apache.geode.management.internal.configuration;
 
+import static java.util.Arrays.stream;
+import static java.util.stream.Collectors.joining;
 import static org.apache.geode.distributed.ConfigurationProperties.CLUSTER_CONFIGURATION_DIR;
 import static org.apache.geode.distributed.ConfigurationProperties.ENABLE_CLUSTER_CONFIGURATION;
 import static org.apache.geode.distributed.ConfigurationProperties.GROUPS;
@@ -29,124 +31,374 @@ import org.apache.geode.distributed.internal.InternalLocator;
 import org.apache.geode.distributed.internal.SharedConfiguration;
 import org.apache.geode.internal.ClassPathLoader;
 import org.apache.geode.internal.JarClassLoader;
+import org.apache.geode.internal.JarDeployer;
+import org.apache.geode.internal.lang.StringUtils;
+import org.apache.geode.management.cli.Result;
+import org.apache.geode.management.internal.cli.result.CommandResult;
 import org.apache.geode.management.internal.configuration.domain.Configuration;
 import org.apache.geode.management.internal.configuration.utils.ZipUtils;
 import org.apache.geode.test.dunit.internal.JUnit4DistributedTestCase;
+import org.apache.geode.test.dunit.rules.GfshShellConnectionRule;
 import org.apache.geode.test.dunit.rules.LocatorServerStartupRule;
 import org.apache.geode.test.dunit.rules.Member;
 import org.apache.geode.test.junit.categories.DistributedTest;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
 
 import java.io.File;
-import java.io.IOException;
 import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
 import java.util.Properties;
+import java.util.Set;
+import java.util.stream.Collectors;
 
 @Category(DistributedTest.class)
 public class ClusterConfigDUnitTest extends JUnit4DistributedTestCase {
-  private static final String EXPORTED_CLUSTER_CONFIG_ZIP_FILENAME = "cluster_config.zip";
-  private static final String[] CONFIG_NAMES = new String[] {"cluster", "group1", "group2"};
-
-  private static final ExpectedConfig NO_GROUP =
-      new ExpectedConfig().maxLogFileSize("5000").regions("regionForCluster").jars("cluster.jar");
-
-  private static final ExpectedConfig GROUP1 = new ExpectedConfig().maxLogFileSize("6000")
-      .regions("regionForCluster", "regionForGroup1").jars("cluster.jar", "group1.jar");
-
-  private static final ExpectedConfig GROUP2 = new ExpectedConfig().maxLogFileSize("7000")
-      .regions("regionForCluster", "regionForGroup2").jars("cluster.jar", "group2.jar");
-
-  private static final ExpectedConfig GROUP1_AND_2 = new ExpectedConfig().maxLogFileSize("7000")
-      .regions("regionForCluster", "regionForGroup1", "regionForGroup2")
-      .jars("cluster.jar", "group1.jar", "group2.jar");
-
-
-  private String locatorString;
 
+  private Properties locatorProps;
+  private Properties serverProps;
+  private GfshShellConnectionRule gfshConnector;
   @Rule
   public LocatorServerStartupRule lsRule = new LocatorServerStartupRule();
 
   @Before
-  public void setupFirstLocatorWithClusterConfigFromDirectory() throws Exception {
-    File locatorDir = lsRule.getRootFolder().newFolder("locator-0");
-
-    // The unzip should yield a cluster config directory structure like:
-    // tempFolder/locator-0/cluster_config/cluster/cluster.xml
-    // tempFolder/locator-0/cluster_config/cluster/cluster.properties
-    // tempFolder/locator-0/cluster_config/cluster/cluster.jar
-    // tempFolder/locator-0/cluster_config/group1/ {group1.xml, group1.properties, group1.jar}
-    // tempFolder/locator-0/cluster_config/group2/ ...
-    ZipUtils.unzip(getClass().getResource(EXPORTED_CLUSTER_CONFIG_ZIP_FILENAME).getPath(),
-        locatorDir.getCanonicalPath());
-
-    Properties locatorProps = new Properties();
+  public void before() throws Exception {
+    locatorProps = new Properties();
     locatorProps.setProperty(ENABLE_CLUSTER_CONFIGURATION, "true");
-    locatorProps.setProperty(LOAD_CLUSTER_CONFIGURATION_FROM_DIR, "true");
-    locatorProps.setProperty(CLUSTER_CONFIGURATION_DIR, locatorDir.getCanonicalPath());
 
-    Member firstLocator = lsRule.startLocatorVM(0, locatorProps);
-    locatorString = "localhost[" + firstLocator.getPort() + "]";
+    serverProps = new Properties();
+    serverProps.setProperty(USE_CLUSTER_CONFIGURATION, "true");
+  }
 
-    verifyLocatorConfigExistsInFileSystem(firstLocator.getWorkingDir());
-    firstLocator.invoke(this::verifyLocatorConfigExistsInInternalRegion);
+  @After
+  public void after() throws Exception {
+    if (gfshConnector != null) {
+      gfshConnector.close();
+    }
   }
 
   @Test
-  public void secondLocatorLoadsClusterConfigFromFirstLocator() throws IOException {
-    Properties secondLocatorProps = new Properties();
-    secondLocatorProps.setProperty(LOCATORS, locatorString);
-    secondLocatorProps.setProperty(ENABLE_CLUSTER_CONFIGURATION, "true");
-    Member secondLocator = lsRule.startLocatorVM(1, secondLocatorProps);
+  public void testStartLocator() throws Exception {
+    Member firstLocator = startLocatorWithLoadCCFromDir();
+
+    locatorProps.setProperty(LOCATORS, "localhost[" + firstLocator.getPort() + "]");
+    Member secondLocator = lsRule.startLocatorVM(1, locatorProps);
 
-    verifyLocatorConfig(secondLocator);
+    verifyClusterConfigZipLoadedInLocator(secondLocator);
   }
 
   @Test
-  public void serverWithZeroOrOneGroupsLoadCorrectConfigFromLocator() throws Exception {
-    Properties serverProps = new Properties();
-    serverProps.setProperty(LOCATORS, locatorString);
-    serverProps.setProperty(USE_CLUSTER_CONFIGURATION, "true");
+  public void testStartServerWithSingleGroup() throws Exception {
+    Member locator = startLocatorWithLoadCCFromDir();
 
-    Member serverWithNoGroup = lsRule.startServerVM(1, serverProps);
+    Member serverWithNoGroup = lsRule.startServerVM(1, serverProps, locator.getPort());
     verifyServerConfig(NO_GROUP, serverWithNoGroup);
 
     serverProps.setProperty(GROUPS, "group1");
-    Member serverForGroup1 = lsRule.startServerVM(2, serverProps);
+    Member serverForGroup1 = lsRule.startServerVM(2, serverProps, locator.getPort());
     verifyServerConfig(GROUP1, serverForGroup1);
 
     serverProps.setProperty(GROUPS, "group2");
-    Member serverForGroup2 = lsRule.startServerVM(3, serverProps);
+    Member serverForGroup2 = lsRule.startServerVM(3, serverProps, locator.getPort());
     verifyServerConfig(GROUP2, serverForGroup2);
   }
 
   @Test
-  public void oneServerWithMultipleGroupsLoadsCorrectConfigFromLocator() throws Exception {
-    Properties serverProps = new Properties();
-    serverProps.setProperty(LOCATORS, locatorString);
-    serverProps.setProperty(USE_CLUSTER_CONFIGURATION, "true");
+  public void testStartServerWithMultipleGroup() throws Exception {
+    Member locator = startLocatorWithLoadCCFromDir();
+
     serverProps.setProperty(GROUPS, "group1,group2");
-    Member serverWithNoGroup = lsRule.startServerVM(1, serverProps);
+    Member server = lsRule.startServerVM(1, serverProps, locator.getPort());
 
-    serverWithNoGroup.invoke(() -> this.verifyServerConfig(GROUP1_AND_2, serverWithNoGroup));
+    verifyServerConfig(GROUP1_AND_2, server);
   }
 
-  private void verifyLocatorConfig(Member locator) {
-    verifyLocatorConfigExistsInFileSystem(locator.getWorkingDir());
-    locator.invoke(this::verifyLocatorConfigExistsInInternalRegion);
+  @Test
+  public void testImportWithRunningServer() throws Exception {
+    String zipFilePath = getClass().getResource(EXPORTED_CLUSTER_CONFIG_ZIP_FILENAME).getPath();
+    // set up the locator/servers
+    Member locator = lsRule.startLocatorVM(0, locatorProps);
+    Member server1 = lsRule.startServerVM(1, serverProps, locator.getPort());
+    gfshConnector =
+        new GfshShellConnectionRule(locator.getPort(), GfshShellConnectionRule.PortType.locator);
+    gfshConnector.connect();
+    CommandResult result =
+        gfshConnector.executeCommand("import cluster-configuration --zip-file-name=" + zipFilePath);
+
+    assertThat(result.getStatus()).isEqualTo(Result.Status.ERROR);
   }
 
-  private void verifyServerConfig(ExpectedConfig expectedConfig, Member server)
-      throws ClassNotFoundException {
-    verifyServerJarFilesExistInFileSystem(server.getWorkingDir(), expectedConfig.jars);
-    server.invoke(() -> this.verifyServerConfigInMemory(expectedConfig));
+  @Test
+  public void testImportClusterConfig() throws Exception {
+    String zipFilePath = getClass().getResource(EXPORTED_CLUSTER_CONFIG_ZIP_FILENAME).getPath();
+    // set up the locator/servers
+    Member locator = lsRule.startLocatorVM(0, locatorProps);
+    verifyInitialLocatorConfigInFileSystem(locator);
+
+    gfshConnector =
+        new GfshShellConnectionRule(locator.getPort(), GfshShellConnectionRule.PortType.locator);
+    gfshConnector.connect();
+    assertThat(gfshConnector.isConnected()).isTrue();
+
+    CommandResult result =
+        gfshConnector.executeCommand("import cluster-configuration --zip-file-name=" + zipFilePath);
+    assertThat(result.getStatus()).isEqualTo(Result.Status.OK);
+
+    // verify that the previous folder is copied to "cluster_configxxxxxx".
+    String workingDirFiles = Arrays.stream(locator.getWorkingDir().listFiles()).map(File::getName)
+        .collect(joining(", "));
+    System.out.println("Locator working dir contains: " + workingDirFiles);
+    assertThat(locator.getWorkingDir().listFiles())
+        .filteredOn((File file) -> file.getName() != "cluster_config")
+        .filteredOn((File file) -> file.getName().startsWith("cluster_config")).isNotEmpty();
+    verifyClusterConfigZipLoadedInLocator(locator);
+
+    // start server1 with no group
+    Member server1 = lsRule.startServerVM(1, serverProps, locator.getPort());
+    verifyServerConfig(NO_GROUP, server1);
+
+    // start server2 in group1
+    serverProps.setProperty(GROUPS, "group1");
+    Member server2 = lsRule.startServerVM(2, serverProps, locator.getPort());
+    verifyServerConfig(GROUP1, server2);
+
+    // start server3 in group1 and group2
+    serverProps.setProperty(GROUPS, "group1,group2");
+    Member server3 = lsRule.startServerVM(3, serverProps, locator.getPort());
+    verifyServerConfig(GROUP1_AND_2, server3);
   }
 
-  private void verifyLocatorConfigExistsInFileSystem(File workingDir) {
-    File clusterConfigDir = new File(workingDir, "cluster_config");
+  @Test
+  public void testDeployToNoServer() throws Exception {
+    String clusterJarPath = getClass().getResource("cluster.jar").getPath();
+    // set up the locator/servers
+    Member locator = lsRule.startLocatorVM(0, locatorProps);
+
+    gfshConnector =
+        new GfshShellConnectionRule(locator.getPort(), GfshShellConnectionRule.PortType.locator);
+    gfshConnector.connect();
+    assertThat(gfshConnector.isConnected()).isTrue();
+
+    CommandResult result = gfshConnector.executeCommand("deploy --jar=" + clusterJarPath);
+    assertThat(result.getStatus()).isEqualTo(Result.Status.ERROR);
+  }
+
+  @Test
+  public void testDeploy() throws Exception {
+    String clusterJar = getClass().getResource("cluster.jar").getPath();
+    String group1Jar = getClass().getResource("group1.jar").getPath();
+    String group2Jar = getClass().getResource("group2.jar").getPath();
+
+    // set up the locator/servers
+    Member locator = lsRule.startLocatorVM(0, locatorProps);
+    // server1 in no group
+    Member server1 = lsRule.startServerVM(1, serverProps, locator.getPort());
+    //server2 in group1
+    serverProps.setProperty(GROUPS, "group1");
+    Member server2 = lsRule.startServerVM(2, serverProps, locator.getPort());
+    // server3 in group1 and group2
+    serverProps.setProperty(GROUPS, "group1,group2");
+    Member server3 = lsRule.startServerVM(3, serverProps, locator.getPort());
+
+    gfshConnector =
+        new GfshShellConnectionRule(locator.getPort(), GfshShellConnectionRule.PortType.locator);
+    gfshConnector.connect();
+    assertThat(gfshConnector.isConnected()).isTrue();
+
+    CommandResult result = gfshConnector.executeCommand("deploy --jar=" + clusterJar);
+    assertThat(result.getStatus()).isEqualTo(Result.Status.OK);
+
+    ExpectedConfig cluster = new ExpectedConfig().jars("cluster.jar").name("cluster");
+    verifyLocatorConfig(cluster, locator);
+    verifyLocatorConfigNotExist("group1", locator);
+    verifyLocatorConfigNotExist("group2", locator);
+    verifyServerConfig(cluster, server1);
+    verifyServerConfig(cluster, server2);
+    verifyServerConfig(cluster, server3);
+
+    result = gfshConnector.executeCommand("deploy --jar=" + group1Jar + " --group=group1");
+    assertThat(result.getStatus()).isEqualTo(Result.Status.OK);
+
+    ExpectedConfig serverGroupOne = new ExpectedConfig().jars("group1.jar", "cluster.jar");
+    ExpectedConfig locatorGroupOne = new ExpectedConfig().jars("group1.jar").name("group1");
+    verifyLocatorConfig(cluster, locator);
+    verifyLocatorConfig(locatorGroupOne, locator);
+    verifyLocatorConfigNotExist("group2", locator);
+    verifyServerConfig(cluster, server1);
+    verifyServerConfig(serverGroupOne, server2);
+    verifyServerConfig(serverGroupOne, server3);
+
+    result = gfshConnector.executeCommand("deploy --jar=" + group2Jar + " --group=group2");
+    assertThat(result.getStatus()).isEqualTo(Result.Status.OK);
+
+    ExpectedConfig groupOneAndTwo =
+        new ExpectedConfig().jars("group1.jar", "group2.jar", "cluster.jar");
+    ExpectedConfig locatorGroupTwo = new ExpectedConfig().jars("group2.jar").name("group2");
+    verifyLocatorConfig(cluster, locator);
+    verifyLocatorConfig(locatorGroupOne, locator);
+    verifyLocatorConfig(locatorGroupTwo, locator);
+    verifyServerConfig(cluster, server1);
+    verifyServerConfig(serverGroupOne, server2);
+    verifyServerConfig(groupOneAndTwo, server3);
+  }
+
+  @Test
+  public void testDeployMultiGroup() throws Exception {
+    String clusterJar = getClass().getResource("cluster.jar").getPath();
+    String group1Jar = getClass().getResource("group1.jar").getPath();
+
+    // set up the locator/servers
+    Member locator = lsRule.startLocatorVM(0, locatorProps);
+    // start 2 servers in the both groups
+    serverProps.setProperty(GROUPS, "group1");
+    Member server1 = lsRule.startServerVM(1, serverProps, locator.getPort());
+    serverProps.setProperty(GROUPS, "group2");
+    Member server2 = lsRule.startServerVM(2, serverProps, locator.getPort());
+    serverProps.setProperty(GROUPS, "group1,group2");
+    Member server3 = lsRule.startServerVM(3, serverProps, locator.getPort());
+
+    ExpectedConfig clusterConfig = new ExpectedConfig().name("cluster");
+    ExpectedConfig group1Config = new ExpectedConfig().name("group1");
+    ExpectedConfig group2Config = new ExpectedConfig().name("group2");
+
+    gfshConnector =
+        new GfshShellConnectionRule(locator.getPort(), GfshShellConnectionRule.PortType.locator);
+    gfshConnector.connect();
+    assertThat(gfshConnector.isConnected()).isTrue();
+
+    CommandResult result = gfshConnector.executeCommand("deploy --jar=" + clusterJar);
+    assertThat(result.getStatus()).isEqualTo(Result.Status.OK);
+
+    // deploy cluster.jar to the cluster
+    clusterConfig.addJar("cluster.jar");
+    verifyLocatorConfig(clusterConfig, locator);
+    verifyLocatorConfigNotExist("group1", locator);
+    verifyLocatorConfigNotExist("group2", locator);
+    verifyServerConfig(clusterConfig, server1);
+    verifyServerConfig(clusterConfig, server2);
+    verifyServerConfig(clusterConfig, server3);
+
+    // deploy group1.jar to both group1 and group2
+    result = gfshConnector.executeCommand("deploy --jar=" + group1Jar + " --group=group1,group2");
+    assertThat(result.getStatus()).isEqualTo(Result.Status.OK);
+    group1Config.addJar("group1.jar");
+    group2Config.addJar("group1.jar");
+    ExpectedConfig serverConfig = new ExpectedConfig().jars("cluster.jar", "group1.jar");
+    verifyLocatorConfig(clusterConfig, locator);
+    verifyLocatorConfig(group1Config, locator);
+    verifyLocatorConfig(group2Config, locator);
+    verifyServerConfig(serverConfig, server1);
+    verifyServerConfig(serverConfig, server2);
+    verifyServerConfig(serverConfig, server3);
+
+    // test undeploy cluster
+    result = gfshConnector.executeCommand("undeploy --jar=cluster.jar");
+    assertThat(result.getStatus()).isEqualTo(Result.Status.OK);
+
+    clusterConfig.removeJar("cluster.jar");
+    verifyLocatorConfig(clusterConfig, locator);
+    verifyLocatorConfig(group1Config, locator);
+    verifyLocatorConfig(group2Config, locator);
+    serverConfig.removeJar("cluster.jar");
+    verifyServerConfig(serverConfig, server1);
+    verifyServerConfig(serverConfig, server2);
+    verifyServerConfig(serverConfig, server2);
+
+    result = gfshConnector.executeCommand("undeploy --jar=group1.jar --group=group1");
+    assertThat(result.getStatus()).isEqualTo(Result.Status.OK);
+
+    group1Config.removeJar("group1.jar");
+    verifyLocatorConfig(clusterConfig, locator);
+    verifyLocatorConfig(group1Config, locator);
+    verifyLocatorConfig(group2Config, locator);
+    // server2 is not in group1, so serverConfig remains unchanged
+    verifyServerConfig(serverConfig, server2);
+
+    // server1 and server3 is in group1, so their group1.jar is removed
+    serverConfig.removeJar("group1.jar");
+    verifyServerConfig(serverConfig, server1);
+    verifyServerConfig(serverConfig, server3);
+  }
+
+
+  private Member startLocatorWithLoadCCFromDir() throws Exception {
+    File locatorDir = lsRule.getRootFolder().newFolder("locator-0");
+    File configDir = new File(locatorDir, "cluster_config");
+
+    // The unzip should yield a cluster config directory structure like:
+    // tempFolder/locator-0/cluster_config/cluster/cluster.xml
+    // tempFolder/locator-0/cluster_config/cluster/cluster.properties
+    // tempFolder/locator-0/cluster_config/cluster/cluster.jar
+    // tempFolder/locator-0/cluster_config/group1/ {group1.xml, group1.properties, group1.jar}
+    // tempFolder/locator-0/cluster_config/group2/ ...
+    ZipUtils.unzip(getClass().getResource(EXPORTED_CLUSTER_CONFIG_ZIP_FILENAME).getPath(),
+        configDir.getCanonicalPath());
+
+    Properties properties = new Properties();
+    properties.setProperty(ENABLE_CLUSTER_CONFIGURATION, "true");
+    properties.setProperty(LOAD_CLUSTER_CONFIGURATION_FROM_DIR, "true");
+    properties.setProperty(CLUSTER_CONFIGURATION_DIR, locatorDir.getCanonicalPath());
+
+    Member locator = lsRule.startLocatorVM(0, properties);
+    verifyClusterConfigZipLoadedInLocator(locator);
+
+    return locator;
+  }
+
+  private static String getServerJarName(String jarName) {
+    return JarDeployer.JAR_PREFIX + jarName + "#1";
+  }
+
+
+  public static final String EXPORTED_CLUSTER_CONFIG_ZIP_FILENAME = "cluster_config.zip";
+  public static final String[] CONFIG_NAMES = new String[] {"cluster", "group1", "group2"};
+
+  public static final ExpectedConfig NO_GROUP =
+      new ExpectedConfig().maxLogFileSize("5000").regions("regionForCluster").jars("cluster.jar");
+
+  public static final ExpectedConfig GROUP1 = new ExpectedConfig().maxLogFileSize("6000")
+      .regions("regionForCluster", "regionForGroup1").jars("cluster.jar", "group1.jar");
+
+  public static final ExpectedConfig GROUP2 = new ExpectedConfig().maxLogFileSize("7000")
+      .regions("regionForCluster", "regionForGroup2").jars("cluster.jar", "group2.jar");
+
+  public static final ExpectedConfig GROUP1_AND_2 = new ExpectedConfig().maxLogFileSize("7000")
+      .regions("regionForCluster", "regionForGroup1", "regionForGroup2")
+      .jars("cluster.jar", "group1.jar", "group2.jar");
+
+
+  public static void verifyInitialLocatorConfigInFileSystem(Member member) {
+    File clusterConfigDir = new File(member.getWorkingDir(), "cluster_config");
+    assertThat(clusterConfigDir).exists();
+    File configDir = new File(clusterConfigDir, "cluster");
+    assertThat(configDir).exists();
+    File properties = new File(configDir, "cluster.properties");
+    assertThat(properties).exists();
+    File xml = new File(configDir, "cluster.xml");
+    assertThat(xml).exists();
+  }
+
+  public static void verifyClusterConfigZipLoadedInLocator(Member locator) {
+    // verify loaded in memeory
+    locator.invoke(() -> {
+      InternalLocator internalLocator = LocatorServerStartupRule.locatorStarter.locator;
+      SharedConfiguration sc = internalLocator.getSharedConfiguration();
+
+      for (String configName : CONFIG_NAMES) {
+        Configuration config = sc.getConfiguration(configName);
+        assertThat(config).isNotNull();
+      }
+    });
+
+    // verify loaded into the file system
+    File clusterConfigDir = new File(locator.getWorkingDir(), "cluster_config");
     assertThat(clusterConfigDir).exists();
 
     for (String configName : CONFIG_NAMES) {
@@ -160,24 +412,54 @@ public class ClusterConfigDUnitTest extends JUnit4DistributedTestCase {
     }
   }
 
-  private void verifyLocatorConfigExistsInInternalRegion() throws Exception {
-    InternalLocator internalLocator = LocatorServerStartupRule.locatorStarter.locator;
-    SharedConfiguration sc = internalLocator.getSharedConfiguration();
+  public static void verifyServerConfig(ExpectedConfig expectedConfig, Member server)
+      throws ClassNotFoundException {
+    verifyServerJarFilesExistInFileSystem(server.getWorkingDir(), expectedConfig.jars);
+    server.invoke(() -> verifyServerConfigInMemory(expectedConfig));
+  }
 
-    for (String configName : CONFIG_NAMES) {
-      Configuration config = sc.getConfiguration(configName);
-      assertThat(config).isNotNull();
+  public static void verifyLocatorConfig(ExpectedConfig expectedConfig, Member locator){
+    // verify info exists in memeory
+    locator.invoke(() -> {
+      InternalLocator internalLocator = LocatorServerStartupRule.locatorStarter.locator;
+      SharedConfiguration sc = internalLocator.getSharedConfiguration();
+      Configuration config = sc.getConfiguration(expectedConfig.name);
+      assertThat(config.getJarNames()).isEqualTo(expectedConfig.jars);
+    });
+
+    // verify files exists on disc
+    for(String jar : expectedConfig.jars) {
+      assertThat(new File(locator.getWorkingDir(), "/cluster_config/"+expectedConfig.name+"/"+jar))
+          .exists();
     }
   }
 
-  private void verifyServerConfigInMemory(ExpectedConfig expectedConfig)
+  public static void verifyLocatorConfigNotExist(String configName, Member locator){
+    // verify info not in memeory
+    locator.invoke(() -> {
+      InternalLocator internalLocator = LocatorServerStartupRule.locatorStarter.locator;
+      SharedConfiguration sc = internalLocator.getSharedConfiguration();
+      Configuration config = sc.getConfiguration(configName);
+      assertThat(config).isNull();
+    });
+
+    // verify files does not
+    assertThat(new File(locator.getWorkingDir(), "/cluster_config/"+configName))
+        .doesNotExist();
+  }
+
+  private static void verifyServerConfigInMemory(ExpectedConfig expectedConfig)
       throws ClassNotFoundException {
     Cache cache = LocatorServerStartupRule.serverStarter.cache;
+
     for (String region : expectedConfig.regions) {
       assertThat(cache.getRegion(region)).isNotNull();
     }
-    Properties props = cache.getDistributedSystem().getProperties();
-    assertThat(props.getProperty(LOG_FILE_SIZE_LIMIT)).isEqualTo(expectedConfig.maxLogFileSize);
+
+    if (!StringUtils.isBlank(expectedConfig.maxLogFileSize)) {
+      Properties props = cache.getDistributedSystem().getProperties();
+      assertThat(props.getProperty(LOG_FILE_SIZE_LIMIT)).isEqualTo(expectedConfig.maxLogFileSize);
+    }
 
     for (String jar : expectedConfig.jars) {
       JarClassLoader jarClassLoader = findJarClassLoader(jar);
@@ -186,16 +468,16 @@ public class ClusterConfigDUnitTest extends JUnit4DistributedTestCase {
     }
   }
 
-  private void verifyServerJarFilesExistInFileSystem(File workingDir, String[] jarNames) {
-    assertThat(workingDir.listFiles()).isNotEmpty();
-
+  private static void verifyServerJarFilesExistInFileSystem(File workingDir, Set<String> jarNames) {
+    Set<String> expectedJarNames = new HashSet<>();
     for (String jarName : jarNames) {
-      assertThat(workingDir.listFiles()).filteredOn((File file) -> file.getName().contains(jarName))
-          .isNotEmpty();
+      expectedJarNames.add(getServerJarName(jarName));
     }
+    Set<String> actualJarNames = Arrays.stream(workingDir.list((dir, filename) -> filename.contains(".jar"))).collect(Collectors.toSet());
+    assertThat(actualJarNames).isEqualTo(expectedJarNames);
   }
 
-  private String nameOfClassContainedInJar(String jarName) {
+  private static String nameOfClassContainedInJar(String jarName) {
     switch (jarName) {
       case "cluster.jar":
         return "Cluster";
@@ -209,7 +491,7 @@ public class ClusterConfigDUnitTest extends JUnit4DistributedTestCase {
     }
   }
 
-  private JarClassLoader findJarClassLoader(final String jarName) {
+  private static JarClassLoader findJarClassLoader(final String jarName) {
     Collection<ClassLoader> classLoaders = ClassPathLoader.getLatest().getClassLoaders();
     for (ClassLoader classLoader : classLoaders) {
       if (classLoader instanceof JarClassLoader
@@ -222,8 +504,9 @@ public class ClusterConfigDUnitTest extends JUnit4DistributedTestCase {
 
   private static class ExpectedConfig implements Serializable {
     public String maxLogFileSize;
-    public String[] regions;
-    public String[] jars;
+    public Set<String> regions = new HashSet<>();
+    public Set<String> jars = new HashSet<>();
+    public String name;
 
     public ExpectedConfig maxLogFileSize(String maxLogFileSize) {
       this.maxLogFileSize = maxLogFileSize;
@@ -231,13 +514,30 @@ public class ClusterConfigDUnitTest extends JUnit4DistributedTestCase {
     }
 
     public ExpectedConfig regions(String... regions) {
-      this.regions = regions;
+      this.regions.addAll(Arrays.asList(regions));
       return this;
     }
 
     public ExpectedConfig jars(String... jars) {
-      this.jars = jars;
+      this.jars.addAll(Arrays.asList(jars));
+      return this;
+    }
+
+    public ExpectedConfig removeJar(String jar) {
+      this.jars.remove(jar);
+      return this;
+    }
+
+    public ExpectedConfig addJar(String jar) {
+      this.jars.add(jar);
+      return this;
+    }
+
+    public ExpectedConfig name(String name){
+      this.name = name;
       return this;
     }
   }
+
+
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/a43941c7/geode-core/src/test/java/org/apache/geode/management/internal/security/DeployCommandsSecurityTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/security/DeployCommandsSecurityTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/security/DeployCommandsSecurityTest.java
index b040751..e89bd62 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/security/DeployCommandsSecurityTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/security/DeployCommandsSecurityTest.java
@@ -62,7 +62,6 @@ public class DeployCommandsSecurityTest {
   @BeforeClass
   public static void beforeClass() throws Exception {
     File zipFile = temporaryFolder.newFile(zipFileName);
-    zipFile.createNewFile();
     deployCommand = "deploy --jar=" + zipFile.getAbsolutePath();
   }
 

http://git-wip-us.apache.org/repos/asf/geode/blob/a43941c7/geode-core/src/test/java/org/apache/geode/test/dunit/rules/GfshShellConnectionRule.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/test/dunit/rules/GfshShellConnectionRule.java b/geode-core/src/test/java/org/apache/geode/test/dunit/rules/GfshShellConnectionRule.java
index 7490928..04807ec 100644
--- a/geode-core/src/test/java/org/apache/geode/test/dunit/rules/GfshShellConnectionRule.java
+++ b/geode-core/src/test/java/org/apache/geode/test/dunit/rules/GfshShellConnectionRule.java
@@ -81,9 +81,22 @@ public class GfshShellConnectionRule extends DescribedExternalResource {
       }
     }
 
-    gfsh.executeCommand(connectCommand.toString());
-
-    CommandResult result = (CommandResult) gfsh.getResult();
+    // when we connect too soon, we would get "Failed to retrieve RMIServer stub:
+    // javax.naming.CommunicationException [Root exception is java.rmi.NoSuchObjectException: no
+    // such object in table]" Exception.
+    // Tried to wait on jmx connector server being ready, but it doesn't work.
+    // Add the retry logic here to try at most 10 times for connection.
+    CommandResult result = null;
+    for (int i = 0; i < 50; i++) {
+      System.out.println("trying to connect, attempt " + i);
+      gfsh.executeCommand(connectCommand.toString());
+      result = (CommandResult) gfsh.getResult();
+      System.out.println(gfsh.outputString);
+      if (!gfsh.outputString.contains("no such object in table")) {
+        break;
+      }
+      Thread.currentThread().sleep(2000);
+    }
     connected = (result.getStatus() == Result.Status.OK);
   }
 
@@ -109,6 +122,11 @@ public class GfshShellConnectionRule extends DescribedExternalResource {
     return gfsh;
   }
 
+  public CommandResult executeCommand(String command) throws Exception {
+    gfsh.executeCommand(command);
+    return (CommandResult) gfsh.getResult();
+  }
+
   public boolean isConnected() {
     return connected;
   }

http://git-wip-us.apache.org/repos/asf/geode/blob/a43941c7/geode-core/src/test/java/org/apache/geode/test/dunit/rules/LocatorServerStartupRule.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/test/dunit/rules/LocatorServerStartupRule.java b/geode-core/src/test/java/org/apache/geode/test/dunit/rules/LocatorServerStartupRule.java
index b096cbb..3d43b93 100644
--- a/geode-core/src/test/java/org/apache/geode/test/dunit/rules/LocatorServerStartupRule.java
+++ b/geode-core/src/test/java/org/apache/geode/test/dunit/rules/LocatorServerStartupRule.java
@@ -19,7 +19,6 @@ package org.apache.geode.test.dunit.rules;
 import static org.apache.geode.distributed.ConfigurationProperties.NAME;
 import static org.apache.geode.test.dunit.Host.getHost;
 
-import org.apache.geode.test.dunit.Host;
 import org.apache.geode.test.dunit.Invoke;
 import org.apache.geode.test.dunit.VM;
 import org.apache.geode.test.junit.rules.serializable.SerializableTemporaryFolder;

http://git-wip-us.apache.org/repos/asf/geode/blob/a43941c7/geode-core/src/test/resources/org/apache/geode/management/internal/configuration/cluster.jar
----------------------------------------------------------------------
diff --git a/geode-core/src/test/resources/org/apache/geode/management/internal/configuration/cluster.jar b/geode-core/src/test/resources/org/apache/geode/management/internal/configuration/cluster.jar
new file mode 100755
index 0000000..9c9541d
Binary files /dev/null and b/geode-core/src/test/resources/org/apache/geode/management/internal/configuration/cluster.jar differ

http://git-wip-us.apache.org/repos/asf/geode/blob/a43941c7/geode-core/src/test/resources/org/apache/geode/management/internal/configuration/cluster_config.zip
----------------------------------------------------------------------
diff --git a/geode-core/src/test/resources/org/apache/geode/management/internal/configuration/cluster_config.zip b/geode-core/src/test/resources/org/apache/geode/management/internal/configuration/cluster_config.zip
index 37cacbf..11fc6bb 100644
Binary files a/geode-core/src/test/resources/org/apache/geode/management/internal/configuration/cluster_config.zip and b/geode-core/src/test/resources/org/apache/geode/management/internal/configuration/cluster_config.zip differ

http://git-wip-us.apache.org/repos/asf/geode/blob/a43941c7/geode-core/src/test/resources/org/apache/geode/management/internal/configuration/group1.jar
----------------------------------------------------------------------
diff --git a/geode-core/src/test/resources/org/apache/geode/management/internal/configuration/group1.jar b/geode-core/src/test/resources/org/apache/geode/management/internal/configuration/group1.jar
new file mode 100755
index 0000000..fa105ab
Binary files /dev/null and b/geode-core/src/test/resources/org/apache/geode/management/internal/configuration/group1.jar differ

http://git-wip-us.apache.org/repos/asf/geode/blob/a43941c7/geode-core/src/test/resources/org/apache/geode/management/internal/configuration/group2.jar
----------------------------------------------------------------------
diff --git a/geode-core/src/test/resources/org/apache/geode/management/internal/configuration/group2.jar b/geode-core/src/test/resources/org/apache/geode/management/internal/configuration/group2.jar
new file mode 100755
index 0000000..b251f0d
Binary files /dev/null and b/geode-core/src/test/resources/org/apache/geode/management/internal/configuration/group2.jar differ