You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by ds...@apache.org on 2019/02/01 17:47:55 UTC

[geode] branch develop updated: GEODE-6273: add group to jdbc-mapping create and describe (#3100)

This is an automated email from the ASF dual-hosted git repository.

dschneider pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/geode.git


The following commit(s) were added to refs/heads/develop by this push:
     new 9b3845d  GEODE-6273: add group to jdbc-mapping create and describe (#3100)
9b3845d is described below

commit 9b3845d8ccf79fded6634e13745b87d28a4171b4
Author: Xiaojian Zhou <ge...@users.noreply.github.com>
AuthorDate: Fri Feb 1 09:47:40 2019 -0800

    GEODE-6273: add group to jdbc-mapping create and describe (#3100)
    
    gfsh create jdbc-mapping and describe jdbc-mapping now have a --group option.
    
    Co-authored-by: Scott Jewell <sj...@pivotal.io>
    Co-authored-by: Jianxia Chen <jc...@pivotal.io>
    Co-authored-by: Ben Ross <br...@pivotal.io>
---
 .../cli/CreateMappingCommandDUnitTest.java         | 437 ++++++++++++++++++---
 .../cli/DescribeMappingCommandDUnitTest.java       | 270 +++++++++++--
 .../codeAnalysis/sanctionedDataSerializables.txt   |   3 -
 .../jdbc/internal/cli/CreateMappingCommand.java    |  31 +-
 .../jdbc/internal/cli/DescribeMappingCommand.java  | 150 ++++++-
 .../jdbc/internal/cli/DescribeMappingFunction.java |  76 ----
 .../util/internal/DescribeMappingResult.java       |  32 +-
 .../connectors/util/internal/MappingConstants.java |   1 +
 .../sanctioned-geode-connectors-serializables.txt  |   1 -
 .../internal/cli/CreateMappingCommandTest.java     |  87 +++-
 .../internal/cli/DescribeMappingFunctionTest.java  | 176 ---------
 .../util/DescribeMappingCommandTest.java           | 242 +++++++++---
 .../util/internal/DescribeMappingResultTest.java   |  61 ---
 .../geode/management/internal/cli/CliUtil.java     |  14 +-
 .../test/junit/assertions/CommandResultAssert.java |  11 +-
 15 files changed, 1034 insertions(+), 558 deletions(-)

diff --git a/geode-connectors/src/distributedTest/java/org/apache/geode/connectors/jdbc/internal/cli/CreateMappingCommandDUnitTest.java b/geode-connectors/src/distributedTest/java/org/apache/geode/connectors/jdbc/internal/cli/CreateMappingCommandDUnitTest.java
index cfc3838..1f47c2d 100644
--- a/geode-connectors/src/distributedTest/java/org/apache/geode/connectors/jdbc/internal/cli/CreateMappingCommandDUnitTest.java
+++ b/geode-connectors/src/distributedTest/java/org/apache/geode/connectors/jdbc/internal/cli/CreateMappingCommandDUnitTest.java
@@ -17,6 +17,7 @@ package org.apache.geode.connectors.jdbc.internal.cli;
 import static org.apache.geode.connectors.jdbc.internal.cli.CreateMappingCommand.CREATE_MAPPING;
 import static org.apache.geode.connectors.util.internal.MappingConstants.CATALOG_NAME;
 import static org.apache.geode.connectors.util.internal.MappingConstants.DATA_SOURCE_NAME;
+import static org.apache.geode.connectors.util.internal.MappingConstants.GROUP_NAME;
 import static org.apache.geode.connectors.util.internal.MappingConstants.ID_NAME;
 import static org.apache.geode.connectors.util.internal.MappingConstants.PDX_NAME;
 import static org.apache.geode.connectors.util.internal.MappingConstants.REGION_NAME;
@@ -59,6 +60,11 @@ import org.apache.geode.test.junit.rules.serializable.SerializableTestName;
 public class CreateMappingCommandDUnitTest {
 
   private static final String TEST_REGION = "testRegion";
+  private static final String GROUP1_REGION = "group1Region";
+  private static final String GROUP2_REGION = "group2Region";
+  private static final String GROUP1_GROUP2_REGION = "group1Group2Region";
+  private static final String TEST_GROUP1 = "testGroup1";
+  private static final String TEST_GROUP2 = "testGroup2";
 
   @Rule
   public transient GfshCommandRule gfsh = new GfshCommandRule();
@@ -70,38 +76,52 @@ public class CreateMappingCommandDUnitTest {
   public SerializableTestName testName = new SerializableTestName();
 
   private MemberVM locator;
-  private MemberVM server;
+  private MemberVM server1;
+  private MemberVM server2;
+  private MemberVM server3;
+  private MemberVM server4;
 
   @Before
   public void before() throws Exception {
     locator = startupRule.startLocatorVM(0);
-    server = startupRule.startServerVM(1, locator.getPort());
+    server1 = startupRule.startServerVM(1, locator.getPort());
+    server2 = startupRule.startServerVM(2, TEST_GROUP1, locator.getPort());
+    server3 = startupRule.startServerVM(3, TEST_GROUP2, locator.getPort());
+    server4 = startupRule.startServerVM(4, TEST_GROUP1 + "," + TEST_GROUP2, locator.getPort());
 
     gfsh.connectAndVerify(locator);
 
   }
 
-  public void cleanUp() throws Exception {
-    startupRule.stop(0);
-    startupRule.stop(1);
-    gfsh.disconnect();
-  }
-
   private void setupReplicate(String regionName) {
     setupReplicate(regionName, false);
   }
 
+  // TODO: we can refactor to create subclass to test different combination of server groups
+  // each with different 'create region' and 'create jdbc-mapping' commands
   private void setupReplicate(String regionName, boolean addLoader) {
     gfsh.executeAndAssertThat("create region --name=" + regionName + " --type=REPLICATE"
         + (addLoader ? " --cache-loader=" + JdbcLoader.class.getName() : ""))
         .statusIsSuccess();
   }
 
+  private void setupGroupReplicate(String regionName, String groupNames) {
+    gfsh.executeAndAssertThat(
+        "create region --name=" + regionName + " --type=REPLICATE --groups=" + groupNames)
+        .statusIsSuccess();
+  }
+
   private void setupPartition(String regionName) {
     gfsh.executeAndAssertThat("create region --name=" + regionName + " --type=PARTITION")
         .statusIsSuccess();
   }
 
+  private void setupGroupPartition(String regionName, String groupNames) {
+    gfsh.executeAndAssertThat(
+        "create region --name=" + regionName + " --type=PARTITION --groups=" + groupNames)
+        .statusIsSuccess();
+  }
+
   private void setupAsyncEventQueue(String regionName) {
     gfsh.executeAndAssertThat(
         "create async-event-queue --id="
@@ -110,14 +130,17 @@ public class CreateMappingCommandDUnitTest {
         .statusIsSuccess();
   }
 
-  private static RegionMapping getRegionMappingFromClusterConfig(String regionName) {
+  private static RegionMapping getRegionMappingFromClusterConfig(String regionName,
+      String groups) {
     CacheConfig cacheConfig =
-        InternalLocator.getLocator().getConfigurationPersistenceService().getCacheConfig(null);
+        InternalLocator.getLocator().getConfigurationPersistenceService().getCacheConfig(groups);
     RegionConfig regionConfig = cacheConfig.getRegions().stream()
         .filter(region -> region.getName().equals(convertRegionPathToName(regionName))).findFirst()
         .orElse(null);
-    return (RegionMapping) regionConfig.getCustomRegionElements().stream()
-        .filter(element -> element instanceof RegionMapping).findFirst().orElse(null);
+    RegionMapping regionMapping =
+        (RegionMapping) regionConfig.getCustomRegionElements().stream()
+            .filter(element -> element instanceof RegionMapping).findFirst().orElse(null);
+    return regionMapping;
   }
 
   private static RegionMapping getRegionMappingFromService(String regionName) {
@@ -126,9 +149,10 @@ public class CreateMappingCommandDUnitTest {
   }
 
   private static void validateAsyncEventQueueCreatedInClusterConfig(String regionName,
+      String groups,
       boolean isParallel) {
     CacheConfig cacheConfig =
-        InternalLocator.getLocator().getConfigurationPersistenceService().getCacheConfig(null);
+        InternalLocator.getLocator().getConfigurationPersistenceService().getCacheConfig(groups);
     List<CacheConfig.AsyncEventQueue> queueList = cacheConfig.getAsyncEventQueues();
     CacheConfig.AsyncEventQueue queue = queueList.get(0);
     String queueName = CreateMappingCommand.createAsyncEventQueueName(regionName);
@@ -145,9 +169,11 @@ public class CreateMappingCommandDUnitTest {
     return regionPath;
   }
 
-  private static void validateRegionAlteredInClusterConfig(String regionName, boolean synchronous) {
+  private static void validateRegionAlteredInClusterConfig(String regionName,
+      String groups,
+      boolean synchronous) {
     CacheConfig cacheConfig =
-        InternalLocator.getLocator().getConfigurationPersistenceService().getCacheConfig(null);
+        InternalLocator.getLocator().getConfigurationPersistenceService().getCacheConfig(groups);
     RegionConfig regionConfig = cacheConfig.getRegions().stream()
         .filter(region -> region.getName().equals(convertRegionPathToName(regionName))).findFirst()
         .orElse(null);
@@ -184,6 +210,218 @@ public class CreateMappingCommandDUnitTest {
   }
 
   @Test
+  @Parameters({GROUP1_REGION, "/" + GROUP1_REGION})
+  public void createMappingReplicatedUpdatesServiceAndClusterConfigForServerGroup(
+      String regionName) {
+    setupGroupReplicate(regionName, TEST_GROUP1);
+    CommandStringBuilder csb = new CommandStringBuilder(CREATE_MAPPING);
+    csb.addOption(REGION_NAME, regionName);
+    csb.addOption(DATA_SOURCE_NAME, "connection");
+    csb.addOption(TABLE_NAME, "myTable");
+    csb.addOption(PDX_NAME, "myPdxClass");
+    csb.addOption(ID_NAME, "myId");
+    csb.addOption(CATALOG_NAME, "myCatalog");
+    csb.addOption(SCHEMA_NAME, "mySchema");
+    csb.addOption(GROUP_NAME, TEST_GROUP1);
+
+    gfsh.executeAndAssertThat(csb.toString()).statusIsSuccess();
+
+    // TEST_GROUP1 only contains server2 and server 4
+    server2.invoke(() -> {
+      RegionMapping mapping = getRegionMappingFromService(regionName);
+      assertValidMappingOnServer(mapping, regionName, false, false);
+    });
+
+    server4.invoke(() -> {
+      RegionMapping mapping = getRegionMappingFromService(regionName);
+      assertValidMappingOnServer(mapping, regionName, false, false);
+    });
+
+    server1.invoke(() -> {
+      RegionMapping mapping = getRegionMappingFromService(regionName);
+      assertThat(mapping).isNull();
+    });
+
+    server3.invoke(() -> {
+      RegionMapping mapping = getRegionMappingFromService(regionName);
+      assertThat(mapping).isNull();
+    });
+
+    locator.invoke(() -> {
+      RegionMapping regionMapping = getRegionMappingFromClusterConfig(regionName, TEST_GROUP1);
+      assertValidMappingOnLocator(regionMapping, regionName, TEST_GROUP1, false, false);
+    });
+  }
+
+  @Test
+  @Parameters({GROUP2_REGION, "/" + GROUP2_REGION})
+  public void createMappingPartitionedUpdatesServiceAndClusterConfigForServerGroup(
+      String regionName) {
+    setupGroupPartition(regionName, TEST_GROUP2);
+    CommandStringBuilder csb = new CommandStringBuilder(CREATE_MAPPING);
+    csb.addOption(REGION_NAME, regionName);
+    csb.addOption(DATA_SOURCE_NAME, "connection");
+    csb.addOption(TABLE_NAME, "myTable");
+    csb.addOption(PDX_NAME, "myPdxClass");
+    csb.addOption(ID_NAME, "myId");
+    csb.addOption(CATALOG_NAME, "myCatalog");
+    csb.addOption(SCHEMA_NAME, "mySchema");
+    csb.addOption(GROUP_NAME, TEST_GROUP2);
+
+    gfsh.executeAndAssertThat(csb.toString()).statusIsSuccess();
+
+    // TEST_GROUP2 only contains server3 and server4
+    server3.invoke(() -> {
+      RegionMapping mapping = getRegionMappingFromService(regionName);
+      assertValidMappingOnServer(mapping, regionName, false, true);
+    });
+
+    server4.invoke(() -> {
+      RegionMapping mapping = getRegionMappingFromService(regionName);
+      assertValidMappingOnServer(mapping, regionName, false, true);
+    });
+
+    server1.invoke(() -> {
+      RegionMapping mapping = getRegionMappingFromService(regionName);
+      assertThat(mapping).isNull();
+    });
+
+    server2.invoke(() -> {
+      RegionMapping mapping = getRegionMappingFromService(regionName);
+      assertThat(mapping).isNull();
+    });
+
+    locator.invoke(() -> {
+      RegionMapping regionMapping = getRegionMappingFromClusterConfig(regionName, TEST_GROUP2);
+      assertValidMappingOnLocator(regionMapping, regionName, TEST_GROUP2, false, true);
+    });
+  }
+
+  @Test
+  @Parameters({GROUP1_GROUP2_REGION, "/" + GROUP1_GROUP2_REGION})
+  public void createMappingReplicatedUpdatesServiceAndClusterConfigForMultiServerGroup(
+      String regionName) {
+    setupGroupReplicate(regionName, TEST_GROUP1 + "," + TEST_GROUP2);
+    CommandStringBuilder csb = new CommandStringBuilder(CREATE_MAPPING);
+    csb.addOption(REGION_NAME, regionName);
+    csb.addOption(DATA_SOURCE_NAME, "connection");
+    csb.addOption(TABLE_NAME, "myTable");
+    csb.addOption(PDX_NAME, "myPdxClass");
+    csb.addOption(ID_NAME, "myId");
+    csb.addOption(CATALOG_NAME, "myCatalog");
+    csb.addOption(SCHEMA_NAME, "mySchema");
+    csb.addOption(GROUP_NAME, TEST_GROUP1 + "," + TEST_GROUP2);
+
+    gfsh.executeAndAssertThat(csb.toString()).statusIsSuccess();
+
+    // TEST_GROUP1 and TEST_GROUP2 only contains server 2, server 3, and server 4
+    server2.invoke(() -> {
+      RegionMapping mapping = getRegionMappingFromService(regionName);
+      assertValidMappingOnServer(mapping, regionName, false, false);
+    });
+
+    server3.invoke(() -> {
+      RegionMapping mapping = getRegionMappingFromService(regionName);
+      assertValidMappingOnServer(mapping, regionName, false, false);
+    });
+
+    server4.invoke(() -> {
+      RegionMapping mapping = getRegionMappingFromService(regionName);
+      assertValidMappingOnServer(mapping, regionName, false, false);
+    });
+
+    server1.invoke(() -> {
+      RegionMapping mapping = getRegionMappingFromService(regionName);
+      assertThat(mapping).isNull();
+    });
+
+    locator.invoke(() -> {
+      RegionMapping regionMapping = getRegionMappingFromClusterConfig(regionName, TEST_GROUP1);
+      assertValidMappingOnLocator(regionMapping, regionName, TEST_GROUP1, false, false);
+    });
+  }
+
+  @Test
+  @Parameters({GROUP1_GROUP2_REGION, "/" + GROUP1_GROUP2_REGION})
+  public void createMappingPartitionedUpdatesServiceAndClusterConfigForMultiServerGroup(
+      String regionName) {
+    setupGroupPartition(regionName, TEST_GROUP1 + "," + TEST_GROUP2);
+    CommandStringBuilder csb = new CommandStringBuilder(CREATE_MAPPING);
+    csb.addOption(REGION_NAME, regionName);
+    csb.addOption(DATA_SOURCE_NAME, "connection");
+    csb.addOption(TABLE_NAME, "myTable");
+    csb.addOption(PDX_NAME, "myPdxClass");
+    csb.addOption(ID_NAME, "myId");
+    csb.addOption(CATALOG_NAME, "myCatalog");
+    csb.addOption(SCHEMA_NAME, "mySchema");
+    csb.addOption(GROUP_NAME, TEST_GROUP1 + "," + TEST_GROUP2);
+
+    gfsh.executeAndAssertThat(csb.toString()).statusIsSuccess();
+
+    // TEST_GROUP1 and TEST_GROUP2 only contains server 2, server 3, and server 4
+    server2.invoke(() -> {
+      RegionMapping mapping = getRegionMappingFromService(regionName);
+      assertValidMappingOnServer(mapping, regionName, false, true);
+    });
+
+    server3.invoke(() -> {
+      RegionMapping mapping = getRegionMappingFromService(regionName);
+      assertValidMappingOnServer(mapping, regionName, false, true);
+    });
+
+    server4.invoke(() -> {
+      RegionMapping mapping = getRegionMappingFromService(regionName);
+      assertValidMappingOnServer(mapping, regionName, false, true);
+    });
+
+    server1.invoke(() -> {
+      RegionMapping mapping = getRegionMappingFromService(regionName);
+      assertThat(mapping).isNull();
+    });
+
+    locator.invoke(() -> {
+      RegionMapping regionMapping = getRegionMappingFromClusterConfig(regionName, TEST_GROUP1);
+      assertValidMappingOnLocator(regionMapping, regionName, TEST_GROUP1, false, true);
+    });
+  }
+
+  private static void assertValidMappingOnServer(RegionMapping mapping, String regionName,
+      boolean synchronous, boolean isParallel) {
+    assertValidMapping(mapping);
+    validateRegionAlteredOnServer(regionName, synchronous);
+    if (!synchronous) {
+      validateAsyncEventQueueCreatedOnServer(regionName, isParallel);
+    }
+  }
+
+  private static void assertValidMappingOnLocator(RegionMapping mapping, String regionName,
+      String groups,
+      boolean synchronous, boolean isParallel) {
+    assertValidMapping(mapping);
+    validateRegionAlteredInClusterConfig(regionName, groups, synchronous);
+    if (!synchronous) {
+      validateAsyncEventQueueCreatedInClusterConfig(regionName, groups, isParallel);
+    }
+  }
+
+  private static void assertValidMapping(RegionMapping mapping) {
+    assertThat(mapping.getDataSourceName()).isEqualTo("connection");
+    assertThat(mapping.getTableName()).isEqualTo("myTable");
+    assertThat(mapping.getPdxName()).isEqualTo("myPdxClass");
+    assertThat(mapping.getIds()).isEqualTo("myId");
+    assertThat(mapping.getCatalog()).isEqualTo("myCatalog");
+    assertThat(mapping.getSchema()).isEqualTo("mySchema");
+  }
+
+  private static void assertValidMappingWithoutIds(RegionMapping mapping) {
+    assertThat(mapping.getDataSourceName()).isEqualTo("connection");
+    assertThat(mapping.getTableName()).isEqualTo("myTable");
+    assertThat(mapping.getPdxName()).isEqualTo("myPdxClass");
+    assertThat(mapping.getCatalog()).isEqualTo("myCatalog");
+    assertThat(mapping.getSchema()).isEqualTo("mySchema");
+  }
+
+  @Test
   @Parameters({TEST_REGION, "/" + TEST_REGION})
   public void createMappingUpdatesServiceAndClusterConfig(String regionName) {
     setupReplicate(regionName);
@@ -198,28 +436,21 @@ public class CreateMappingCommandDUnitTest {
 
     gfsh.executeAndAssertThat(csb.toString()).statusIsSuccess();
 
-    server.invoke(() -> {
+    server1.invoke(() -> {
       RegionMapping mapping = getRegionMappingFromService(regionName);
-      assertThat(mapping.getDataSourceName()).isEqualTo("connection");
-      assertThat(mapping.getTableName()).isEqualTo("myTable");
-      assertThat(mapping.getPdxName()).isEqualTo("myPdxClass");
-      assertThat(mapping.getIds()).isEqualTo("myId");
-      assertThat(mapping.getCatalog()).isEqualTo("myCatalog");
-      assertThat(mapping.getSchema()).isEqualTo("mySchema");
-      validateRegionAlteredOnServer(regionName, false);
-      validateAsyncEventQueueCreatedOnServer(regionName, false);
+      assertValidMappingOnServer(mapping, regionName, false, false);
+    });
+
+    // without specifying 'group/groups', the region and regionmapping will be created on all
+    // servers
+    server2.invoke(() -> {
+      RegionMapping mapping = getRegionMappingFromService(regionName);
+      assertValidMappingOnServer(mapping, regionName, false, false);
     });
 
     locator.invoke(() -> {
-      RegionMapping regionMapping = getRegionMappingFromClusterConfig(regionName);
-      assertThat(regionMapping.getDataSourceName()).isEqualTo("connection");
-      assertThat(regionMapping.getTableName()).isEqualTo("myTable");
-      assertThat(regionMapping.getPdxName()).isEqualTo("myPdxClass");
-      assertThat(regionMapping.getIds()).isEqualTo("myId");
-      assertThat(regionMapping.getCatalog()).isEqualTo("myCatalog");
-      assertThat(regionMapping.getSchema()).isEqualTo("mySchema");
-      validateRegionAlteredInClusterConfig(regionName, false);
-      validateAsyncEventQueueCreatedInClusterConfig(regionName, false);
+      RegionMapping regionMapping = getRegionMappingFromClusterConfig(regionName, null);
+      assertValidMappingOnLocator(regionMapping, regionName, null, false, false);
     });
   }
 
@@ -239,26 +470,31 @@ public class CreateMappingCommandDUnitTest {
 
     gfsh.executeAndAssertThat(csb.toString()).statusIsSuccess();
 
-    server.invoke(() -> {
+    server1.invoke(() -> {
       RegionMapping mapping = getRegionMappingFromService(regionName);
-      assertThat(mapping.getDataSourceName()).isEqualTo("connection");
-      assertThat(mapping.getTableName()).isEqualTo("myTable");
-      assertThat(mapping.getPdxName()).isEqualTo("myPdxClass");
-      assertThat(mapping.getIds()).isEqualTo("myId");
-      assertThat(mapping.getCatalog()).isEqualTo("myCatalog");
-      assertThat(mapping.getSchema()).isEqualTo("mySchema");
-      validateRegionAlteredOnServer(regionName, true);
+      assertValidMappingOnServer(mapping, regionName, true, false);
+    });
+
+    // without specifying 'group/groups', the region and regionmapping will be created on all
+    // servers
+    server2.invoke(() -> {
+      RegionMapping mapping = getRegionMappingFromService(regionName);
+      assertValidMappingOnServer(mapping, regionName, true, false);
+    });
+
+    server3.invoke(() -> {
+      RegionMapping mapping = getRegionMappingFromService(regionName);
+      assertValidMappingOnServer(mapping, regionName, true, false);
+    });
+
+    server4.invoke(() -> {
+      RegionMapping mapping = getRegionMappingFromService(regionName);
+      assertValidMappingOnServer(mapping, regionName, true, false);
     });
 
     locator.invoke(() -> {
-      RegionMapping regionMapping = getRegionMappingFromClusterConfig(regionName);
-      assertThat(regionMapping.getDataSourceName()).isEqualTo("connection");
-      assertThat(regionMapping.getTableName()).isEqualTo("myTable");
-      assertThat(regionMapping.getPdxName()).isEqualTo("myPdxClass");
-      assertThat(regionMapping.getIds()).isEqualTo("myId");
-      assertThat(regionMapping.getCatalog()).isEqualTo("myCatalog");
-      assertThat(regionMapping.getSchema()).isEqualTo("mySchema");
-      validateRegionAlteredInClusterConfig(regionName, true);
+      RegionMapping mapping = getRegionMappingFromClusterConfig(regionName, null);
+      assertValidMappingOnLocator(mapping, regionName, null, true, false);
     });
   }
 
@@ -274,7 +510,36 @@ public class CreateMappingCommandDUnitTest {
 
     gfsh.executeAndAssertThat(csb.toString()).statusIsSuccess();
 
-    server.invoke(() -> {
+    server1.invoke(() -> {
+      RegionMapping mapping = getRegionMappingFromService(regionName);
+      assertThat(mapping.getDataSourceName()).isEqualTo("connection");
+      assertThat(mapping.getTableName()).isEqualTo("myTable");
+      assertThat(mapping.getPdxName()).isEqualTo("myPdxClass");
+      validateRegionAlteredOnServer(regionName, false);
+      validateAsyncEventQueueCreatedOnServer(regionName, true);
+    });
+
+    // without specifying 'group/groups', the region and regionmapping will be created on all
+    // servers
+    server2.invoke(() -> {
+      RegionMapping mapping = getRegionMappingFromService(regionName);
+      assertThat(mapping.getDataSourceName()).isEqualTo("connection");
+      assertThat(mapping.getTableName()).isEqualTo("myTable");
+      assertThat(mapping.getPdxName()).isEqualTo("myPdxClass");
+      validateRegionAlteredOnServer(regionName, false);
+      validateAsyncEventQueueCreatedOnServer(regionName, true);
+    });
+
+    server3.invoke(() -> {
+      RegionMapping mapping = getRegionMappingFromService(regionName);
+      assertThat(mapping.getDataSourceName()).isEqualTo("connection");
+      assertThat(mapping.getTableName()).isEqualTo("myTable");
+      assertThat(mapping.getPdxName()).isEqualTo("myPdxClass");
+      validateRegionAlteredOnServer(regionName, false);
+      validateAsyncEventQueueCreatedOnServer(regionName, true);
+    });
+
+    server4.invoke(() -> {
       RegionMapping mapping = getRegionMappingFromService(regionName);
       assertThat(mapping.getDataSourceName()).isEqualTo("connection");
       assertThat(mapping.getTableName()).isEqualTo("myTable");
@@ -284,12 +549,12 @@ public class CreateMappingCommandDUnitTest {
     });
 
     locator.invoke(() -> {
-      RegionMapping regionMapping = getRegionMappingFromClusterConfig(regionName);
+      RegionMapping regionMapping = getRegionMappingFromClusterConfig(regionName, null);
       assertThat(regionMapping.getDataSourceName()).isEqualTo("connection");
       assertThat(regionMapping.getTableName()).isEqualTo("myTable");
       assertThat(regionMapping.getPdxName()).isEqualTo("myPdxClass");
-      validateRegionAlteredInClusterConfig(regionName, false);
-      validateAsyncEventQueueCreatedInClusterConfig(regionName, true);
+      validateRegionAlteredInClusterConfig(regionName, null, false);
+      validateAsyncEventQueueCreatedInClusterConfig(regionName, null, true);
     });
   }
 
@@ -304,7 +569,36 @@ public class CreateMappingCommandDUnitTest {
 
     gfsh.executeAndAssertThat(csb.toString()).statusIsSuccess();
 
-    server.invoke(() -> {
+    server1.invoke(() -> {
+      RegionMapping mapping = getRegionMappingFromService(regionName);
+      assertThat(mapping.getDataSourceName()).isEqualTo("connection");
+      assertThat(mapping.getTableName()).isNull();
+      assertThat(mapping.getPdxName()).isEqualTo("myPdxClass");
+      validateRegionAlteredOnServer(regionName, false);
+      validateAsyncEventQueueCreatedOnServer(regionName, false);
+    });
+
+    // without specifying 'group/groups', the region and regionmapping will be created on all
+    // servers
+    server2.invoke(() -> {
+      RegionMapping mapping = getRegionMappingFromService(regionName);
+      assertThat(mapping.getDataSourceName()).isEqualTo("connection");
+      assertThat(mapping.getTableName()).isNull();
+      assertThat(mapping.getPdxName()).isEqualTo("myPdxClass");
+      validateRegionAlteredOnServer(regionName, false);
+      validateAsyncEventQueueCreatedOnServer(regionName, false);
+    });
+
+    server3.invoke(() -> {
+      RegionMapping mapping = getRegionMappingFromService(regionName);
+      assertThat(mapping.getDataSourceName()).isEqualTo("connection");
+      assertThat(mapping.getTableName()).isNull();
+      assertThat(mapping.getPdxName()).isEqualTo("myPdxClass");
+      validateRegionAlteredOnServer(regionName, false);
+      validateAsyncEventQueueCreatedOnServer(regionName, false);
+    });
+
+    server4.invoke(() -> {
       RegionMapping mapping = getRegionMappingFromService(regionName);
       assertThat(mapping.getDataSourceName()).isEqualTo("connection");
       assertThat(mapping.getTableName()).isNull();
@@ -314,12 +608,12 @@ public class CreateMappingCommandDUnitTest {
     });
 
     locator.invoke(() -> {
-      RegionMapping regionMapping = getRegionMappingFromClusterConfig(regionName);
+      RegionMapping regionMapping = getRegionMappingFromClusterConfig(regionName, null);
       assertThat(regionMapping.getDataSourceName()).isEqualTo("connection");
       assertThat(regionMapping.getTableName()).isNull();
       assertThat(regionMapping.getPdxName()).isEqualTo("myPdxClass");
-      validateRegionAlteredInClusterConfig(regionName, false);
-      validateAsyncEventQueueCreatedInClusterConfig(regionName, false);
+      validateRegionAlteredInClusterConfig(regionName, null, false);
+      validateAsyncEventQueueCreatedInClusterConfig(regionName, null, false);
     });
   }
 
@@ -343,7 +637,30 @@ public class CreateMappingCommandDUnitTest {
         .containsOutput(
             "A JDBC mapping for " + convertRegionPathToName(regionName) + " already exists");
 
-    server.invoke(() -> {
+    server1.invoke(() -> {
+      RegionMapping mapping = getRegionMappingFromService(regionName);
+      assertThat(mapping.getDataSourceName()).isEqualTo("connection");
+      assertThat(mapping.getTableName()).isEqualTo("myTable");
+      assertThat(mapping.getPdxName()).isEqualTo("myPdxClass");
+    });
+
+    // without specifying 'group/groups', the region and regionmapping will be created on all
+    // servers
+    server2.invoke(() -> {
+      RegionMapping mapping = getRegionMappingFromService(regionName);
+      assertThat(mapping.getDataSourceName()).isEqualTo("connection");
+      assertThat(mapping.getTableName()).isEqualTo("myTable");
+      assertThat(mapping.getPdxName()).isEqualTo("myPdxClass");
+    });
+
+    server3.invoke(() -> {
+      RegionMapping mapping = getRegionMappingFromService(regionName);
+      assertThat(mapping.getDataSourceName()).isEqualTo("connection");
+      assertThat(mapping.getTableName()).isEqualTo("myTable");
+      assertThat(mapping.getPdxName()).isEqualTo("myPdxClass");
+    });
+
+    server4.invoke(() -> {
       RegionMapping mapping = getRegionMappingFromService(regionName);
       assertThat(mapping.getDataSourceName()).isEqualTo("connection");
       assertThat(mapping.getTableName()).isEqualTo("myTable");
@@ -351,7 +668,7 @@ public class CreateMappingCommandDUnitTest {
     });
 
     locator.invoke(() -> {
-      RegionMapping regionMapping = getRegionMappingFromClusterConfig(regionName);
+      RegionMapping regionMapping = getRegionMappingFromClusterConfig(regionName, null);
       assertThat(regionMapping.getDataSourceName()).isEqualTo("connection");
       assertThat(regionMapping.getTableName()).isEqualTo("myTable");
       assertThat(regionMapping.getPdxName()).isEqualTo("myPdxClass");
@@ -369,7 +686,7 @@ public class CreateMappingCommandDUnitTest {
     // NOTE: --table is optional so it should not be in the output but it is. See GEODE-3468.
     gfsh.executeAndAssertThat(csb.toString()).statusIsError()
         .containsOutput(
-            "You should specify option (--table, --pdx-name, --synchronous, --id, --catalog, --schema) for this command");
+            "You should specify option (--table, --pdx-name, --synchronous, --id, --catalog, --schema, --group) for this command");
   }
 
   @Test
diff --git a/geode-connectors/src/distributedTest/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeMappingCommandDUnitTest.java b/geode-connectors/src/distributedTest/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeMappingCommandDUnitTest.java
index 724c2c7..9263ebe 100644
--- a/geode-connectors/src/distributedTest/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeMappingCommandDUnitTest.java
+++ b/geode-connectors/src/distributedTest/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeMappingCommandDUnitTest.java
@@ -18,30 +18,23 @@ import static org.apache.geode.connectors.jdbc.internal.cli.CreateMappingCommand
 import static org.apache.geode.connectors.jdbc.internal.cli.DescribeMappingCommand.DESCRIBE_MAPPING;
 import static org.apache.geode.connectors.util.internal.MappingConstants.CATALOG_NAME;
 import static org.apache.geode.connectors.util.internal.MappingConstants.DATA_SOURCE_NAME;
+import static org.apache.geode.connectors.util.internal.MappingConstants.GROUP_NAME;
 import static org.apache.geode.connectors.util.internal.MappingConstants.ID_NAME;
 import static org.apache.geode.connectors.util.internal.MappingConstants.PDX_NAME;
 import static org.apache.geode.connectors.util.internal.MappingConstants.REGION_NAME;
 import static org.apache.geode.connectors.util.internal.MappingConstants.SCHEMA_NAME;
 import static org.apache.geode.connectors.util.internal.MappingConstants.SYNCHRONOUS_NAME;
 import static org.apache.geode.connectors.util.internal.MappingConstants.TABLE_NAME;
-import static org.assertj.core.api.Assertions.assertThat;
 
 import java.io.Serializable;
-import java.util.Properties;
 
 import junitparams.JUnitParamsRunner;
 import junitparams.Parameters;
-import org.junit.After;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
 import org.junit.runner.RunWith;
 
-import org.apache.geode.connectors.jdbc.internal.JdbcConnectorService;
-import org.apache.geode.connectors.jdbc.internal.RegionMappingExistsException;
-import org.apache.geode.connectors.jdbc.internal.configuration.RegionMapping;
-import org.apache.geode.distributed.internal.DistributionConfig;
-import org.apache.geode.internal.cache.InternalCache;
 import org.apache.geode.management.internal.cli.util.CommandStringBuilder;
 import org.apache.geode.test.dunit.rules.ClusterStartupRule;
 import org.apache.geode.test.dunit.rules.MemberVM;
@@ -65,7 +58,7 @@ public class DescribeMappingCommandDUnitTest implements Serializable {
   @Rule
   public SerializableTestName testName = new SerializableTestName();
 
-  private MemberVM locator, server;
+  private MemberVM locator;
 
   private static String convertRegionPathToName(String regionPath) {
     if (regionPath.startsWith("/")) {
@@ -74,18 +67,11 @@ public class DescribeMappingCommandDUnitTest implements Serializable {
     return regionPath;
   }
 
-  @After
-  public void cleanUp() throws Exception {
-    startupRule.stop(0);
-    startupRule.stop(1);
-    gfsh.disconnect();
-  }
-
   @Test
   @Parameters({TEST_REGION, "/" + TEST_REGION})
   public void describesExistingSynchronousMapping(String regionName) throws Exception {
     locator = startupRule.startLocatorVM(0);
-    server = startupRule.startServerVM(1, locator.getPort());
+    startupRule.startServerVM(1, locator.getPort());
 
     gfsh.connectAndVerify(locator);
     gfsh.executeAndAssertThat("create region --name=" + regionName + " --type=REPLICATE")
@@ -107,6 +93,46 @@ public class DescribeMappingCommandDUnitTest implements Serializable {
     CommandResultAssert commandResultAssert = gfsh.executeAndAssertThat(csb.toString());
 
     commandResultAssert.statusIsSuccess();
+    commandResultAssert.doesNotContainOutput("Mapping for group");
+    commandResultAssert.containsKeyValuePair(REGION_NAME,
+        convertRegionPathToName(regionName));
+    commandResultAssert.containsKeyValuePair(DATA_SOURCE_NAME, "connection");
+    commandResultAssert.containsKeyValuePair(TABLE_NAME, "testTable");
+    commandResultAssert.containsKeyValuePair(PDX_NAME, "myPdxClass");
+    commandResultAssert.containsKeyValuePair(SYNCHRONOUS_NAME, "true");
+    commandResultAssert.containsKeyValuePair(ID_NAME, "myId");
+  }
+
+  @Test
+  @Parameters({TEST_REGION, "/" + TEST_REGION})
+  public void describesExistingSynchronousMappingWithGroups(String regionName) throws Exception {
+    String groupName = "group1";
+    locator = startupRule.startLocatorVM(0);
+    startupRule.startServerVM(1, groupName, locator.getPort());
+
+    gfsh.connectAndVerify(locator);
+    gfsh.executeAndAssertThat(
+        "create region --name=" + regionName + " --type=REPLICATE --group=" + groupName)
+        .statusIsSuccess();
+
+    CommandStringBuilder csb = new CommandStringBuilder(CREATE_MAPPING);
+    csb.addOption(REGION_NAME, regionName);
+    csb.addOption(GROUP_NAME, groupName);
+    csb.addOption(DATA_SOURCE_NAME, "connection");
+    csb.addOption(TABLE_NAME, "testTable");
+    csb.addOption(PDX_NAME, "myPdxClass");
+    csb.addOption(SYNCHRONOUS_NAME, "true");
+    csb.addOption(ID_NAME, "myId");
+
+    gfsh.executeAndAssertThat(csb.toString()).statusIsSuccess();
+
+    csb = new CommandStringBuilder(DESCRIBE_MAPPING).addOption(REGION_NAME,
+        regionName).addOption(GROUP_NAME, groupName);
+
+    CommandResultAssert commandResultAssert = gfsh.executeAndAssertThat(csb.toString());
+
+    commandResultAssert.statusIsSuccess();
+    commandResultAssert.containsKeyValuePair("Mapping for group", "group1");
     commandResultAssert.containsKeyValuePair(REGION_NAME,
         convertRegionPathToName(regionName));
     commandResultAssert.containsKeyValuePair(DATA_SOURCE_NAME, "connection");
@@ -120,7 +146,7 @@ public class DescribeMappingCommandDUnitTest implements Serializable {
   @Parameters({TEST_REGION, "/" + TEST_REGION})
   public void describesExistingAsyncMapping(String regionName) throws Exception {
     locator = startupRule.startLocatorVM(0);
-    server = startupRule.startServerVM(1, locator.getPort());
+    startupRule.startServerVM(1, locator.getPort());
 
     gfsh.connectAndVerify(locator);
     gfsh.executeAndAssertThat("create region --name=" + regionName + " --type=REPLICATE")
@@ -158,53 +184,213 @@ public class DescribeMappingCommandDUnitTest implements Serializable {
   }
 
   @Test
-  public void reportsNoMappingFound() throws Exception {
+  @Parameters({TEST_REGION, "/" + TEST_REGION})
+  public void describesExistingAsyncMappingWithGroup(String regionName) throws Exception {
+    String groupName = "group1";
     locator = startupRule.startLocatorVM(0);
-    server = startupRule.startServerVM(1, locator.getPort());
+    startupRule.startServerVM(1, groupName, locator.getPort());
+
     gfsh.connectAndVerify(locator);
-    gfsh.executeAndAssertThat("create region --name=" + TEST_REGION + " --type=REPLICATE")
+    gfsh.executeAndAssertThat(
+        "create region --name=" + regionName + " --type=REPLICATE --group=" + groupName)
         .statusIsSuccess();
 
-    CommandStringBuilder csb = new CommandStringBuilder(DESCRIBE_MAPPING)
-        .addOption(REGION_NAME, "nonExisting");
+    CommandStringBuilder csb = new CommandStringBuilder(CREATE_MAPPING);
+
+    csb.addOption(REGION_NAME, regionName);
+    csb.addOption(GROUP_NAME, groupName);
+    csb.addOption(DATA_SOURCE_NAME, "connection");
+    csb.addOption(TABLE_NAME, "testTable");
+    csb.addOption(PDX_NAME, "myPdxClass");
+    csb.addOption(SYNCHRONOUS_NAME, "false");
+    csb.addOption(ID_NAME, "myId");
+    csb.addOption(CATALOG_NAME, "myCatalog");
+    csb.addOption(SCHEMA_NAME, "mySchema");
+
+    gfsh.executeAndAssertThat(csb.toString()).statusIsSuccess();
+
+    csb = new CommandStringBuilder(DESCRIBE_MAPPING).addOption(REGION_NAME,
+        regionName).addOption(GROUP_NAME, groupName);
 
     CommandResultAssert commandResultAssert = gfsh.executeAndAssertThat(csb.toString());
 
-    commandResultAssert.statusIsError();
-    commandResultAssert.containsOutput(
-        String.format("(Experimental) \n" + "JDBC mapping for region 'nonExisting' not found"));
+    commandResultAssert.statusIsSuccess();
+    commandResultAssert.containsKeyValuePair(REGION_NAME,
+        convertRegionPathToName(regionName));
+
+    commandResultAssert.containsKeyValuePair("Mapping for group", "group1");
+    commandResultAssert.containsKeyValuePair(DATA_SOURCE_NAME, "connection");
+    commandResultAssert.containsKeyValuePair(TABLE_NAME, "testTable");
+    commandResultAssert.containsKeyValuePair(PDX_NAME, "myPdxClass");
+    commandResultAssert.containsKeyValuePair(SYNCHRONOUS_NAME, "false");
+    commandResultAssert.containsKeyValuePair(ID_NAME, "myId");
+    commandResultAssert.containsKeyValuePair(CATALOG_NAME, "myCatalog");
+    commandResultAssert.containsKeyValuePair(SCHEMA_NAME, "mySchema");
   }
 
   @Test
-  public void reportConfigurationFoundOnMember() throws Exception {
-    Properties properties = new Properties();
-    properties.put(DistributionConfig.ENABLE_CLUSTER_CONFIGURATION_NAME, "false");
+  @Parameters({TEST_REGION, "/" + TEST_REGION})
+  public void describesExistingAsyncMappingsWithSameRegionOnDifferentGroups(String regionName)
+      throws Exception {
+    String groupName1 = "group1";
+    String groupName2 = "group2";
+    locator = startupRule.startLocatorVM(0);
+    startupRule.startServerVM(1, groupName1, locator.getPort());
+    startupRule.startServerVM(2, groupName2, locator.getPort());
 
-    locator = startupRule.startLocatorVM(0, properties);
-    server = startupRule.startServerVM(1, locator.getPort());
     gfsh.connectAndVerify(locator);
-    gfsh.executeAndAssertThat("create region --name=" + TEST_REGION + " --type=REPLICATE")
+    gfsh.executeAndAssertThat("create region --name=" + regionName + " --type=REPLICATE --group="
+        + groupName1 + "," + groupName2)
         .statusIsSuccess();
 
-    server.invoke(() -> createRegionMapping());
+    CommandStringBuilder csb = new CommandStringBuilder(CREATE_MAPPING);
 
-    CommandResultAssert commandResultAssert =
-        gfsh.executeAndAssertThat(DESCRIBE_MAPPING + " --region=" + TEST_REGION).statusIsSuccess();
+    csb.addOption(REGION_NAME, regionName);
+    csb.addOption(GROUP_NAME, groupName1 + "," + groupName2);
+    csb.addOption(DATA_SOURCE_NAME, "connection");
+    csb.addOption(TABLE_NAME, "testTable");
+    csb.addOption(PDX_NAME, "myPdxClass");
+    csb.addOption(SYNCHRONOUS_NAME, "false");
+    csb.addOption(ID_NAME, "myId");
+    csb.addOption(CATALOG_NAME, "myCatalog");
+    csb.addOption(SCHEMA_NAME, "mySchema");
+
+    gfsh.executeAndAssertThat(csb.toString()).statusIsSuccess();
 
-    commandResultAssert.containsKeyValuePair(REGION_NAME, TEST_REGION);
+    csb = new CommandStringBuilder(DESCRIBE_MAPPING).addOption(REGION_NAME,
+        regionName).addOption(GROUP_NAME, groupName1 + "," + groupName2);
+
+    CommandResultAssert commandResultAssert = gfsh.executeAndAssertThat(csb.toString());
+
+    commandResultAssert.statusIsSuccess();
+    commandResultAssert.containsKeyValuePair(REGION_NAME,
+        convertRegionPathToName(regionName));
+
+    commandResultAssert.containsKeyValuePair("Mapping for group", "group1");
+    commandResultAssert.containsKeyValuePair("Mapping for group", "group2");
     commandResultAssert.containsKeyValuePair(DATA_SOURCE_NAME, "connection");
     commandResultAssert.containsKeyValuePair(TABLE_NAME, "testTable");
     commandResultAssert.containsKeyValuePair(PDX_NAME, "myPdxClass");
     commandResultAssert.containsKeyValuePair(SYNCHRONOUS_NAME, "false");
     commandResultAssert.containsKeyValuePair(ID_NAME, "myId");
+    commandResultAssert.containsKeyValuePair(CATALOG_NAME, "myCatalog");
+    commandResultAssert.containsKeyValuePair(SCHEMA_NAME, "mySchema");
+  }
+
+  @Test
+  @Parameters({TEST_REGION, "/" + TEST_REGION})
+  public void describesExistingAsyncMappingsWithSameRegionOnDifferentGroupsWithDifferentMappings(
+      String regionName)
+      throws Exception {
+    String groupName1 = "group1";
+    String groupName2 = "group2";
+    locator = startupRule.startLocatorVM(0);
+    startupRule.startServerVM(1, groupName1, locator.getPort());
+    startupRule.startServerVM(2, groupName2, locator.getPort());
+
+    gfsh.connectAndVerify(locator);
+    gfsh.executeAndAssertThat("create region --name=" + regionName + " --type=REPLICATE --group="
+        + groupName1 + "," + groupName2)
+        .statusIsSuccess();
+
+    CommandStringBuilder csb = new CommandStringBuilder(CREATE_MAPPING);
+
+    csb.addOption(REGION_NAME, regionName);
+    csb.addOption(GROUP_NAME, groupName1);
+    csb.addOption(DATA_SOURCE_NAME, "connection");
+    csb.addOption(TABLE_NAME, "testTable");
+    csb.addOption(PDX_NAME, "myPdxClass");
+    csb.addOption(SYNCHRONOUS_NAME, "false");
+    csb.addOption(ID_NAME, "myId");
+    csb.addOption(CATALOG_NAME, "myCatalog");
+    csb.addOption(SCHEMA_NAME, "mySchema");
+
+    gfsh.executeAndAssertThat(csb.toString()).statusIsSuccess();
+
+    csb = new CommandStringBuilder(CREATE_MAPPING);
+
+    csb.addOption(REGION_NAME, regionName);
+    csb.addOption(GROUP_NAME, groupName2);
+    csb.addOption(DATA_SOURCE_NAME, "connection2");
+    csb.addOption(TABLE_NAME, "testTable2");
+    csb.addOption(PDX_NAME, "myPdxClass2");
+    csb.addOption(SYNCHRONOUS_NAME, "false");
+    csb.addOption(ID_NAME, "myId2");
+    csb.addOption(CATALOG_NAME, "myCatalog2");
+    csb.addOption(SCHEMA_NAME, "mySchema2");
+
+    gfsh.executeAndAssertThat(csb.toString()).statusIsSuccess();
 
+    csb = new CommandStringBuilder(DESCRIBE_MAPPING).addOption(REGION_NAME,
+        regionName).addOption(GROUP_NAME, groupName1);
+
+    CommandResultAssert commandResultAssert = gfsh.executeAndAssertThat(csb.toString());
+
+    commandResultAssert.statusIsSuccess();
+    commandResultAssert.containsKeyValuePair(REGION_NAME,
+        convertRegionPathToName(regionName));
+
+    commandResultAssert.containsKeyValuePair("Mapping for group", "group1");
+    commandResultAssert.containsKeyValuePair(DATA_SOURCE_NAME, "connection");
+    commandResultAssert.containsKeyValuePair(TABLE_NAME, "testTable");
+    commandResultAssert.containsKeyValuePair(PDX_NAME, "myPdxClass");
+    commandResultAssert.containsKeyValuePair(SYNCHRONOUS_NAME, "false");
+    commandResultAssert.containsKeyValuePair(ID_NAME, "myId");
+    commandResultAssert.containsKeyValuePair(CATALOG_NAME, "myCatalog");
+    commandResultAssert.containsKeyValuePair(SCHEMA_NAME, "mySchema");
+
+    csb = new CommandStringBuilder(DESCRIBE_MAPPING).addOption(REGION_NAME,
+        regionName).addOption(GROUP_NAME, groupName2);
+
+    commandResultAssert = gfsh.executeAndAssertThat(csb.toString());
+
+    commandResultAssert.statusIsSuccess();
+    commandResultAssert.containsKeyValuePair(REGION_NAME,
+        convertRegionPathToName(regionName));
+
+    commandResultAssert.containsKeyValuePair("Mapping for group", "group2");
+    commandResultAssert.containsKeyValuePair(DATA_SOURCE_NAME, "connection2");
+    commandResultAssert.containsKeyValuePair(TABLE_NAME, "testTable2");
+    commandResultAssert.containsKeyValuePair(PDX_NAME, "myPdxClass2");
+    commandResultAssert.containsKeyValuePair(SYNCHRONOUS_NAME, "false");
+    commandResultAssert.containsKeyValuePair(ID_NAME, "myId2");
+    commandResultAssert.containsKeyValuePair(CATALOG_NAME, "myCatalog2");
+    commandResultAssert.containsKeyValuePair(SCHEMA_NAME, "mySchema2");
   }
 
-  private void createRegionMapping() throws RegionMappingExistsException {
-    InternalCache cache = ClusterStartupRule.getCache();
-    JdbcConnectorService service = cache.getService(JdbcConnectorService.class);
-    service.createRegionMapping(new RegionMapping(TEST_REGION, "myPdxClass",
-        "testTable", "connection", "myId", "myCatalog", "mySchema"));
-    assertThat(service.getMappingForRegion(TEST_REGION)).isNotNull();
+  @Test
+  public void reportsNoRegionFound() throws Exception {
+    locator = startupRule.startLocatorVM(0);
+    startupRule.startServerVM(1, locator.getPort());
+    gfsh.connectAndVerify(locator);
+    gfsh.executeAndAssertThat("create region --name=" + TEST_REGION + " --type=REPLICATE")
+        .statusIsSuccess();
+
+    CommandStringBuilder csb = new CommandStringBuilder(DESCRIBE_MAPPING)
+        .addOption(REGION_NAME, "nonExisting");
+
+    CommandResultAssert commandResultAssert = gfsh.executeAndAssertThat(csb.toString());
+
+    commandResultAssert.statusIsError();
+    commandResultAssert.containsOutput(
+        String.format("A region named nonExisting must already exist."));
+  }
+
+  @Test
+  public void reportsRegionButNoMappingFound() throws Exception {
+    locator = startupRule.startLocatorVM(0);
+    startupRule.startServerVM(1, locator.getPort());
+    gfsh.connectAndVerify(locator);
+    gfsh.executeAndAssertThat("create region --name=" + TEST_REGION + " --type=REPLICATE")
+        .statusIsSuccess();
+
+    CommandStringBuilder csb = new CommandStringBuilder(DESCRIBE_MAPPING)
+        .addOption(REGION_NAME, TEST_REGION);
+
+    CommandResultAssert commandResultAssert = gfsh.executeAndAssertThat(csb.toString());
+
+    commandResultAssert.statusIsError();
+    commandResultAssert.containsOutput(
+        String.format("JDBC mapping for region '" + TEST_REGION + "' not found"));
   }
 }
diff --git a/geode-connectors/src/integrationTest/resources/org/apache/geode/codeAnalysis/sanctionedDataSerializables.txt b/geode-connectors/src/integrationTest/resources/org/apache/geode/codeAnalysis/sanctionedDataSerializables.txt
index 5dd33d0..e69de29 100644
--- a/geode-connectors/src/integrationTest/resources/org/apache/geode/codeAnalysis/sanctionedDataSerializables.txt
+++ b/geode-connectors/src/integrationTest/resources/org/apache/geode/codeAnalysis/sanctionedDataSerializables.txt
@@ -1,3 +0,0 @@
-org/apache/geode/connectors/util/internal/DescribeMappingResult,2
-fromData,48
-toData,80
\ No newline at end of file
diff --git a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/CreateMappingCommand.java b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/CreateMappingCommand.java
index 1412f41..e6e1f8c 100644
--- a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/CreateMappingCommand.java
+++ b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/CreateMappingCommand.java
@@ -14,8 +14,6 @@
  */
 package org.apache.geode.connectors.jdbc.internal.cli;
 
-
-
 import java.util.List;
 import java.util.Set;
 
@@ -38,6 +36,7 @@ import org.apache.geode.connectors.util.internal.MappingConstants;
 import org.apache.geode.distributed.ConfigurationPersistenceService;
 import org.apache.geode.distributed.DistributedMember;
 import org.apache.geode.management.cli.CliMetaData;
+import org.apache.geode.management.cli.ConverterHint;
 import org.apache.geode.management.cli.SingleGfshCommand;
 import org.apache.geode.management.internal.cli.functions.CliFunctionResult;
 import org.apache.geode.management.internal.cli.i18n.CliStrings;
@@ -74,6 +73,9 @@ public class CreateMappingCommand extends SingleGfshCommand {
   private static final String CREATE_MAPPING__SCHEMA_NAME = MappingConstants.SCHEMA_NAME;
   private static final String CREATE_MAPPING__SCHEMA_NAME__HELP =
       "The schema that contains the database table. By default, the schema is the empty string causing the table to be referenced without a schema prefix.";
+  private static final String CREATE_MAPPING__GROUPS_NAME = "groups";
+  private static final String CREATE_MAPPING__GROUPS_NAME__HELP =
+      "The names of the server groups on which this mapping should be created.";
 
   public static String createAsyncEventQueueName(String regionPath) {
     if (regionPath.startsWith("/")) {
@@ -102,25 +104,32 @@ public class CreateMappingCommand extends SingleGfshCommand {
       @CliOption(key = CREATE_MAPPING__CATALOG_NAME,
           help = CREATE_MAPPING__CATALOG_NAME__HELP) String catalog,
       @CliOption(key = CREATE_MAPPING__SCHEMA_NAME,
-          help = CREATE_MAPPING__SCHEMA_NAME__HELP) String schema) {
+          help = CREATE_MAPPING__SCHEMA_NAME__HELP) String schema,
+      @CliOption(key = {CliStrings.GROUP, CliStrings.GROUPS},
+          optionContext = ConverterHint.MEMBERGROUP,
+          help = CREATE_MAPPING__GROUPS_NAME__HELP) String[] groups) {
     if (regionName.startsWith("/")) {
       regionName = regionName.substring(1);
     }
 
-    // input
-    Set<DistributedMember> targetMembers = findMembersForRegion(regionName);
+    Set<DistributedMember> targetMembers = findMembers(groups, null);
     RegionMapping mapping =
         new RegionMapping(regionName, pdxName, table, dataSourceName, id, catalog, schema);
 
     try {
       ConfigurationPersistenceService configurationPersistenceService =
           checkForClusterConfiguration();
-      CacheConfig cacheConfig = configurationPersistenceService.getCacheConfig(null);
-      RegionConfig regionConfig = checkForRegion(regionName, cacheConfig);
-      checkForExistingMapping(regionName, regionConfig);
-      checkForCacheLoader(regionName, regionConfig);
-      checkForCacheWriter(regionName, synchronous, regionConfig);
-      checkForAsyncQueue(regionName, synchronous, cacheConfig);
+      if (groups == null) {
+        groups = new String[] {ConfigurationPersistenceService.CLUSTER_CONFIG};
+      }
+      for (String group : groups) {
+        CacheConfig cacheConfig = configurationPersistenceService.getCacheConfig(group);
+        RegionConfig regionConfig = checkForRegion(regionName, cacheConfig);
+        checkForExistingMapping(regionName, regionConfig);
+        checkForCacheLoader(regionName, regionConfig);
+        checkForCacheWriter(regionName, synchronous, regionConfig);
+        checkForAsyncQueue(regionName, synchronous, cacheConfig);
+      }
     } catch (PreconditionException ex) {
       return ResultModel.createError(ex.getMessage());
     }
diff --git a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeMappingCommand.java b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeMappingCommand.java
index 2d6d803..62d071f 100644
--- a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeMappingCommand.java
+++ b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeMappingCommand.java
@@ -14,20 +14,32 @@
  */
 package org.apache.geode.connectors.jdbc.internal.cli;
 
+import static org.apache.geode.connectors.util.internal.MappingConstants.CATALOG_NAME;
+import static org.apache.geode.connectors.util.internal.MappingConstants.DATA_SOURCE_NAME;
+import static org.apache.geode.connectors.util.internal.MappingConstants.ID_NAME;
+import static org.apache.geode.connectors.util.internal.MappingConstants.PDX_NAME;
 import static org.apache.geode.connectors.util.internal.MappingConstants.REGION_NAME;
+import static org.apache.geode.connectors.util.internal.MappingConstants.SCHEMA_NAME;
+import static org.apache.geode.connectors.util.internal.MappingConstants.SYNCHRONOUS_NAME;
+import static org.apache.geode.connectors.util.internal.MappingConstants.TABLE_NAME;
 
-import java.util.Set;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
 
 import org.springframework.shell.core.annotation.CliAvailabilityIndicator;
 import org.springframework.shell.core.annotation.CliCommand;
 import org.springframework.shell.core.annotation.CliOption;
 
 import org.apache.geode.annotations.Experimental;
+import org.apache.geode.cache.configuration.CacheConfig;
+import org.apache.geode.cache.configuration.CacheElement;
+import org.apache.geode.cache.configuration.RegionConfig;
+import org.apache.geode.connectors.jdbc.internal.configuration.RegionMapping;
 import org.apache.geode.connectors.util.internal.DescribeMappingResult;
-import org.apache.geode.distributed.DistributedMember;
+import org.apache.geode.distributed.ConfigurationPersistenceService;
 import org.apache.geode.management.cli.CliMetaData;
+import org.apache.geode.management.cli.ConverterHint;
 import org.apache.geode.management.cli.GfshCommand;
-import org.apache.geode.management.internal.cli.functions.CliFunctionResult;
 import org.apache.geode.management.internal.cli.i18n.CliStrings;
 import org.apache.geode.management.internal.cli.result.model.DataResultModel;
 import org.apache.geode.management.internal.cli.result.model.ResultModel;
@@ -43,6 +55,8 @@ public class DescribeMappingCommand extends GfshCommand {
   private static final String DESCRIBE_MAPPING__REGION_NAME = REGION_NAME;
   private static final String DESCRIBE_MAPPING__REGION_NAME__HELP =
       "Region name of the JDBC mapping to be described.";
+  private static final String CREATE_MAPPING__GROUPS_NAME__HELP =
+      "Server Group(s) of the JDBC mapping to be described.";
 
   public static final String RESULT_SECTION_NAME = "MappingDescription";
 
@@ -51,40 +65,134 @@ public class DescribeMappingCommand extends GfshCommand {
   @ResourceOperation(resource = ResourcePermission.Resource.CLUSTER,
       operation = ResourcePermission.Operation.MANAGE)
   public ResultModel describeMapping(@CliOption(key = DESCRIBE_MAPPING__REGION_NAME,
-      mandatory = true, help = DESCRIBE_MAPPING__REGION_NAME__HELP) String regionName) {
+      mandatory = true, help = DESCRIBE_MAPPING__REGION_NAME__HELP) String regionName,
+      @CliOption(key = {CliStrings.GROUP, CliStrings.GROUPS},
+          optionContext = ConverterHint.MEMBERGROUP,
+          help = CREATE_MAPPING__GROUPS_NAME__HELP) String[] groups) {
     if (regionName.startsWith("/")) {
       regionName = regionName.substring(1);
     }
 
-    DescribeMappingResult describeMappingResult = null;
+    ArrayList<DescribeMappingResult> describeMappingResults = new ArrayList<>();
 
-    Set<DistributedMember> members = findMembers(null, null);
-    if (members.size() > 0) {
-      DistributedMember targetMember = members.iterator().next();
-      CliFunctionResult result = executeFunctionAndGetFunctionResult(
-          new DescribeMappingFunction(), regionName, targetMember);
-      if (result != null) {
-        describeMappingResult = (DescribeMappingResult) result.getResultObject();
+    try {
+      ConfigurationPersistenceService configService = checkForClusterConfiguration();
+      if (groups == null) {
+        groups = new String[] {ConfigurationPersistenceService.CLUSTER_CONFIG};
       }
-    } else {
-      return ResultModel.createError(CliStrings.NO_MEMBERS_FOUND_MESSAGE);
+      for (String group : groups) {
+        CacheConfig cacheConfig = getCacheConfig(configService, group);
+        RegionConfig regionConfig = checkForRegion(regionName, cacheConfig, group);
+        describeMappingResults
+            .addAll(getMappingsFromRegionConfig(cacheConfig, regionConfig, group));
+      }
+    } catch (PreconditionException ex) {
+      return ResultModel.createError(ex.getMessage());
     }
 
-    if (describeMappingResult == null) {
+    if (describeMappingResults.isEmpty()) {
       throw new EntityNotFoundException(
           EXPERIMENTAL + "\n" + "JDBC mapping for region '" + regionName + "' not found");
     }
 
-    ResultModel resultModel = new ResultModel();
-    fillResultData(describeMappingResult, resultModel);
+    ResultModel resultModel = buildResultModel(describeMappingResults);
     resultModel.setHeader(EXPERIMENTAL);
     return resultModel;
   }
 
-  private void fillResultData(DescribeMappingResult describeMappingResult,
-      ResultModel resultModel) {
-    DataResultModel sectionModel = resultModel.addData(RESULT_SECTION_NAME);
-    describeMappingResult.getAttributeMap().forEach(sectionModel::addData);
+  private CacheConfig getCacheConfig(ConfigurationPersistenceService configService, String group)
+      throws PreconditionException {
+    CacheConfig result = configService.getCacheConfig(group);
+    if (result == null) {
+      throw new PreconditionException(
+          "Cache Configuration not found"
+              + ((group.equals(ConfigurationPersistenceService.CLUSTER_CONFIG)) ? "."
+                  : " for group " + group + "."));
+    }
+    return result;
+  }
+
+  private ArrayList<DescribeMappingResult> getMappingsFromRegionConfig(CacheConfig cacheConfig,
+      RegionConfig regionConfig, String group) {
+    CacheConfig.AsyncEventQueue asyncEventQueue = findAsyncEventQueue(cacheConfig, regionConfig);
+    ArrayList<DescribeMappingResult> results = new ArrayList<>();
+    for (CacheElement element : regionConfig.getCustomRegionElements()) {
+      if (element instanceof RegionMapping) {
+        results.add(buildDescribeMappingResult((RegionMapping) element, regionConfig.getName(),
+            asyncEventQueue == null, group));
+      }
+    }
+    return results;
+  }
+
+  private CacheConfig.AsyncEventQueue findAsyncEventQueue(CacheConfig cacheConfig,
+      RegionConfig regionConfig) {
+    for (CacheConfig.AsyncEventQueue queue : cacheConfig.getAsyncEventQueues()) {
+      if (queue.getId()
+          .equals(CreateMappingCommand.createAsyncEventQueueName(regionConfig.getName()))) {
+        return queue;
+      }
+    }
+    return null;
+  }
+
+  private DescribeMappingResult buildDescribeMappingResult(RegionMapping regionMapping,
+      String regionName, boolean synchronous, String group) {
+    LinkedHashMap<String, String> attributes = new LinkedHashMap<>();
+    attributes.put(REGION_NAME, regionName);
+    attributes.put(PDX_NAME, regionMapping.getPdxName());
+    attributes.put(TABLE_NAME, regionMapping.getTableName());
+    attributes.put(DATA_SOURCE_NAME, regionMapping.getDataSourceName());
+    attributes.put(SYNCHRONOUS_NAME, Boolean.toString(synchronous));
+    attributes.put(ID_NAME, regionMapping.getIds());
+    if (regionMapping.getCatalog() != null) {
+      attributes.put(CATALOG_NAME, regionMapping.getCatalog());
+    }
+    if (regionMapping.getSchema() != null) {
+      attributes.put(SCHEMA_NAME, regionMapping.getSchema());
+    }
+    DescribeMappingResult result = new DescribeMappingResult(attributes);
+    result.setGroupName(group);
+    return result;
+  }
+
+  private ResultModel buildResultModel(ArrayList<DescribeMappingResult> describeMappingResult) {
+    ResultModel resultModel = new ResultModel();
+    for (int i = 0; i < describeMappingResult.size(); i++) {
+      DataResultModel sectionModel = resultModel.addData(RESULT_SECTION_NAME + String.valueOf(i));
+      DescribeMappingResult result = describeMappingResult.get(i);
+      if (!result.getGroupName().equals(ConfigurationPersistenceService.CLUSTER_CONFIG)) {
+        sectionModel.addData("Mapping for group", result.getGroupName());
+      }
+      result.getAttributeMap().forEach(sectionModel::addData);
+    }
+    return resultModel;
+  }
+
+  public ConfigurationPersistenceService checkForClusterConfiguration()
+      throws PreconditionException {
+    ConfigurationPersistenceService result = getConfigurationPersistenceService();
+    if (result == null) {
+      throw new PreconditionException("Cluster Configuration must be enabled.");
+    }
+    return result;
+  }
+
+  private RegionConfig checkForRegion(String regionName, CacheConfig cacheConfig, String groupName)
+      throws PreconditionException {
+    RegionConfig regionConfig = findRegionConfig(cacheConfig, regionName);
+    if (regionConfig == null) {
+      String groupClause = "A region named " + regionName + " must already exist"
+          + (!groupName.equals(ConfigurationPersistenceService.CLUSTER_CONFIG)
+              ? " for group " + groupName + "." : ".");
+      throw new PreconditionException(groupClause);
+    }
+    return regionConfig;
+  }
+
+  private RegionConfig findRegionConfig(CacheConfig cacheConfig, String regionName) {
+    return cacheConfig.getRegions().stream()
+        .filter(region -> region.getName().equals(regionName)).findFirst().orElse(null);
   }
 
   @CliAvailabilityIndicator({DESCRIBE_MAPPING})
diff --git a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeMappingFunction.java b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeMappingFunction.java
deleted file mode 100644
index 2cd9f9e..0000000
--- a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeMappingFunction.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * 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.connectors.jdbc.internal.cli;
-
-import static org.apache.geode.connectors.util.internal.MappingConstants.CATALOG_NAME;
-import static org.apache.geode.connectors.util.internal.MappingConstants.DATA_SOURCE_NAME;
-import static org.apache.geode.connectors.util.internal.MappingConstants.ID_NAME;
-import static org.apache.geode.connectors.util.internal.MappingConstants.PDX_NAME;
-import static org.apache.geode.connectors.util.internal.MappingConstants.REGION_NAME;
-import static org.apache.geode.connectors.util.internal.MappingConstants.SCHEMA_NAME;
-import static org.apache.geode.connectors.util.internal.MappingConstants.SYNCHRONOUS_NAME;
-import static org.apache.geode.connectors.util.internal.MappingConstants.TABLE_NAME;
-
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import org.apache.geode.cache.execute.FunctionContext;
-import org.apache.geode.connectors.jdbc.internal.JdbcConnectorService;
-import org.apache.geode.connectors.jdbc.internal.RegionMappingNotFoundException;
-import org.apache.geode.connectors.jdbc.internal.configuration.RegionMapping;
-import org.apache.geode.connectors.util.internal.DescribeMappingResult;
-import org.apache.geode.management.cli.CliFunction;
-import org.apache.geode.management.internal.cli.functions.CliFunctionResult;
-
-public class DescribeMappingFunction extends CliFunction<String> {
-
-  @Override
-  public CliFunctionResult executeFunction(FunctionContext<String> context) {
-    return new CliFunctionResult(context.getMemberName(), getResult(context));
-
-  }
-
-  private DescribeMappingResult getResult(FunctionContext<String> context) {
-    JdbcConnectorService service = FunctionContextArgumentProvider.getJdbcConnectorService(context);
-    RegionMapping mapping = service.getMappingForRegion(context.getArguments());
-    if (mapping == null) {
-      return null;
-    }
-
-    Map<String, String> attributes = new LinkedHashMap<>();
-    attributes.put(REGION_NAME, mapping.getRegionName());
-    attributes.put(TABLE_NAME, mapping.getTableName());
-    attributes.put(DATA_SOURCE_NAME, mapping.getDataSourceName());
-    attributes.put(ID_NAME, mapping.getIds());
-    attributes.put(PDX_NAME, mapping.getPdxName());
-
-    try {
-      attributes.put(SYNCHRONOUS_NAME,
-          Boolean
-              .toString(service.isMappingSynchronous(mapping.getRegionName(), context.getCache())));
-    } catch (RegionMappingNotFoundException e) {
-      attributes.put(SYNCHRONOUS_NAME, "Not found.");
-    }
-
-    if (mapping.getCatalog() != null) {
-      attributes.put(CATALOG_NAME, mapping.getCatalog());
-    }
-    if (mapping.getSchema() != null) {
-      attributes.put(SCHEMA_NAME, mapping.getSchema());
-    }
-
-    return new DescribeMappingResult(attributes);
-  }
-}
diff --git a/geode-connectors/src/main/java/org/apache/geode/connectors/util/internal/DescribeMappingResult.java b/geode-connectors/src/main/java/org/apache/geode/connectors/util/internal/DescribeMappingResult.java
index ca3e704..6b63904 100644
--- a/geode-connectors/src/main/java/org/apache/geode/connectors/util/internal/DescribeMappingResult.java
+++ b/geode-connectors/src/main/java/org/apache/geode/connectors/util/internal/DescribeMappingResult.java
@@ -14,17 +14,12 @@
  */
 package org.apache.geode.connectors.util.internal;
 
-import java.io.DataInput;
-import java.io.DataOutput;
-import java.io.IOException;
 import java.util.LinkedHashMap;
 import java.util.Map;
 
-import org.apache.geode.DataSerializable;
-import org.apache.geode.DataSerializer;
-
-public class DescribeMappingResult implements DataSerializable {
+public class DescribeMappingResult {
   private final Map<String, String> attributeMap;
+  private String groupName;
 
   public DescribeMappingResult() {
     this.attributeMap = new LinkedHashMap<>();
@@ -38,26 +33,11 @@ public class DescribeMappingResult implements DataSerializable {
     return this.attributeMap;
   }
 
-  @Override
-  public void toData(DataOutput out) throws IOException {
-    DataSerializer.writeInteger(attributeMap.size(), out);
-    for (Map.Entry<String, String> entry : attributeMap.entrySet()) {
-      DataSerializer.writeString(entry.getKey(), out);
-      DataSerializer.writeString(entry.getValue(), out);
-    }
+  public String getGroupName() {
+    return groupName;
   }
 
-  @Override
-  public void fromData(DataInput in) throws IOException {
-    int dataSize = DataSerializer.readInteger(in);
-
-    for (int i = 0; i < dataSize; i++) {
-      String key, value;
-
-      key = DataSerializer.readString(in);
-      value = DataSerializer.readString(in);
-
-      this.attributeMap.put(key, value);
-    }
+  public void setGroupName(String group) {
+    groupName = group;
   }
 }
diff --git a/geode-connectors/src/main/java/org/apache/geode/connectors/util/internal/MappingConstants.java b/geode-connectors/src/main/java/org/apache/geode/connectors/util/internal/MappingConstants.java
index 1c7a1fc..aec52c1 100644
--- a/geode-connectors/src/main/java/org/apache/geode/connectors/util/internal/MappingConstants.java
+++ b/geode-connectors/src/main/java/org/apache/geode/connectors/util/internal/MappingConstants.java
@@ -23,6 +23,7 @@ public final class MappingConstants {
   public static final String ID_NAME = "id";
   public static final String SCHEMA_NAME = "schema";
   public static final String CATALOG_NAME = "catalog";
+  public static final String GROUP_NAME = "groups";
 
   private MappingConstants() {}
 }
diff --git a/geode-connectors/src/main/resources/org/apache/geode/internal/sanctioned-geode-connectors-serializables.txt b/geode-connectors/src/main/resources/org/apache/geode/internal/sanctioned-geode-connectors-serializables.txt
index 83029fd..ffe660c 100755
--- a/geode-connectors/src/main/resources/org/apache/geode/internal/sanctioned-geode-connectors-serializables.txt
+++ b/geode-connectors/src/main/resources/org/apache/geode/internal/sanctioned-geode-connectors-serializables.txt
@@ -2,7 +2,6 @@ org/apache/geode/connectors/jdbc/JdbcConnectorException,true,1
 org/apache/geode/connectors/jdbc/internal/RegionMappingExistsException,false
 org/apache/geode/connectors/jdbc/internal/RegionMappingNotFoundException,false
 org/apache/geode/connectors/jdbc/internal/cli/CreateMappingFunction,false
-org/apache/geode/connectors/jdbc/internal/cli/DescribeMappingFunction,false
 org/apache/geode/connectors/jdbc/internal/cli/DestroyMappingFunction,false
 org/apache/geode/connectors/jdbc/internal/cli/ListMappingFunction,false
 org/apache/geode/connectors/jdbc/internal/configuration/RegionMapping,false,catalog:java/lang/String,dataSourceName:java/lang/String,ids:java/lang/String,pdxName:java/lang/String,regionName:java/lang/String,schema:java/lang/String,tableName:java/lang/String
diff --git a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/CreateMappingCommandTest.java b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/CreateMappingCommandTest.java
index 2d66fbf..d765a8e 100644
--- a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/CreateMappingCommandTest.java
+++ b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/CreateMappingCommandTest.java
@@ -43,6 +43,7 @@ import org.apache.geode.cache.configuration.RegionConfig;
 import org.apache.geode.connectors.jdbc.JdbcAsyncWriter;
 import org.apache.geode.connectors.jdbc.internal.configuration.RegionMapping;
 import org.apache.geode.distributed.ConfigurationPersistenceService;
+import org.apache.geode.distributed.internal.DistributionManager;
 import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
 import org.apache.geode.internal.cache.InternalCache;
 import org.apache.geode.management.cli.Result;
@@ -58,6 +59,8 @@ public class CreateMappingCommandTest {
   private String dataSourceName;
   private String tableName;
   private String pdxClass;
+  private String group1Name;
+  private String group2Name;
   private Set<InternalDistributedMember> members;
   private List<CliFunctionResult> results;
   private CliFunctionResult successFunctionResult;
@@ -73,7 +76,11 @@ public class CreateMappingCommandTest {
     dataSourceName = "connection";
     tableName = "testTable";
     pdxClass = "myPdxClass";
+    group1Name = "group1";
+    group2Name = "group2";
     cache = mock(InternalCache.class);
+    DistributionManager dm = mock(DistributionManager.class);
+    when(cache.getDistributionManager()).thenReturn(dm);
     members = new HashSet<>();
     members.add(mock(InternalDistributedMember.class));
     createRegionMappingCommand = spy(CreateMappingCommand.class);
@@ -106,7 +113,20 @@ public class CreateMappingCommandTest {
         mock(ConfigurationPersistenceService.class);
     doReturn(configurationPersistenceService).when(createRegionMappingCommand)
         .getConfigurationPersistenceService();
-    when(configurationPersistenceService.getCacheConfig(null)).thenReturn(cacheConfig);
+    when(configurationPersistenceService
+        .getCacheConfig(ConfigurationPersistenceService.CLUSTER_CONFIG)).thenReturn(cacheConfig);
+    List<RegionConfig> list = new ArrayList<>();
+    list.add(matchingRegion);
+    when(cacheConfig.getRegions()).thenReturn(list);
+  }
+
+  private void setupRequiredPreconditionsForGroup() {
+    ConfigurationPersistenceService configurationPersistenceService =
+        mock(ConfigurationPersistenceService.class);
+    doReturn(configurationPersistenceService).when(createRegionMappingCommand)
+        .getConfigurationPersistenceService();
+    when(configurationPersistenceService.getCacheConfig(group1Name)).thenReturn(cacheConfig);
+    when(configurationPersistenceService.getCacheConfig(group2Name)).thenReturn(cacheConfig);
     List<RegionConfig> list = new ArrayList<>();
     list.add(matchingRegion);
     when(cacheConfig.getRegions()).thenReturn(list);
@@ -121,7 +141,34 @@ public class CreateMappingCommandTest {
     String schema = "schema";
 
     ResultModel result = createRegionMappingCommand.createMapping(regionName, dataSourceName,
-        tableName, pdxClass, false, ids, catalog, schema);
+        tableName, pdxClass, false, ids, catalog, schema, null);
+
+    assertThat(result.getStatus()).isSameAs(Result.Status.OK);
+    Object[] results = (Object[]) result.getConfigObject();
+    RegionMapping regionMapping = (RegionMapping) results[0];
+    boolean synchronous = (boolean) results[1];
+    assertThat(regionMapping).isNotNull();
+    assertThat(regionMapping.getRegionName()).isEqualTo(regionName);
+    assertThat(regionMapping.getDataSourceName()).isEqualTo(dataSourceName);
+    assertThat(regionMapping.getTableName()).isEqualTo(tableName);
+    assertThat(regionMapping.getPdxName()).isEqualTo(pdxClass);
+    assertThat(regionMapping.getIds()).isEqualTo(ids);
+    assertThat(regionMapping.getCatalog()).isEqualTo(catalog);
+    assertThat(regionMapping.getSchema()).isEqualTo(schema);
+    assertThat(synchronous).isFalse();
+  }
+
+  @Test
+  public void createsMappingReturnsStatusOKWhenFunctionResultSuccessWithGroups() {
+    setupRequiredPreconditionsForGroup();
+    results.add(successFunctionResult);
+    String ids = "ids";
+    String catalog = "catalog";
+    String schema = "schema";
+    String[] groups = {group1Name, group2Name};
+
+    ResultModel result = createRegionMappingCommand.createMapping(regionName, dataSourceName,
+        tableName, pdxClass, false, ids, catalog, schema, groups);
 
     assertThat(result.getStatus()).isSameAs(Result.Status.OK);
     Object[] results = (Object[]) result.getConfigObject();
@@ -144,7 +191,7 @@ public class CreateMappingCommandTest {
     results.add(successFunctionResult);
 
     ResultModel result = createRegionMappingCommand.createMapping("/" + regionName, dataSourceName,
-        tableName, pdxClass, false, null, null, null);
+        tableName, pdxClass, false, null, null, null, null);
 
     assertThat(result.getStatus()).isSameAs(Result.Status.OK);
     Object[] results = (Object[]) result.getConfigObject();
@@ -159,7 +206,7 @@ public class CreateMappingCommandTest {
     results.clear();
 
     ResultModel result = createRegionMappingCommand.createMapping(regionName, dataSourceName,
-        tableName, pdxClass, false, null, null, null);
+        tableName, pdxClass, false, null, null, null, null);
 
     assertThat(result.getStatus()).isSameAs(Result.Status.ERROR);
   }
@@ -170,7 +217,7 @@ public class CreateMappingCommandTest {
     doReturn(null).when(createRegionMappingCommand).getConfigurationPersistenceService();
 
     ResultModel result = createRegionMappingCommand.createMapping(regionName, dataSourceName,
-        tableName, pdxClass, false, null, null, null);
+        tableName, pdxClass, false, null, null, null, null);
 
     assertThat(result.getStatus()).isSameAs(Result.Status.ERROR);
     assertThat(result.toString()).contains("Cluster Configuration must be enabled.");
@@ -183,11 +230,12 @@ public class CreateMappingCommandTest {
         mock(ConfigurationPersistenceService.class);
     doReturn(configurationPersistenceService).when(createRegionMappingCommand)
         .getConfigurationPersistenceService();
-    when(configurationPersistenceService.getCacheConfig(null)).thenReturn(cacheConfig);
+    when(configurationPersistenceService
+        .getCacheConfig(ConfigurationPersistenceService.CLUSTER_CONFIG)).thenReturn(cacheConfig);
     when(cacheConfig.getRegions()).thenReturn(Collections.emptyList());
 
     ResultModel result = createRegionMappingCommand.createMapping(regionName, dataSourceName,
-        tableName, pdxClass, false, null, null, null);
+        tableName, pdxClass, false, null, null, null, null);
 
     assertThat(result.getStatus()).isSameAs(Result.Status.ERROR);
     assertThat(result.toString())
@@ -201,7 +249,8 @@ public class CreateMappingCommandTest {
         mock(ConfigurationPersistenceService.class);
     doReturn(configurationPersistenceService).when(createRegionMappingCommand)
         .getConfigurationPersistenceService();
-    when(configurationPersistenceService.getCacheConfig(null)).thenReturn(cacheConfig);
+    when(configurationPersistenceService
+        .getCacheConfig(ConfigurationPersistenceService.CLUSTER_CONFIG)).thenReturn(cacheConfig);
     List<RegionConfig> list = new ArrayList<>();
     list.add(matchingRegion);
     when(cacheConfig.getRegions()).thenReturn(list);
@@ -216,7 +265,7 @@ public class CreateMappingCommandTest {
     when(matchingRegion.getCustomRegionElements()).thenReturn(customList);
 
     ResultModel result = createRegionMappingCommand.createMapping(regionName, dataSourceName,
-        tableName, pdxClass, false, null, null, null);
+        tableName, pdxClass, false, null, null, null, null);
 
     assertThat(result.getStatus()).isSameAs(Result.Status.ERROR);
     assertThat(result.toString()).contains("A JDBC mapping for " + regionName + " already exists.");
@@ -229,7 +278,8 @@ public class CreateMappingCommandTest {
         mock(ConfigurationPersistenceService.class);
     doReturn(configurationPersistenceService).when(createRegionMappingCommand)
         .getConfigurationPersistenceService();
-    when(configurationPersistenceService.getCacheConfig(null)).thenReturn(cacheConfig);
+    when(configurationPersistenceService
+        .getCacheConfig(ConfigurationPersistenceService.CLUSTER_CONFIG)).thenReturn(cacheConfig);
     List<RegionConfig> list = new ArrayList<>();
     list.add(matchingRegion);
     when(cacheConfig.getRegions()).thenReturn(list);
@@ -240,7 +290,7 @@ public class CreateMappingCommandTest {
     when(matchingRegion.getRegionAttributes()).thenReturn(loaderAttribute);
 
     ResultModel result = createRegionMappingCommand.createMapping(regionName, dataSourceName,
-        tableName, pdxClass, false, null, null, null);
+        tableName, pdxClass, false, null, null, null, null);
 
     assertThat(result.getStatus()).isSameAs(Result.Status.ERROR);
     assertThat(result.toString()).contains("The existing region " + regionName
@@ -254,7 +304,8 @@ public class CreateMappingCommandTest {
         mock(ConfigurationPersistenceService.class);
     doReturn(configurationPersistenceService).when(createRegionMappingCommand)
         .getConfigurationPersistenceService();
-    when(configurationPersistenceService.getCacheConfig(null)).thenReturn(cacheConfig);
+    when(configurationPersistenceService
+        .getCacheConfig(ConfigurationPersistenceService.CLUSTER_CONFIG)).thenReturn(cacheConfig);
     List<RegionConfig> list = new ArrayList<>();
     list.add(matchingRegion);
     when(cacheConfig.getRegions()).thenReturn(list);
@@ -265,7 +316,7 @@ public class CreateMappingCommandTest {
     when(matchingRegion.getRegionAttributes()).thenReturn(writerAttribute);
 
     ResultModel result = createRegionMappingCommand.createMapping(regionName, dataSourceName,
-        tableName, pdxClass, true, null, null, null);
+        tableName, pdxClass, true, null, null, null, null);
 
     assertThat(result.getStatus()).isSameAs(Result.Status.ERROR);
     assertThat(result.toString()).contains("The existing region " + regionName
@@ -279,7 +330,8 @@ public class CreateMappingCommandTest {
         mock(ConfigurationPersistenceService.class);
     doReturn(configurationPersistenceService).when(createRegionMappingCommand)
         .getConfigurationPersistenceService();
-    when(configurationPersistenceService.getCacheConfig(null)).thenReturn(cacheConfig);
+    when(configurationPersistenceService
+        .getCacheConfig(ConfigurationPersistenceService.CLUSTER_CONFIG)).thenReturn(cacheConfig);
     List<RegionConfig> list = new ArrayList<>();
     list.add(matchingRegion);
     when(cacheConfig.getRegions()).thenReturn(list);
@@ -294,7 +346,7 @@ public class CreateMappingCommandTest {
     when(cacheConfig.getAsyncEventQueues()).thenReturn(asyncEventQueues);
 
     ResultModel result = createRegionMappingCommand.createMapping(regionName, dataSourceName,
-        tableName, pdxClass, true, null, null, null);
+        tableName, pdxClass, true, null, null, null, null);
 
     assertThat(result.getStatus()).isSameAs(Result.Status.OK);
   }
@@ -307,7 +359,8 @@ public class CreateMappingCommandTest {
         mock(ConfigurationPersistenceService.class);
     doReturn(configurationPersistenceService).when(createRegionMappingCommand)
         .getConfigurationPersistenceService();
-    when(configurationPersistenceService.getCacheConfig(null)).thenReturn(cacheConfig);
+    when(configurationPersistenceService
+        .getCacheConfig(ConfigurationPersistenceService.CLUSTER_CONFIG)).thenReturn(cacheConfig);
     List<RegionConfig> list = new ArrayList<>();
     list.add(matchingRegion);
     when(cacheConfig.getRegions()).thenReturn(list);
@@ -322,7 +375,7 @@ public class CreateMappingCommandTest {
     when(cacheConfig.getAsyncEventQueues()).thenReturn(asyncEventQueues);
 
     ResultModel result = createRegionMappingCommand.createMapping(regionName, dataSourceName,
-        tableName, pdxClass, false, null, null, null);
+        tableName, pdxClass, false, null, null, null, null);
 
     assertThat(result.getStatus()).isSameAs(Result.Status.ERROR);
     assertThat(result.toString())
diff --git a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeMappingFunctionTest.java b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeMappingFunctionTest.java
deleted file mode 100644
index 2e29dd1..0000000
--- a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeMappingFunctionTest.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * 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.connectors.jdbc.internal.cli;
-
-import static org.apache.geode.connectors.util.internal.MappingConstants.CATALOG_NAME;
-import static org.apache.geode.connectors.util.internal.MappingConstants.DATA_SOURCE_NAME;
-import static org.apache.geode.connectors.util.internal.MappingConstants.ID_NAME;
-import static org.apache.geode.connectors.util.internal.MappingConstants.PDX_NAME;
-import static org.apache.geode.connectors.util.internal.MappingConstants.REGION_NAME;
-import static org.apache.geode.connectors.util.internal.MappingConstants.SCHEMA_NAME;
-import static org.apache.geode.connectors.util.internal.MappingConstants.SYNCHRONOUS_NAME;
-import static org.apache.geode.connectors.util.internal.MappingConstants.TABLE_NAME;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import org.apache.commons.lang3.SerializationUtils;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-
-import org.apache.geode.cache.execute.FunctionContext;
-import org.apache.geode.cache.execute.ResultSender;
-import org.apache.geode.connectors.jdbc.internal.JdbcConnectorService;
-import org.apache.geode.connectors.jdbc.internal.configuration.RegionMapping;
-import org.apache.geode.connectors.util.internal.DescribeMappingResult;
-import org.apache.geode.distributed.DistributedMember;
-import org.apache.geode.distributed.DistributedSystem;
-import org.apache.geode.internal.cache.InternalCache;
-import org.apache.geode.management.internal.cli.functions.CliFunctionResult;
-
-public class DescribeMappingFunctionTest {
-
-  private static final String EXISTING_MAPPING = "existingMapping";
-  private static final String TEST_REGION = "testRegion";
-  private static final String TEST_PDX = "testPdx";
-  private static final String TEST_TABLE = "testTableName";
-  private static final String TEST_DATASOURCE = "testDataSource";
-  private static final String TEST_SYNCHRONOUS = "false";
-  private static final String TEST_ID = "testId";
-  private static final String TEST_CATALOG = "testCatalog";
-  private static final String TEST_SCHEMA = "testSchema";
-
-  private DescribeMappingFunction function;
-  private JdbcConnectorService service;
-  private FunctionContext<String> context;
-  private RegionMapping regionMapping;
-  private ResultSender<Object> resultSender;
-
-  @Before
-  public void setUp() {
-    function = new DescribeMappingFunction();
-
-    InternalCache cache = mock(InternalCache.class);
-    context = mock(FunctionContext.class);
-    service = mock(JdbcConnectorService.class);
-    regionMapping = mock(RegionMapping.class);
-    resultSender = mock(ResultSender.class);
-
-    DistributedMember member = mock(DistributedMember.class);
-    DistributedSystem system = mock(DistributedSystem.class);
-
-    when(context.getResultSender()).thenReturn(resultSender);
-    when(context.getCache()).thenReturn(cache);
-    when(cache.getService(eq(JdbcConnectorService.class))).thenReturn(service);
-    when(service.getMappingForRegion(EXISTING_MAPPING)).thenReturn(regionMapping);
-    when(cache.getDistributedSystem()).thenReturn(system);
-    when(system.getDistributedMember()).thenReturn(member);
-    when(regionMapping.getRegionName()).thenReturn(TEST_REGION);
-    when(regionMapping.getDataSourceName()).thenReturn(TEST_DATASOURCE);
-    when(regionMapping.getTableName()).thenReturn(TEST_TABLE);
-    when(regionMapping.getPdxName()).thenReturn(TEST_PDX);
-    when(regionMapping.getIds()).thenReturn(TEST_ID);
-    when(regionMapping.getCatalog()).thenReturn(TEST_CATALOG);
-    when(regionMapping.getSchema()).thenReturn(TEST_SCHEMA);
-  }
-
-  @Test
-  public void isHAReturnsFalse() {
-    assertThat(function.isHA()).isFalse();
-  }
-
-  @Test
-  public void getIdReturnsNameOfClass() {
-    assertThat(function.getId()).isEqualTo(function.getClass().getName());
-  }
-
-  @Test
-  public void serializes() {
-    Serializable original = function;
-    Object copy = SerializationUtils.clone(original);
-    assertThat(copy).isNotSameAs(original).isInstanceOf(DescribeMappingFunction.class);
-  }
-
-  @Test
-  public void returnsResultWithCorrectConfig() {
-    when(context.getArguments()).thenReturn(EXISTING_MAPPING);
-
-    function.execute(context);
-
-    Map<String, String> expectedAttributes = new LinkedHashMap<>();
-    expectedAttributes.put(REGION_NAME, TEST_REGION);
-    expectedAttributes.put(TABLE_NAME, TEST_TABLE);
-    expectedAttributes.put(DATA_SOURCE_NAME, TEST_DATASOURCE);
-    expectedAttributes.put(ID_NAME, TEST_ID);
-    expectedAttributes.put(PDX_NAME, TEST_PDX);
-    expectedAttributes.put(SYNCHRONOUS_NAME, TEST_SYNCHRONOUS);
-    expectedAttributes.put(CATALOG_NAME, TEST_CATALOG);
-    expectedAttributes.put(SCHEMA_NAME, TEST_SCHEMA);
-
-    ArgumentCaptor<CliFunctionResult> argument = ArgumentCaptor.forClass(CliFunctionResult.class);
-    verify(resultSender, times(1)).lastResult(argument.capture());
-    DescribeMappingResult result = (DescribeMappingResult) argument.getValue().getResultObject();
-    assertThat(result.getAttributeMap()).isEqualTo(expectedAttributes);
-
-    assertThat(new ArrayList<String>(result.getAttributeMap().keySet()))
-        .isEqualTo(new ArrayList<String>(expectedAttributes.keySet()));
-  }
-
-  @Test
-  public void returnNullWithNonExistingConfig() {
-    when(context.getArguments()).thenReturn("non existing");
-
-    function.execute(context);
-
-    ArgumentCaptor<CliFunctionResult> argument = ArgumentCaptor.forClass(CliFunctionResult.class);
-    verify(resultSender, times(1)).lastResult(argument.capture());
-    assertThat(argument.getValue().getResultObject()).isNull();
-
-  }
-
-  @Test
-  public void executeReturnsResultForExceptionWithoutMessage() {
-    when(service.getMappingForRegion(any())).thenThrow(new NullPointerException());
-
-    function.execute(context);
-
-    ArgumentCaptor<CliFunctionResult> argument = ArgumentCaptor.forClass(CliFunctionResult.class);
-    verify(resultSender, times(1)).lastResult(argument.capture());
-    assertThat(argument.getValue().getStatusMessage())
-        .contains(NullPointerException.class.getName());
-  }
-
-  @Test
-  public void executeReturnsResultForExceptionWithMessage() {
-    when(service.getMappingForRegion(any()))
-        .thenThrow(new IllegalArgumentException("some message"));
-
-    function.execute(context);
-
-    ArgumentCaptor<CliFunctionResult> argument = ArgumentCaptor.forClass(CliFunctionResult.class);
-    verify(resultSender, times(1)).lastResult(argument.capture());
-    assertThat(argument.getValue().getStatusMessage()).contains("some message");
-  }
-}
diff --git a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/org/apache/geode/connectors/util/DescribeMappingCommandTest.java b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/org/apache/geode/connectors/util/DescribeMappingCommandTest.java
index 2ad9006..3eed997 100644
--- a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/org/apache/geode/connectors/util/DescribeMappingCommandTest.java
+++ b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/org/apache/geode/connectors/util/DescribeMappingCommandTest.java
@@ -22,42 +22,56 @@ import static org.apache.geode.connectors.util.internal.MappingConstants.REGION_
 import static org.apache.geode.connectors.util.internal.MappingConstants.SCHEMA_NAME;
 import static org.apache.geode.connectors.util.internal.MappingConstants.SYNCHRONOUS_NAME;
 import static org.apache.geode.connectors.util.internal.MappingConstants.TABLE_NAME;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Set;
+import java.util.ArrayList;
 
 import org.junit.Before;
 import org.junit.ClassRule;
 import org.junit.Test;
+import org.mockito.Mock;
 
-import org.apache.geode.cache.execute.ResultCollector;
+import org.apache.geode.cache.configuration.CacheConfig;
+import org.apache.geode.cache.configuration.CacheElement;
+import org.apache.geode.cache.configuration.RegionConfig;
+import org.apache.geode.connectors.jdbc.internal.cli.CreateMappingCommand;
 import org.apache.geode.connectors.jdbc.internal.cli.DescribeMappingCommand;
-import org.apache.geode.connectors.util.internal.DescribeMappingResult;
-import org.apache.geode.distributed.DistributedMember;
-import org.apache.geode.management.internal.cli.functions.CliFunctionResult;
+import org.apache.geode.connectors.jdbc.internal.configuration.RegionMapping;
+import org.apache.geode.distributed.ConfigurationPersistenceService;
 import org.apache.geode.test.junit.rules.GfshParserRule;
 
 
 public class DescribeMappingCommandTest {
-  public static final String COMMAND = "describe jdbc-mapping --region=region ";
+  public static final String COMMAND = "describe jdbc-mapping --region=region1";
   private DescribeMappingCommand command;
 
+  @Mock
+  ConfigurationPersistenceService configurationPersistenceService;
+
+  @Mock
+  CacheConfig clusterConfig;
+
+  @Mock
+  RegionConfig regionConfig;
+
   @ClassRule
   public static GfshParserRule gfsh = new GfshParserRule();
 
   @Before
   public void setUp() {
     command = spy(DescribeMappingCommand.class);
+    configurationPersistenceService = mock(ConfigurationPersistenceService.class);
+    clusterConfig = mock(CacheConfig.class);
+    regionConfig = mock(RegionConfig.class);
+    when(command.getConfigurationPersistenceService()).thenReturn(configurationPersistenceService);
+    when(configurationPersistenceService
+        .getCacheConfig(ConfigurationPersistenceService.CLUSTER_CONFIG)).thenReturn(clusterConfig);
+    ArrayList<RegionConfig> regionConfigList = new ArrayList<RegionConfig>();
+    regionConfigList.add(regionConfig);
+    when(clusterConfig.getRegions()).thenReturn(regionConfigList);
+    when(regionConfig.getName()).thenReturn("region1");
   }
 
   @Test
@@ -67,41 +81,112 @@ public class DescribeMappingCommandTest {
   }
 
   @Test
-  public void whenNoMemberExists() {
-    doReturn(Collections.emptySet()).when(command).findMembers(null, null);
+  public void commandFailureWhenClusterConfigServiceNotEnabled() {
+    RegionMapping regionMapping = new RegionMapping();
+    regionMapping.setRegionName("region1");
+    regionMapping.setPdxName("class1");
+    regionMapping.setTableName("table1");
+    regionMapping.setDataSourceName("name1");
+    regionMapping.setIds("myId");
+    regionMapping.setCatalog("myCatalog");
+    regionMapping.setSchema("mySchema");
+    ArrayList<CacheElement> elements = new ArrayList<>();
+    elements.add(regionMapping);
+    when(command.getConfigurationPersistenceService()).thenReturn(null);
 
     gfsh.executeAndAssertThat(command, COMMAND).statusIsError()
-        .containsOutput("No Members Found");
+        .containsOutput("Cluster Configuration must be enabled.");
   }
 
   @Test
-  public void whenMemberExists() {
-    doReturn(Collections.singleton(mock(DistributedMember.class))).when(command).findMembers(null,
-        null);
-    Map<String, String> attributes = new LinkedHashMap<>();
-    attributes.put(REGION_NAME, "region");
-    attributes.put(PDX_NAME, "class1");
-    attributes.put(TABLE_NAME, "table1");
-    attributes.put(DATA_SOURCE_NAME, "name1");
-    attributes.put(SYNCHRONOUS_NAME, "true");
-    attributes.put(ID_NAME, "myId");
-    attributes.put(CATALOG_NAME, "myCatalog");
-    attributes.put(SCHEMA_NAME, "mySchema");
+  public void commandFailureWhenClusterConfigServiceEnabledAndCacheConfigNotFound() {
+    RegionMapping regionMapping = new RegionMapping();
+    regionMapping.setRegionName("region1");
+    regionMapping.setPdxName("class1");
+    regionMapping.setTableName("table1");
+    regionMapping.setDataSourceName("name1");
+    regionMapping.setIds("myId");
+    regionMapping.setCatalog("myCatalog");
+    regionMapping.setSchema("mySchema");
+    ArrayList<CacheElement> elements = new ArrayList<>();
+    elements.add(regionMapping);
+    when(configurationPersistenceService
+        .getCacheConfig(ConfigurationPersistenceService.CLUSTER_CONFIG)).thenReturn(null);
+
+    gfsh.executeAndAssertThat(command, COMMAND).statusIsError()
+        .containsOutput("Cache Configuration not found.");
+  }
+
+  @Test
+  public void commandFailureWhenClusterConfigServiceEnabledAndCacheConfigNotFoundWithGroup() {
+    RegionMapping regionMapping = new RegionMapping();
+    regionMapping.setRegionName("region1");
+    regionMapping.setPdxName("class1");
+    regionMapping.setTableName("table1");
+    regionMapping.setDataSourceName("name1");
+    regionMapping.setIds("myId");
+    regionMapping.setCatalog("myCatalog");
+    regionMapping.setSchema("mySchema");
+    ArrayList<CacheElement> elements = new ArrayList<>();
+    elements.add(regionMapping);
+    when(configurationPersistenceService.getCacheConfig("group1")).thenReturn(null);
+
+    gfsh.executeAndAssertThat(command, COMMAND + " --group=group1").statusIsError()
+        .containsOutput("Cache Configuration not found for group group1.");
+  }
 
-    DescribeMappingResult mappingResult = new DescribeMappingResult(attributes);
+  @Test
+  public void commandFailureWhenCacheConfigFoundAndRegionConfigNotFound() {
+    RegionMapping regionMapping = new RegionMapping();
+    regionMapping.setRegionName("region1");
+    regionMapping.setPdxName("class1");
+    regionMapping.setTableName("table1");
+    regionMapping.setDataSourceName("name1");
+    regionMapping.setIds("myId");
+    regionMapping.setCatalog("myCatalog");
+    regionMapping.setSchema("mySchema");
+    when(clusterConfig.getRegions()).thenReturn(new ArrayList<>());
 
+    gfsh.executeAndAssertThat(command, COMMAND).statusIsError()
+        .containsOutput("A region named region1 must already exist.");
+  }
 
-    ResultCollector rc = mock(ResultCollector.class);
-    doReturn(rc).when(command).executeFunction(any(), any(), any(Set.class));
-    when(rc.getResult()).thenReturn(
-        Collections.singletonList(new CliFunctionResult("server-1", mappingResult, "success")));
+  @Test
+  public void commandFailureWhenCacheConfigFoundAndRegionConfigNotFoundWithGroup() {
+    RegionMapping regionMapping = new RegionMapping();
+    regionMapping.setRegionName("region1");
+    regionMapping.setPdxName("class1");
+    regionMapping.setTableName("table1");
+    regionMapping.setDataSourceName("name1");
+    regionMapping.setIds("myId");
+    regionMapping.setCatalog("myCatalog");
+    regionMapping.setSchema("mySchema");
+    when(clusterConfig.getRegions()).thenReturn(new ArrayList<>());
+    when(configurationPersistenceService.getCacheConfig("group1")).thenReturn(clusterConfig);
 
+    gfsh.executeAndAssertThat(command, COMMAND + " --groups=group1").statusIsError()
+        .containsOutput("A region named region1 must already exist for group group1.");
+  }
 
+  @Test
+  public void commandSuccessWhenClusterConfigFoundAndRegionConfigFound() {
+    RegionMapping regionMapping = new RegionMapping();
+    regionMapping.setRegionName("region1");
+    regionMapping.setPdxName("class1");
+    regionMapping.setTableName("table1");
+    regionMapping.setDataSourceName("name1");
+    regionMapping.setIds("myId");
+    regionMapping.setCatalog("myCatalog");
+    regionMapping.setSchema("mySchema");
+    ArrayList<CacheElement> elements = new ArrayList<>();
+    elements.add(regionMapping);
+    when(regionConfig.getCustomRegionElements()).thenReturn(elements);
 
     gfsh.executeAndAssertThat(command, COMMAND).statusIsSuccess()
-        .containsOrderedOutput(DescribeMappingCommand.RESULT_SECTION_NAME, REGION_NAME, PDX_NAME,
+        .containsOrderedOutput(DescribeMappingCommand.RESULT_SECTION_NAME + "0", REGION_NAME,
+            PDX_NAME,
             TABLE_NAME, DATA_SOURCE_NAME, SYNCHRONOUS_NAME, ID_NAME, CATALOG_NAME, SCHEMA_NAME)
-        .containsOutput(REGION_NAME, "region")
+        .containsOutput(REGION_NAME, "region1")
         .containsOutput(DATA_SOURCE_NAME, "name1").containsOutput(TABLE_NAME, "table1")
         .containsOutput(PDX_NAME, "class1").containsOutput(ID_NAME, "myId")
         .containsOutput(SCHEMA_NAME, "mySchema").containsOutput(CATALOG_NAME, "myCatalog")
@@ -109,30 +194,77 @@ public class DescribeMappingCommandTest {
   }
 
   @Test
-  public void whenMemberExistsWithRegionPathFunctionIsCalledWithNoSlashRegionName() {
-    doReturn(Collections.singleton(mock(DistributedMember.class))).when(command).findMembers(null,
-        null);
-    ResultCollector rc = mock(ResultCollector.class);
-    doReturn(rc).when(command).executeFunction(any(), any(), any(Set.class));
-    when(rc.getResult()).thenReturn(
-        Collections.singletonList(
-            new CliFunctionResult("server-1", mock(DescribeMappingResult.class), "success")));
-
-    command.describeMapping("/regionName");
-
-    verify(command, times(1)).executeFunctionAndGetFunctionResult(any(), eq("regionName"), any());
+  public void commandSuccessWhenClusterConfigFoundAndRegionConfigFoundAsync() {
+
+    CacheConfig.AsyncEventQueue asyncEventQueue = mock(CacheConfig.AsyncEventQueue.class);
+    ArrayList<CacheConfig.AsyncEventQueue> queueList = new ArrayList<>();
+    // Adding multiple mocked objects to the list to demonstrate the ability to distinguish the
+    // correct queue later on
+    queueList.add(asyncEventQueue);
+    queueList.add(asyncEventQueue);
+    queueList.add(asyncEventQueue);
+
+    RegionMapping regionMapping = new RegionMapping();
+    regionMapping.setRegionName("region1");
+    regionMapping.setPdxName("class1");
+    regionMapping.setTableName("table1");
+    regionMapping.setDataSourceName("name1");
+    regionMapping.setIds("myId");
+    regionMapping.setCatalog("myCatalog");
+    regionMapping.setSchema("mySchema");
+    ArrayList<CacheElement> elements = new ArrayList<>();
+    elements.add(regionMapping);
+    when(regionConfig.getCustomRegionElements()).thenReturn(elements);
+    when(clusterConfig.getAsyncEventQueues()).thenReturn(queueList);
+    when(asyncEventQueue.getId())
+        .thenReturn(CreateMappingCommand.createAsyncEventQueueName("region2"))
+        .thenReturn(CreateMappingCommand.createAsyncEventQueueName("region1"))
+        .thenReturn(CreateMappingCommand.createAsyncEventQueueName("region3"));
+
+    gfsh.executeAndAssertThat(command, COMMAND).statusIsSuccess()
+        .containsOrderedOutput(DescribeMappingCommand.RESULT_SECTION_NAME + "0", REGION_NAME,
+            PDX_NAME,
+            TABLE_NAME, DATA_SOURCE_NAME, SYNCHRONOUS_NAME, ID_NAME, CATALOG_NAME, SCHEMA_NAME)
+        .containsOutput(REGION_NAME, "region1")
+        .containsOutput(DATA_SOURCE_NAME, "name1").containsOutput(TABLE_NAME, "table1")
+        .containsOutput(PDX_NAME, "class1").containsOutput(ID_NAME, "myId")
+        .containsOutput(SCHEMA_NAME, "mySchema").containsOutput(CATALOG_NAME, "myCatalog")
+        .containsOutput("false");
+  }
+
+  @Test
+  public void whenMemberExistsForGroup() {
+    RegionMapping regionMapping = new RegionMapping();
+    regionMapping.setRegionName("region1");
+    regionMapping.setPdxName("class1");
+    regionMapping.setTableName("table1");
+    regionMapping.setDataSourceName("name1");
+    regionMapping.setIds("myId");
+    regionMapping.setCatalog("myCatalog");
+    regionMapping.setSchema("mySchema");
+    ArrayList<CacheElement> elements = new ArrayList<>();
+    elements.add(regionMapping);
+    when(regionConfig.getCustomRegionElements()).thenReturn(elements);
+    when(configurationPersistenceService.getCacheConfig("group1")).thenReturn(clusterConfig);
+
+
+
+    gfsh.executeAndAssertThat(command, COMMAND + " --groups=group1").statusIsSuccess()
+        .containsOrderedOutput(DescribeMappingCommand.RESULT_SECTION_NAME + "0", REGION_NAME,
+            PDX_NAME,
+            TABLE_NAME, DATA_SOURCE_NAME, SYNCHRONOUS_NAME, ID_NAME, CATALOG_NAME, SCHEMA_NAME)
+        .containsOutput(REGION_NAME, "region1")
+        .containsOutput(DATA_SOURCE_NAME, "name1").containsOutput(TABLE_NAME, "table1")
+        .containsOutput(PDX_NAME, "class1").containsOutput(ID_NAME, "myId")
+        .containsOutput(SCHEMA_NAME, "mySchema").containsOutput(CATALOG_NAME, "myCatalog")
+        .containsOutput("true");
   }
 
   @Test
   public void whenNoMappingFoundOnMember() {
-    doReturn(Collections.singleton(mock(DistributedMember.class))).when(command).findMembers(null,
-        null);
-
-    ResultCollector rc = mock(ResultCollector.class);
-    doReturn(rc).when(command).executeFunction(any(), any(), any(Set.class));
-    when(rc.getResult()).thenReturn(Collections.emptyList());
+    when(regionConfig.getCustomRegionElements()).thenReturn(new ArrayList<>());
 
     gfsh.executeAndAssertThat(command, COMMAND).statusIsError()
-        .containsOutput("mapping for region 'region' not found");
+        .containsOutput("mapping for region 'region1' not found");
   }
 }
diff --git a/geode-connectors/src/test/java/org/apache/geode/connectors/util/internal/DescribeMappingResultTest.java b/geode-connectors/src/test/java/org/apache/geode/connectors/util/internal/DescribeMappingResultTest.java
deleted file mode 100644
index c2e75d8..0000000
--- a/geode-connectors/src/test/java/org/apache/geode/connectors/util/internal/DescribeMappingResultTest.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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.connectors.util.internal;
-
-import static org.apache.geode.connectors.util.internal.MappingConstants.DATA_SOURCE_NAME;
-import static org.apache.geode.connectors.util.internal.MappingConstants.ID_NAME;
-import static org.apache.geode.connectors.util.internal.MappingConstants.PDX_NAME;
-import static org.apache.geode.connectors.util.internal.MappingConstants.REGION_NAME;
-import static org.apache.geode.connectors.util.internal.MappingConstants.SYNCHRONOUS_NAME;
-import static org.apache.geode.connectors.util.internal.MappingConstants.TABLE_NAME;
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.jgroups.util.ByteArrayDataInputStream;
-import org.jgroups.util.ByteArrayDataOutputStream;
-import org.junit.Test;
-
-public class DescribeMappingResultTest {
-
-  @Test
-  public void testSeriazilabeToAndFromByteArray() throws IOException {
-    Map<String, String> attributesMap = new HashMap<>();
-    attributesMap.put(REGION_NAME, "myRegion");
-    attributesMap.put(TABLE_NAME, "myTable");
-    attributesMap.put(PDX_NAME, "myPdx");
-    attributesMap.put(DATA_SOURCE_NAME, "myDatasource");
-    attributesMap.put(SYNCHRONOUS_NAME, "false");
-    attributesMap.put(ID_NAME, "myId");
-
-    DescribeMappingResult result = new DescribeMappingResult(attributesMap);
-    DescribeMappingResult newResult = new DescribeMappingResult();
-
-    ByteArrayDataOutputStream output = new ByteArrayDataOutputStream();
-    ByteArrayDataInputStream input;
-
-    result.toData(output);
-
-    input = new ByteArrayDataInputStream(output.buffer());
-
-    newResult.fromData(input);
-
-    Map<String, String> newAttributeMap = newResult.getAttributeMap();
-    assertThat(attributesMap).isEqualTo(newAttributeMap);
-  }
-
-}
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/CliUtil.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/CliUtil.java
index b2d4dd6..d139294 100755
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/CliUtil.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/CliUtil.java
@@ -28,6 +28,7 @@ import java.io.UnsupportedEncodingException;
 import java.net.URLDecoder;
 import java.nio.charset.Charset;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -135,13 +136,12 @@ public class CliUtil {
     allClusterMembers.add(cache.getDistributedSystem().getDistributedMember());
 
     for (DistributedMember member : allClusterMembers) {
-      for (String regionAssociatedMemberName : regionAssociatedMemberNames) {
-        String name = MBeanJMXAdapter.getMemberNameOrUniqueId(member);
-        if (name.equals(regionAssociatedMemberName)) {
-          matchedMembers.add(member);
-          if (!returnAll) {
-            return matchedMembers;
-          }
+      List<String> regionAssociatedMemberNamesList = Arrays.asList(regionAssociatedMemberNames);
+      String name = MBeanJMXAdapter.getMemberNameOrUniqueId(member);
+      if (regionAssociatedMemberNamesList.contains(name)) {
+        matchedMembers.add(member);
+        if (!returnAll) {
+          return matchedMembers;
         }
       }
     }
diff --git a/geode-junit/src/main/java/org/apache/geode/test/junit/assertions/CommandResultAssert.java b/geode-junit/src/main/java/org/apache/geode/test/junit/assertions/CommandResultAssert.java
index 2a0afd0..e674e58 100644
--- a/geode-junit/src/main/java/org/apache/geode/test/junit/assertions/CommandResultAssert.java
+++ b/geode-junit/src/main/java/org/apache/geode/test/junit/assertions/CommandResultAssert.java
@@ -91,8 +91,15 @@ public class CommandResultAssert
 
   public CommandResultAssert containsOrderedOutput(String dataSectionName,
       String... expectedOutputs) {
-    LinkedHashMap<String, String> outputMap =
-        ((LinkedHashMap) actual.getCommandResult().getMapFromSection(dataSectionName));
+
+    LinkedHashMap<String, String> outputMap;
+    try {
+      outputMap =
+          ((LinkedHashMap) actual.getCommandResult().getMapFromSection(dataSectionName));
+    } catch (NullPointerException ex) {
+      Assert.fail("No section found for \"" + dataSectionName + "\"");
+      return this;
+    }
     String outputString = outputMap.toString();
     int outputIndex = 0;