geode-issues mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "ASF GitHub Bot (JIRA)" <j...@apache.org>
Subject [jira] [Commented] (GEODE-3955) The gfsh 'describe region' command doesn't include asyncEventQueueIds or gatewaySenderIds
Date Wed, 06 Dec 2017 22:36:01 GMT

    [ https://issues.apache.org/jira/browse/GEODE-3955?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16281043#comment-16281043 ] 

ASF GitHub Bot commented on GEODE-3955:
---------------------------------------

PurelyApplied closed pull request #1099: GEODE-3955: Add AEQ and Gateway Sender information to 'describe region' output.
URL: https://github.com/apache/geode/pull/1099
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommand.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommand.java
index 732ca09210..889107c289 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommand.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommand.java
@@ -299,7 +299,7 @@ public Result createRegion(
         if (!specifiedGatewaySenders.isEmpty()) {
           return ResultBuilder.createUserErrorResult(CliStrings.format(
               CliStrings.CREATE_REGION__MSG__SPECIFY_VALID_GATEWAYSENDER_ID_UNKNOWN_0,
-              new Object[] {gatewaySenderIds}));
+              gatewaySenderIds));
         }
       }
     }
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/DescribeRegionCommand.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/DescribeRegionCommand.java
index ebbdb6c5b3..0abe36aec6 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/DescribeRegionCommand.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/DescribeRegionCommand.java
@@ -15,22 +15,22 @@
 
 package org.apache.geode.management.internal.cli.commands;
 
-import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.logging.log4j.Logger;
 import org.springframework.shell.core.annotation.CliCommand;
 import org.springframework.shell.core.annotation.CliOption;
 
 import org.apache.geode.cache.execute.ResultCollector;
 import org.apache.geode.internal.cache.InternalCache;
+import org.apache.geode.internal.logging.LogService;
 import org.apache.geode.management.cli.CliMetaData;
 import org.apache.geode.management.cli.ConverterHint;
 import org.apache.geode.management.cli.Result;
 import org.apache.geode.management.internal.cli.CliUtil;
-import org.apache.geode.management.internal.cli.LogWrapper;
 import org.apache.geode.management.internal.cli.domain.FixedPartitionAttributesInfo;
 import org.apache.geode.management.internal.cli.domain.RegionDescription;
 import org.apache.geode.management.internal.cli.domain.RegionDescriptionPerMember;
@@ -44,6 +44,8 @@
 import org.apache.geode.security.ResourcePermission;
 
 public class DescribeRegionCommand implements GfshCommand {
+  public static final Logger logger = LogService.getLogger();
+
   private static final GetRegionDescriptionFunction getRegionDescription =
       new GetRegionDescriptionFunction();
 
@@ -55,153 +57,134 @@ public Result describeRegion(
       @CliOption(key = CliStrings.DESCRIBE_REGION__NAME, optionContext = ConverterHint.REGION_PATH,
           help = CliStrings.DESCRIBE_REGION__NAME__HELP, mandatory = true) String regionName) {
 
-    Result result;
+    List<?> resultList = getFunctionResultFromMembers(regionName);
+
+    // Log any errors received.
+    resultList.stream().filter(Throwable.class::isInstance).map(Throwable.class::cast)
+        .forEach(t -> logger.info(t.getMessage(), t));
+
+    // Aggregate PerMember data to to a single RegionDescription
+    RegionDescription regionDescription = new RegionDescription();
+    resultList.stream().filter(RegionDescriptionPerMember.class::isInstance)
+        .map(RegionDescriptionPerMember.class::cast).forEach(regionDescription::add);
+
+    // No point in displaying the scope for PR's
+    if (regionDescription.isPartition()) {
+      regionDescription.getCndRegionAttributes().remove(RegionAttributesNames.SCOPE);
+    } else {
+      String scope = regionDescription.getCndRegionAttributes().get(RegionAttributesNames.SCOPE);
+      if (scope != null) {
+        scope = scope.toLowerCase().replace('_', '-');
+        regionDescription.getCndRegionAttributes().put(RegionAttributesNames.SCOPE, scope);
+      }
+    }
+
+    return buildDescriptionResult(regionName, regionDescription);
+  }
 
+  List<?> getFunctionResultFromMembers(String regionName) {
     InternalCache cache = getCache();
     ResultCollector<?, ?> rc =
-        CliUtil.executeFunction(getRegionDescription, regionName, CliUtil.getAllMembers(cache));
-
-    List<?> resultList = (List<?>) rc.getResult();
-
-    // The returned result could be a region description with per member and /or single local
-    // region
-    Object[] results = resultList.toArray();
-    List<RegionDescription> regionDescriptionList = new ArrayList<>();
-
-    for (int i = 0; i < results.length; i++) {
-
-      if (results[i] instanceof RegionDescriptionPerMember) {
-        RegionDescriptionPerMember regionDescPerMember = (RegionDescriptionPerMember) results[i];
-
-        if (regionDescPerMember != null) {
-          RegionDescription regionDescription = new RegionDescription();
-          regionDescription.add(regionDescPerMember);
-
-          for (int j = i + 1; j < results.length; j++) {
-            if (results[j] != null && results[j] instanceof RegionDescriptionPerMember) {
-              RegionDescriptionPerMember preyRegionDescPerMember =
-                  (RegionDescriptionPerMember) results[j];
-              if (regionDescription.add(preyRegionDescPerMember)) {
-                results[j] = null;
-              }
-            }
-          }
-          regionDescriptionList.add(regionDescription);
-        }
-      } else if (results[i] instanceof Throwable) {
-        Throwable t = (Throwable) results[i];
-        LogWrapper.getInstance().info(t.getMessage(), t);
-      }
-    }
+        executeFunction(getRegionDescription, regionName, getAllNormalMembers(cache));
 
-    if (regionDescriptionList.isEmpty()) {
+    return (List<?>) rc.getResult();
+  }
+
+  public Result buildDescriptionResult(String regionName, RegionDescription regionDescription) {
+    if (regionDescription.isEmpty()) {
       return ResultBuilder
           .createUserErrorResult(CliStrings.format(CliStrings.REGION_NOT_FOUND, regionName));
     }
 
     CompositeResultData crd = ResultBuilder.createCompositeResultData();
+    CompositeResultData.SectionResultData regionSection = crd.addSection();
+    regionSection.addSeparator('-');
+    regionSection.addData("Name", regionDescription.getName());
 
-    for (RegionDescription regionDescription : regionDescriptionList) {
-      // No point in displaying the scope for PR's
-      if (regionDescription.isPartition()) {
-        regionDescription.getCndRegionAttributes().remove(RegionAttributesNames.SCOPE);
-      } else {
-        String scope = regionDescription.getCndRegionAttributes().get(RegionAttributesNames.SCOPE);
-        if (scope != null) {
-          scope = scope.toLowerCase().replace('_', '-');
-          regionDescription.getCndRegionAttributes().put(RegionAttributesNames.SCOPE, scope);
-        }
-      }
-      CompositeResultData.SectionResultData regionSection = crd.addSection();
-      regionSection.addSeparator('-');
-      regionSection.addData("Name", regionDescription.getName());
-
-      String dataPolicy =
-          regionDescription.getDataPolicy().toString().toLowerCase().replace('_', ' ');
-      regionSection.addData("Data Policy", dataPolicy);
+    String dataPolicy =
+        regionDescription.getDataPolicy().toString().toLowerCase().replace('_', ' ');
+    regionSection.addData("Data Policy", dataPolicy);
 
-      String memberType;
+    String memberType;
 
-      if (regionDescription.isAccessor()) {
-        memberType = CliStrings.DESCRIBE_REGION__ACCESSOR__MEMBER;
-      } else {
-        memberType = CliStrings.DESCRIBE_REGION__HOSTING__MEMBER;
-      }
-      regionSection.addData(memberType,
-          CliUtil.convertStringSetToString(regionDescription.getHostingMembers(), '\n'));
-      regionSection.addSeparator('.');
-
-      TabularResultData commonNonDefaultAttrTable = regionSection.addSection().addTable();
-
-      commonNonDefaultAttrTable.setHeader(CliStrings
-          .format(CliStrings.DESCRIBE_REGION__NONDEFAULT__COMMONATTRIBUTES__HEADER, memberType));
-      // Common Non Default Region Attributes
-      Map<String, String> cndRegionAttrsMap = regionDescription.getCndRegionAttributes();
-
-      // Common Non Default Eviction Attributes
-      Map<String, String> cndEvictionAttrsMap = regionDescription.getCndEvictionAttributes();
-
-      // Common Non Default Partition Attributes
-      Map<String, String> cndPartitionAttrsMap = regionDescription.getCndPartitionAttributes();
-
-      writeCommonAttributesToTable(commonNonDefaultAttrTable,
-          CliStrings.DESCRIBE_REGION__ATTRIBUTE__TYPE__REGION, cndRegionAttrsMap);
-      writeCommonAttributesToTable(commonNonDefaultAttrTable,
-          CliStrings.DESCRIBE_REGION__ATTRIBUTE__TYPE__EVICTION, cndEvictionAttrsMap);
-      writeCommonAttributesToTable(commonNonDefaultAttrTable,
-          CliStrings.DESCRIBE_REGION__ATTRIBUTE__TYPE__PARTITION, cndPartitionAttrsMap);
-
-      // Member-wise non default Attributes
-      Map<String, RegionDescriptionPerMember> regDescPerMemberMap =
-          regionDescription.getRegionDescriptionPerMemberMap();
-      Set<String> members = regDescPerMemberMap.keySet();
-
-      TabularResultData table = regionSection.addSection().addTable();
-
-      boolean setHeader = false;
-      for (String member : members) {
-        RegionDescriptionPerMember regDescPerMem = regDescPerMemberMap.get(member);
-        Map<String, String> ndRa = regDescPerMem.getNonDefaultRegionAttributes();
-        Map<String, String> ndEa = regDescPerMem.getNonDefaultEvictionAttributes();
-        Map<String, String> ndPa = regDescPerMem.getNonDefaultPartitionAttributes();
-
-        // Get all the member-specific non-default attributes by removing the common keys
-        ndRa.keySet().removeAll(cndRegionAttrsMap.keySet());
-        ndEa.keySet().removeAll(cndEvictionAttrsMap.keySet());
-        ndPa.keySet().removeAll(cndPartitionAttrsMap.keySet());
-
-        // Scope is not valid for PR's
-        if (regionDescription.isPartition()) {
-          if (ndRa.get(RegionAttributesNames.SCOPE) != null) {
-            ndRa.remove(RegionAttributesNames.SCOPE);
-          }
+    if (regionDescription.isAccessor()) {
+      memberType = CliStrings.DESCRIBE_REGION__ACCESSOR__MEMBER;
+    } else {
+      memberType = CliStrings.DESCRIBE_REGION__HOSTING__MEMBER;
+    }
+    regionSection.addData(memberType,
+        CliUtil.convertStringSetToString(regionDescription.getHostingMembers(), '\n'));
+    regionSection.addSeparator('.');
+
+    TabularResultData commonNonDefaultAttrTable = regionSection.addSection().addTable();
+
+    commonNonDefaultAttrTable.setHeader(CliStrings
+        .format(CliStrings.DESCRIBE_REGION__NONDEFAULT__COMMONATTRIBUTES__HEADER, memberType));
+    // Common Non Default Region Attributes
+    Map<String, String> cndRegionAttrsMap = regionDescription.getCndRegionAttributes();
+
+    // Common Non Default Eviction Attributes
+    Map<String, String> cndEvictionAttrsMap = regionDescription.getCndEvictionAttributes();
+
+    // Common Non Default Partition Attributes
+    Map<String, String> cndPartitionAttrsMap = regionDescription.getCndPartitionAttributes();
+
+    writeCommonAttributesToTable(commonNonDefaultAttrTable,
+        CliStrings.DESCRIBE_REGION__ATTRIBUTE__TYPE__REGION, cndRegionAttrsMap);
+    writeCommonAttributesToTable(commonNonDefaultAttrTable,
+        CliStrings.DESCRIBE_REGION__ATTRIBUTE__TYPE__EVICTION, cndEvictionAttrsMap);
+    writeCommonAttributesToTable(commonNonDefaultAttrTable,
+        CliStrings.DESCRIBE_REGION__ATTRIBUTE__TYPE__PARTITION, cndPartitionAttrsMap);
+
+    // Member-wise non default Attributes
+    Map<String, RegionDescriptionPerMember> regDescPerMemberMap =
+        regionDescription.getRegionDescriptionPerMemberMap();
+    Set<String> members = regDescPerMemberMap.keySet();
+
+    TabularResultData table = regionSection.addSection().addTable();
+
+    boolean setHeader = false;
+    for (String member : members) {
+      RegionDescriptionPerMember regDescPerMem = regDescPerMemberMap.get(member);
+      Map<String, String> ndRa = regDescPerMem.getNonDefaultRegionAttributes();
+      Map<String, String> ndEa = regDescPerMem.getNonDefaultEvictionAttributes();
+      Map<String, String> ndPa = regDescPerMem.getNonDefaultPartitionAttributes();
+
+      // Get all the member-specific non-default attributes by removing the common keys
+      ndRa.keySet().removeAll(cndRegionAttrsMap.keySet());
+      ndEa.keySet().removeAll(cndEvictionAttrsMap.keySet());
+      ndPa.keySet().removeAll(cndPartitionAttrsMap.keySet());
+
+      // Scope is not valid for PR's
+      if (regionDescription.isPartition()) {
+        if (ndRa.get(RegionAttributesNames.SCOPE) != null) {
+          ndRa.remove(RegionAttributesNames.SCOPE);
         }
+      }
 
-        List<FixedPartitionAttributesInfo> fpaList = regDescPerMem.getFixedPartitionAttributes();
+      List<FixedPartitionAttributesInfo> fpaList = regDescPerMem.getFixedPartitionAttributes();
 
-        if (!(ndRa.isEmpty() && ndEa.isEmpty() && ndPa.isEmpty()) || fpaList != null) {
-          setHeader = true;
-          boolean memberNameAdded;
-          memberNameAdded = writeAttributesToTable(table,
-              CliStrings.DESCRIBE_REGION__ATTRIBUTE__TYPE__REGION, ndRa, member, false);
-          memberNameAdded = writeAttributesToTable(table,
-              CliStrings.DESCRIBE_REGION__ATTRIBUTE__TYPE__EVICTION, ndEa, member, memberNameAdded);
-          memberNameAdded =
-              writeAttributesToTable(table, CliStrings.DESCRIBE_REGION__ATTRIBUTE__TYPE__PARTITION,
-                  ndPa, member, memberNameAdded);
+      if (!ndRa.isEmpty() || !ndEa.isEmpty() || !ndPa.isEmpty()
+          || (fpaList != null && !fpaList.isEmpty())) {
+        setHeader = true;
+        boolean memberNameAdded;
+        memberNameAdded = writeAttributesToTable(table,
+            CliStrings.DESCRIBE_REGION__ATTRIBUTE__TYPE__REGION, ndRa, member, false);
+        memberNameAdded = writeAttributesToTable(table,
+            CliStrings.DESCRIBE_REGION__ATTRIBUTE__TYPE__EVICTION, ndEa, member, memberNameAdded);
+        memberNameAdded = writeAttributesToTable(table,
+            CliStrings.DESCRIBE_REGION__ATTRIBUTE__TYPE__PARTITION, ndPa, member, memberNameAdded);
 
-          writeFixedPartitionAttributesToTable(table, fpaList, member, memberNameAdded);
-        }
+        writeFixedPartitionAttributesToTable(table, fpaList, member, memberNameAdded);
       }
+    }
 
-      if (setHeader) {
-        table.setHeader(CliStrings.format(
-            CliStrings.DESCRIBE_REGION__NONDEFAULT__PERMEMBERATTRIBUTES__HEADER, memberType));
-      }
+    if (setHeader) {
+      table.setHeader(CliStrings
+          .format(CliStrings.DESCRIBE_REGION__NONDEFAULT__PERMEMBERATTRIBUTES__HEADER, memberType));
     }
 
-    result = ResultBuilder.buildResult(crd);
-    return result;
+    return ResultBuilder.buildResult(crd);
   }
 
   private void writeCommonAttributesToTable(TabularResultData table, String attributeType,
@@ -213,7 +196,7 @@ private void writeCommonAttributesToTable(TabularResultData table, String attrib
 
       for (String attributeName : attributes) {
         String attributeValue = attributesMap.get(attributeName);
-        String type, memName;
+        String type;
 
         if (!isTypeAdded) {
           type = attributeType;
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/GfshCommand.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/GfshCommand.java
index b251d64804..565a044d2e 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/GfshCommand.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/GfshCommand.java
@@ -118,7 +118,7 @@ default DistributedMember findMember(final String memberName) {
   }
 
   /**
-   * Get All members, exclusing locators
+   * Get All members, excluding locators
    */
   default Set<DistributedMember> getAllNormalMembers(InternalCache cache) {
     return CliUtil.getAllNormalMembers(cache);
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/RegionAttributesInfo.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/RegionAttributesInfo.java
index 18ad530ce2..faaa919c08 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/RegionAttributesInfo.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/RegionAttributesInfo.java
@@ -18,8 +18,10 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import org.apache.commons.lang.StringUtils;
 
@@ -40,11 +42,8 @@
 
 
 public class RegionAttributesInfo implements Serializable {
-  /**
-   *
-   */
-  private static final long serialVersionUID = 1L;
 
+  private static final long serialVersionUID = 336184564012988487L;
   private Scope scope = AbstractRegion.DEFAULT_SCOPE;
 
   private boolean cloningEnabled = false;
@@ -70,6 +69,8 @@
 
   private String compressorClassName = null;
 
+  private Set<String> asyncEventQueueIDs = new HashSet<>();
+  private Set<String> gatewaySenderIDs = new HashSet<>();
 
   private PartitionAttributesInfo partitionAttributesInfo = null;
   private EvictionAttributesInfo evictionAttributesInfo = null;
@@ -138,7 +139,8 @@ public RegionAttributesInfo(RegionAttributes<?, ?> ra) {
       regionIdleTimeoutAction = expAction.toString();
     }
 
-
+    asyncEventQueueIDs = ra.getAsyncEventQueueIds();
+    gatewaySenderIDs = ra.getGatewaySenderIds();
 
     // Collecting information about all the CacheListeners, CacheWriters, CacheLoaders
     CacheListener<?, ?>[] cacheListeners = ra.getCacheListeners();
@@ -170,15 +172,15 @@ public RegionAttributesInfo(RegionAttributes<?, ?> ra) {
     PartitionAttributes<?, ?> partitionAttributes = ra.getPartitionAttributes();
     EvictionAttributes evictionAttributes = ra.getEvictionAttributes();
 
-
-    if (partitionAttributes != null)
+    if (partitionAttributes != null) {
       partitionAttributesInfo = new PartitionAttributesInfo(partitionAttributes);
+    }
 
     if (evictionAttributes != null) {
       evictionAttributesInfo = new EvictionAttributesInfo(evictionAttributes);
 
     }
-    this.offHeap = ra.getOffHeap();
+    offHeap = ra.getOffHeap();
   }
 
 
@@ -258,6 +260,14 @@ public int getInitialCapacity() {
     return initialCapacity;
   }
 
+  public Set<String> getAsyncEventQueueIDs() {
+    return asyncEventQueueIDs;
+  }
+
+  public Set<String> getGatewaySenderIDs() {
+    return gatewaySenderIDs;
+  }
+
   public float getLoadFactor() {
     return loadFactor;
   }
@@ -305,7 +315,7 @@ public String getRegionTimeToLiveAction() {
   }
 
   public boolean getOffHeap() {
-    return this.offHeap;
+    return offHeap;
   }
 
   @Override
@@ -323,175 +333,166 @@ public int hashCode() {
    */
   public Map<String, String> getNonDefaultAttributes() {
 
-    if (nonDefaultAttributes == null) {
-      nonDefaultAttributes = new HashMap<String, String>();
-
-      if (cloningEnabled != RegionAttributesDefault.CLONING_ENABLED) {
-        nonDefaultAttributes.put(RegionAttributesNames.CLONING_ENABLED,
-            Boolean.toString(cloningEnabled));
-      }
-
-      if (!StringUtils.equals(RegionAttributesDefault.COMPRESSOR_CLASS_NAME, compressorClassName)) {
-        nonDefaultAttributes.put(RegionAttributesNames.COMPRESSOR, compressorClassName);
-      }
-
-      if (concurrencyChecksEnabled != RegionAttributesDefault.CONCURRENCY_CHECK_ENABLED) {
-        nonDefaultAttributes.put(RegionAttributesNames.CONCURRENCY_CHECK_ENABLED,
-            Boolean.toString(concurrencyChecksEnabled));
-      }
-
-
-      if (concurrencyLevel != RegionAttributesDefault.CONCURRENCY_LEVEL) {
-        nonDefaultAttributes.put(RegionAttributesNames.CONCURRENCY_LEVEL,
-            Integer.toString(concurrencyLevel));
-      }
-
-
-      if (!dataPolicy.equals(RegionAttributesDefault.DATA_POLICY)) {
-        nonDefaultAttributes.put(RegionAttributesNames.DATA_POLICY, dataPolicy.toString());
-      }
-
-
-      if (diskStoreName != null && !diskStoreName.equals(RegionAttributesDefault.DISK_STORE_NAME)) {
-        nonDefaultAttributes.put(RegionAttributesNames.DISK_STORE_NAME, diskStoreName);
-      }
-
-
-      if (enableAsyncConflation != RegionAttributesDefault.ENABLE_ASYNC_CONFLATION) {
-        nonDefaultAttributes.put(RegionAttributesNames.ENABLE_ASYNC_CONFLATION,
-            Boolean.toString(enableAsyncConflation));
-      }
-
-
-
-      if (enableSubscriptionConflation != RegionAttributesDefault.ENABLE_SUBSCRIPTION_CONFLATION) {
-        nonDefaultAttributes.put(RegionAttributesNames.ENABLE_SUBSCRIPTION_CONFLATION,
-            Boolean.toString(enableSubscriptionConflation));
-      }
-
-
-      if (entryIdleTimeout != RegionAttributesDefault.ENTRY_IDLE_TIMEOUT) {
-        nonDefaultAttributes.put(RegionAttributesNames.ENTRY_IDLE_TIMEOUT,
-            Integer.toString(entryIdleTimeout));
-      }
-
-
-      if (ignoreJTA != RegionAttributesDefault.IGNORE_JTA) {
-        nonDefaultAttributes.put(RegionAttributesNames.IGNORE_JTA, Boolean.toString(ignoreJTA));
-      }
-
+    if (nonDefaultAttributes != null) {
+      return nonDefaultAttributes;
+    }
 
-      if (indexMaintenanceSynchronous != RegionAttributesDefault.INDEX_MAINTENANCE_SYNCHRONOUS) {
-        nonDefaultAttributes.put(RegionAttributesNames.INDEX_MAINTENANCE_SYNCHRONOUS,
-            Boolean.toString(indexMaintenanceSynchronous));
-      }
+    nonDefaultAttributes = new HashMap<>();
 
+    if (cloningEnabled != RegionAttributesDefault.CLONING_ENABLED) {
+      nonDefaultAttributes.put(RegionAttributesNames.CLONING_ENABLED,
+          Boolean.toString(cloningEnabled));
+    }
 
-      if (initialCapacity != RegionAttributesDefault.INITIAL_CAPACITY) {
-        nonDefaultAttributes.put(RegionAttributesNames.INITIAL_CAPACITY,
-            Integer.toString(initialCapacity));
-      }
+    if (!StringUtils.equals(RegionAttributesDefault.COMPRESSOR_CLASS_NAME, compressorClassName)) {
+      nonDefaultAttributes.put(RegionAttributesNames.COMPRESSOR, compressorClassName);
+    }
 
+    if (concurrencyChecksEnabled != RegionAttributesDefault.CONCURRENCY_CHECK_ENABLED) {
+      nonDefaultAttributes.put(RegionAttributesNames.CONCURRENCY_CHECK_ENABLED,
+          Boolean.toString(concurrencyChecksEnabled));
+    }
 
-      if (loadFactor != RegionAttributesDefault.LOAD_FACTOR) {
-        nonDefaultAttributes.put(RegionAttributesNames.LOAD_FACTOR, Float.toString(loadFactor));
-      }
+    if (concurrencyLevel != RegionAttributesDefault.CONCURRENCY_LEVEL) {
+      nonDefaultAttributes.put(RegionAttributesNames.CONCURRENCY_LEVEL,
+          Integer.toString(concurrencyLevel));
+    }
 
+    if (!dataPolicy.equals(RegionAttributesDefault.DATA_POLICY)) {
+      nonDefaultAttributes.put(RegionAttributesNames.DATA_POLICY, dataPolicy.toString());
+    }
 
-      if (multicastEnabled != RegionAttributesDefault.MULTICAST_ENABLED) {
-        nonDefaultAttributes.put(RegionAttributesNames.MULTICAST_ENABLED,
-            Boolean.toString(multicastEnabled));
-      }
+    if (diskStoreName != null && !diskStoreName.equals(RegionAttributesDefault.DISK_STORE_NAME)) {
+      nonDefaultAttributes.put(RegionAttributesNames.DISK_STORE_NAME, diskStoreName);
+    }
 
+    if (enableAsyncConflation != RegionAttributesDefault.ENABLE_ASYNC_CONFLATION) {
+      nonDefaultAttributes.put(RegionAttributesNames.ENABLE_ASYNC_CONFLATION,
+          Boolean.toString(enableAsyncConflation));
+    }
 
-      if (poolName != null && !poolName.equals(RegionAttributesDefault.POOL_NAME)) {
-        nonDefaultAttributes.put(RegionAttributesNames.POOL_NAME, poolName);
-      }
+    if (enableSubscriptionConflation != RegionAttributesDefault.ENABLE_SUBSCRIPTION_CONFLATION) {
+      nonDefaultAttributes.put(RegionAttributesNames.ENABLE_SUBSCRIPTION_CONFLATION,
+          Boolean.toString(enableSubscriptionConflation));
+    }
 
+    if (entryIdleTimeout != RegionAttributesDefault.ENTRY_IDLE_TIMEOUT) {
+      nonDefaultAttributes.put(RegionAttributesNames.ENTRY_IDLE_TIMEOUT,
+          Integer.toString(entryIdleTimeout));
+    }
 
-      if (!scope.equals(RegionAttributesDefault.SCOPE)) {
-        nonDefaultAttributes.put(RegionAttributesNames.SCOPE, scope.toString());
-      }
+    if (ignoreJTA != RegionAttributesDefault.IGNORE_JTA) {
+      nonDefaultAttributes.put(RegionAttributesNames.IGNORE_JTA, Boolean.toString(ignoreJTA));
+    }
 
+    if (indexMaintenanceSynchronous != RegionAttributesDefault.INDEX_MAINTENANCE_SYNCHRONOUS) {
+      nonDefaultAttributes.put(RegionAttributesNames.INDEX_MAINTENANCE_SYNCHRONOUS,
+          Boolean.toString(indexMaintenanceSynchronous));
+    }
 
-      if (statisticsEnabled != RegionAttributesDefault.STATISTICS_ENABLED) {
-        nonDefaultAttributes.put(RegionAttributesNames.STATISTICS_ENABLED,
-            Boolean.toString(statisticsEnabled));
-      }
+    if (initialCapacity != RegionAttributesDefault.INITIAL_CAPACITY) {
+      nonDefaultAttributes.put(RegionAttributesNames.INITIAL_CAPACITY,
+          Integer.toString(initialCapacity));
+    }
 
+    if (loadFactor != RegionAttributesDefault.LOAD_FACTOR) {
+      nonDefaultAttributes.put(RegionAttributesNames.LOAD_FACTOR, Float.toString(loadFactor));
+    }
 
+    if (multicastEnabled != RegionAttributesDefault.MULTICAST_ENABLED) {
+      nonDefaultAttributes.put(RegionAttributesNames.MULTICAST_ENABLED,
+          Boolean.toString(multicastEnabled));
+    }
 
-      if (isLockGrantor != RegionAttributesDefault.IS_LOCK_GRANTOR) {
-        nonDefaultAttributes.put(RegionAttributesNames.IS_LOCK_GRANTOR,
-            Boolean.toString(isLockGrantor));
-      }
+    if (poolName != null && !poolName.equals(RegionAttributesDefault.POOL_NAME)) {
+      nonDefaultAttributes.put(RegionAttributesNames.POOL_NAME, poolName);
+    }
 
+    if (!scope.equals(RegionAttributesDefault.SCOPE)) {
+      nonDefaultAttributes.put(RegionAttributesNames.SCOPE, scope.toString());
+    }
 
-      if (entryIdleTimeout != RegionAttributesDefault.ENTRY_IDLE_TIMEOUT) {
-        nonDefaultAttributes.put(RegionAttributesNames.ENTRY_IDLE_TIMEOUT,
-            Integer.toString(entryIdleTimeout));
-      }
+    if (statisticsEnabled != RegionAttributesDefault.STATISTICS_ENABLED) {
+      nonDefaultAttributes.put(RegionAttributesNames.STATISTICS_ENABLED,
+          Boolean.toString(statisticsEnabled));
+    }
 
-      if (entryIdleTimeoutAction != null
-          && !entryIdleTimeoutAction.equals(RegionAttributesDefault.ENTRY_IDLE_TIMEOUT_ACTION)) {
-        nonDefaultAttributes.put(RegionAttributesNames.ENTRY_IDLE_TIMEOUT_ACTION,
-            entryIdleTimeoutAction);
-      }
+    if (isLockGrantor != RegionAttributesDefault.IS_LOCK_GRANTOR) {
+      nonDefaultAttributes.put(RegionAttributesNames.IS_LOCK_GRANTOR,
+          Boolean.toString(isLockGrantor));
+    }
 
+    if (entryIdleTimeout != RegionAttributesDefault.ENTRY_IDLE_TIMEOUT) {
+      nonDefaultAttributes.put(RegionAttributesNames.ENTRY_IDLE_TIMEOUT,
+          Integer.toString(entryIdleTimeout));
+    }
 
-      if (entryTimeToLive != RegionAttributesDefault.ENTRY_TIME_TO_LIVE) {
-        nonDefaultAttributes.put(RegionAttributesNames.ENTRY_TIME_TO_LIVE,
-            Integer.toString(entryTimeToLive));
-      }
+    if (entryIdleTimeoutAction != null
+        && !entryIdleTimeoutAction.equals(RegionAttributesDefault.ENTRY_IDLE_TIMEOUT_ACTION)) {
+      nonDefaultAttributes.put(RegionAttributesNames.ENTRY_IDLE_TIMEOUT_ACTION,
+          entryIdleTimeoutAction);
+    }
 
+    if (entryTimeToLive != RegionAttributesDefault.ENTRY_TIME_TO_LIVE) {
+      nonDefaultAttributes.put(RegionAttributesNames.ENTRY_TIME_TO_LIVE,
+          Integer.toString(entryTimeToLive));
+    }
 
-      if (entryTimeToLiveAction != null
-          && !entryTimeToLiveAction.equals(RegionAttributesDefault.ENTRY_TIME_TO_LIVE_ACTION)) {
-        nonDefaultAttributes.put(RegionAttributesNames.ENTRY_TIME_TO_LIVE_ACTION,
-            entryTimeToLiveAction);
-      }
+    if (entryTimeToLiveAction != null
+        && !entryTimeToLiveAction.equals(RegionAttributesDefault.ENTRY_TIME_TO_LIVE_ACTION)) {
+      nonDefaultAttributes.put(RegionAttributesNames.ENTRY_TIME_TO_LIVE_ACTION,
+          entryTimeToLiveAction);
+    }
 
+    if (regionIdleTimeout != RegionAttributesDefault.REGION_IDLE_TIMEOUT) {
+      nonDefaultAttributes.put(RegionAttributesNames.REGION_IDLE_TIMEOUT,
+          Integer.toString(regionIdleTimeout));
+    }
 
-      if (regionIdleTimeout != RegionAttributesDefault.REGION_IDLE_TIMEOUT) {
-        nonDefaultAttributes.put(RegionAttributesNames.REGION_IDLE_TIMEOUT,
-            Integer.toString(regionIdleTimeout));
-      }
+    if (regionIdleTimeoutAction != null
+        && !regionIdleTimeoutAction.equals(RegionAttributesDefault.REGION_IDLE_TIMEOUT_ACTION)) {
+      nonDefaultAttributes.put(RegionAttributesNames.REGION_IDLE_TIMEOUT_ACTION,
+          regionIdleTimeoutAction);
+    }
 
-      if (regionIdleTimeoutAction != null
-          && !regionIdleTimeoutAction.equals(RegionAttributesDefault.REGION_IDLE_TIMEOUT_ACTION)) {
-        nonDefaultAttributes.put(RegionAttributesNames.REGION_IDLE_TIMEOUT_ACTION,
-            regionIdleTimeoutAction);
-      }
+    if (regionTimeToLive != RegionAttributesDefault.REGION_TIME_TO_LIVE) {
+      nonDefaultAttributes.put(RegionAttributesNames.REGION_TIME_TO_LIVE,
+          Integer.toString(regionTimeToLive));
+    }
 
-      if (regionTimeToLive != RegionAttributesDefault.REGION_TIME_TO_LIVE) {
-        nonDefaultAttributes.put(RegionAttributesNames.REGION_TIME_TO_LIVE,
-            Integer.toString(regionTimeToLive));
-      }
+    if (regionTimeToLiveAction != null
+        && !regionTimeToLiveAction.equals(RegionAttributesDefault.REGION_TIME_TO_LIVE_ACTION)) {
+      nonDefaultAttributes.put(RegionAttributesNames.REGION_TIME_TO_LIVE_ACTION,
+          regionTimeToLiveAction);
+    }
 
+    if (cacheListenerClassNames != null && !cacheListenerClassNames.isEmpty()) {
+      nonDefaultAttributes.put(RegionAttributesNames.CACHE_LISTENERS,
+          CliUtil.convertStringListToString(cacheListenerClassNames, ','));
+    }
 
-      if (regionTimeToLiveAction != null
-          && !regionTimeToLiveAction.equals(RegionAttributesDefault.REGION_TIME_TO_LIVE_ACTION)) {
-        nonDefaultAttributes.put(RegionAttributesNames.REGION_TIME_TO_LIVE_ACTION,
-            regionTimeToLiveAction);
-      }
+    if (cacheLoaderClassName != null && !cacheLoaderClassName.isEmpty()) {
+      nonDefaultAttributes.put(RegionAttributesNames.CACHE_LOADER, cacheLoaderClassName);
+    }
 
-      if (cacheListenerClassNames != null && !cacheListenerClassNames.isEmpty()) {
-        nonDefaultAttributes.put(RegionAttributesNames.CACHE_LISTENERS,
-            CliUtil.convertStringListToString(cacheListenerClassNames, ','));
-      }
+    if (cacheWriterClassName != null && !cacheWriterClassName.isEmpty()) {
+      nonDefaultAttributes.put(RegionAttributesNames.CACHE_WRITER, cacheWriterClassName);
+    }
 
-      if (cacheLoaderClassName != null && !cacheLoaderClassName.isEmpty()) {
-        nonDefaultAttributes.put(RegionAttributesNames.CACHE_LOADER, cacheLoaderClassName);
-      }
+    if (offHeap != RegionAttributesDefault.OFF_HEAP) {
+      nonDefaultAttributes.put(RegionAttributesNames.OFF_HEAP, Boolean.toString(offHeap));
+    }
 
-      if (cacheWriterClassName != null && !cacheWriterClassName.isEmpty()) {
-        nonDefaultAttributes.put(RegionAttributesNames.CACHE_WRITER, cacheWriterClassName);
-      }
+    if (!asyncEventQueueIDs.isEmpty()) {
+      nonDefaultAttributes.put(RegionAttributesNames.ASYNC_EVENT_QUEUE_ID,
+          String.join(",", asyncEventQueueIDs));
+    }
 
-      if (this.offHeap != RegionAttributesDefault.OFF_HEAP) {
-        nonDefaultAttributes.put(RegionAttributesNames.OFF_HEAP, Boolean.toString(this.offHeap));
-      }
+    if (!gatewaySenderIDs.isEmpty()) {
+      nonDefaultAttributes.put(RegionAttributesNames.GATEWAY_SENDER_ID,
+          String.join(",", gatewaySenderIDs));
     }
-    return this.nonDefaultAttributes;
+
+    return nonDefaultAttributes;
   }
 }
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/RegionDescription.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/RegionDescription.java
index d0d564091e..2f25afc02d 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/RegionDescription.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/RegionDescription.java
@@ -17,47 +17,37 @@
 import java.io.Serializable;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
 import org.apache.geode.cache.DataPolicy;
-import org.apache.geode.cache.Region;
-import org.apache.geode.cache.RegionShortcut;
 import org.apache.geode.cache.Scope;
 
 /***
  * Data class which contains description of a region and provides the aggregated view of the region
  * Used by describe region command
- *
- *
  */
 public class RegionDescription implements Serializable {
 
-  private static final long serialVersionUID = 1L;
+  private static final long serialVersionUID = 6461449275798378332L;
   private String name;
   private boolean isPartition;
   private boolean isPersistent;
   private boolean isReplicate;
-  private boolean haslocalDataStorage;
   private boolean isLocal = false;
-  private boolean isReplicatedProxy = false;;
   private boolean isAccessor = false;
 
-
+  // COPY
   // Common Non Default Attributes
-  private Map<String, String> cndRegionAttributes;
-  private Map<String, String> cndPartitionAttributes;
-  private Map<String, String> cndEvictionAttributes;
+  private Map<String, String> cndRegionAttributes = new HashMap<>();
+  private Map<String, String> cndPartitionAttributes = new HashMap<>();
+  private Map<String, String> cndEvictionAttributes = new HashMap<>();
 
   private Map<String, RegionDescriptionPerMember> regionDescPerMemberMap = null;
   private Scope scope;
   private DataPolicy dataPolicy;
 
-  public RegionDescription() {
-
-  }
+  public RegionDescription() {}
 
   public DataPolicy getDataPolicy() {
     return this.dataPolicy;
@@ -70,85 +60,61 @@ public Scope getScope() {
   /**
    * Adds the RegionDescription per member to the aggregated view
    *
-   * @param regionDescPerMember
-   *
+   * @return boolean describing if description was successfully added
    */
   public boolean add(RegionDescriptionPerMember regionDescPerMember) {
     boolean isAdded = false;
 
     if (regionDescPerMemberMap == null) {
-      regionDescPerMemberMap = new HashMap<String, RegionDescriptionPerMember>();
+      regionDescPerMemberMap = new HashMap<>();
       regionDescPerMemberMap.put(regionDescPerMember.getHostingMember(), regionDescPerMember);
-      this.scope = regionDescPerMember.getScope();
-      this.dataPolicy = regionDescPerMember.getDataPolicy();
-      this.name = regionDescPerMember.getName();
-      isPartition = this.dataPolicy.withPartitioning();
-      isPersistent = this.dataPolicy.withPersistence();
-      isReplicate = this.dataPolicy.withReplication();
-      haslocalDataStorage = this.dataPolicy.withStorage();
-      isLocal = this.scope.isLocal();
+      scope = regionDescPerMember.getScope();
+      dataPolicy = regionDescPerMember.getDataPolicy();
+      name = regionDescPerMember.getName();
+      isPartition = dataPolicy.withPartitioning();
+      isPersistent = dataPolicy.withPersistence();
+      isReplicate = dataPolicy.withReplication();
+      isLocal = scope.isLocal();
       isAccessor = regionDescPerMember.isAccessor();
-      // COPY
-      this.cndRegionAttributes = new HashMap<String, String>();
-      this.cndRegionAttributes.putAll(regionDescPerMember.getNonDefaultRegionAttributes());
-
-      this.cndPartitionAttributes = new HashMap<String, String>();
-      this.cndPartitionAttributes.putAll(regionDescPerMember.getNonDefaultPartitionAttributes());
+      cndRegionAttributes.putAll(regionDescPerMember.getNonDefaultRegionAttributes());
+      cndPartitionAttributes.putAll(regionDescPerMember.getNonDefaultPartitionAttributes());
+      cndEvictionAttributes.putAll(regionDescPerMember.getNonDefaultEvictionAttributes());
 
-      this.cndEvictionAttributes = new HashMap<String, String>();
-      this.cndEvictionAttributes.putAll(regionDescPerMember.getNonDefaultEvictionAttributes());
-
-      if (this.dataPolicy.equals(DataPolicy.EMPTY) && this.scope.equals(Scope.DISTRIBUTED_ACK)) {
-        isReplicatedProxy = true;
-      }
-
-      // Don't have to show the scope for PR's
+      isAdded = true;
+    } else if (scope.equals(regionDescPerMember.getScope())
+        && name.equals(regionDescPerMember.getName())
+        && dataPolicy.equals(regionDescPerMember.getDataPolicy())
+        && isAccessor == regionDescPerMember.isAccessor()) {
 
+      regionDescPerMemberMap.put(regionDescPerMember.getHostingMember(), regionDescPerMember);
+      findCommon(cndRegionAttributes, regionDescPerMember.getNonDefaultRegionAttributes());
+      findCommon(cndEvictionAttributes, regionDescPerMember.getNonDefaultEvictionAttributes());
+      findCommon(cndPartitionAttributes, regionDescPerMember.getNonDefaultPartitionAttributes());
 
       isAdded = true;
-    } else {
-      if (this.scope.equals(regionDescPerMember.getScope())
-          && this.name.equals(regionDescPerMember.getName())
-          && this.dataPolicy.equals(regionDescPerMember.getDataPolicy())
-          && this.isAccessor == regionDescPerMember.isAccessor()) {
-
-        regionDescPerMemberMap.put(regionDescPerMember.getHostingMember(), regionDescPerMember);
-        findCommon(cndRegionAttributes, regionDescPerMember.getNonDefaultRegionAttributes());
-        findCommon(cndEvictionAttributes, regionDescPerMember.getNonDefaultEvictionAttributes());
-        findCommon(cndPartitionAttributes, regionDescPerMember.getNonDefaultPartitionAttributes());
-
-        isAdded = true;
-      }
     }
     return isAdded;
   }
 
-  private void findCommon(Map<String, String> commonNdMap, Map<String, String> incomingNdMap) {
-    // First get the intersection of the both maps
-
-    Set<String> commonNdKeySet = commonNdMap.keySet();
-    Set<String> incomingNdKeySet = incomingNdMap.keySet();
-
-    commonNdKeySet.retainAll(incomingNdKeySet);
-
-    // Now compare the values
-    // Take a copy of the set to avoid a CME
-    Iterator<String> commonKeysIter = (new HashSet<String>(commonNdKeySet)).iterator();
-
-    while (commonKeysIter.hasNext()) {
-      String attribute = commonKeysIter.next();
-      String commonNdValue = commonNdMap.get(attribute);
-      String incomingNdValue = incomingNdMap.get(attribute);
-
-      if (commonNdValue != null) {
-        if (!commonNdValue.equals(incomingNdValue)) {
-          // Remove it from the commonNdMa
-          commonNdMap.remove(attribute);
-        }
-      } else {
-        if (incomingNdValue != null) {
-          commonNdMap.remove(attribute);
-        }
+  /**
+   * Removes any key-value pairs from @commonValuesMap that do not agree with the respective
+   * key-value pairs of @additionalValuesMap
+   *
+   * @param commonValuesMap Common values map, whose key set will be reduced.
+   * @param additionalValuesMap Incoming values map, against which @commonValuesMap.
+   */
+  static void findCommon(Map<String, String> commonValuesMap,
+      Map<String, String> additionalValuesMap) {
+
+    Set<String> sharedKeySet = commonValuesMap.keySet();
+    sharedKeySet.retainAll(additionalValuesMap.keySet());
+
+    for (String sharedKey : new HashSet<>(sharedKeySet)) {
+      String commonNdValue = commonValuesMap.get(sharedKey);
+      String incomingNdValue = additionalValuesMap.get(sharedKey);
+      if (commonNdValue != null && !commonNdValue.equals(incomingNdValue)
+          || commonNdValue == null && incomingNdValue != null) {
+        commonValuesMap.remove(sharedKey);
       }
     }
   }
@@ -190,25 +156,16 @@ public boolean isReplicate() {
     return this.isReplicate;
   }
 
-  public boolean hasLocalStorage() {
-    return this.haslocalDataStorage;
-  }
-
   public boolean isLocal() {
     return this.isLocal;
   }
 
-  public boolean isReplicatedProxy() {
-    return this.isReplicatedProxy;
-  }
-
   public boolean isAccessor() {
     return this.isAccessor;
   }
 
-
   /***
-   * Get
+   * Gets the common, non-default region attributes
    *
    * @return Map containing attribute name and its associated value
    */
@@ -217,7 +174,7 @@ public boolean isAccessor() {
   }
 
   /***
-   * Gets the common non-default Eviction Attributes
+   * Gets the common, non-default eviction attributes
    *
    * @return Map containing attribute name and its associated value
    */
@@ -226,7 +183,7 @@ public boolean isAccessor() {
   }
 
   /***
-   * Gets the common non-default PartitionAttributes
+   * Gets the common, non-default partition attributes
    *
    * @return Map containing attribute name and its associated value
    */
@@ -238,11 +195,13 @@ public boolean isAccessor() {
     return this.regionDescPerMemberMap;
   }
 
-
   public String toString() {
     StringBuilder sb = new StringBuilder();
 
     return sb.toString();
   }
 
+  public boolean isEmpty() {
+    return regionDescPerMemberMap == null || regionDescPerMemberMap.isEmpty();
+  }
 }
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/GetRegionDescriptionFunction.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/GetRegionDescriptionFunction.java
index afaeac507c..d13446caa8 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/GetRegionDescriptionFunction.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/GetRegionDescriptionFunction.java
@@ -16,14 +16,13 @@
 
 
 import org.apache.geode.cache.Cache;
-import org.apache.geode.cache.CacheClosedException;
 import org.apache.geode.cache.Region;
-import org.apache.geode.cache.execute.FunctionAdapter;
+import org.apache.geode.cache.execute.Function;
 import org.apache.geode.cache.execute.FunctionContext;
 import org.apache.geode.internal.InternalEntity;
 import org.apache.geode.management.internal.cli.domain.RegionDescriptionPerMember;
 
-public class GetRegionDescriptionFunction extends FunctionAdapter implements InternalEntity {
+public class GetRegionDescriptionFunction implements Function, InternalEntity {
 
 
   private static final long serialVersionUID = 1L;
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/CommandResult.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/CommandResult.java
index 13153ecaeb..b7aac061da 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/CommandResult.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/CommandResult.java
@@ -618,15 +618,28 @@ public GfJsonObject getTableContent() {
     return getTableContent(0, 0);
   }
 
-  public GfJsonObject getTableContent(int sectionIdx, int tableIdx) {
+  /**
+   * Most frequently, only two index values are required: a section index followed by a table index.
+   * Some commands, such as 'describe region', may return command results with subsections, however.
+   * Include these in order, e.g., getTableContent(sectionIndex, subsectionIndex, tableIndex);
+   */
+  public GfJsonObject getTableContent(int... sectionAndTableIDs) {
     GfJsonObject topLevelContent = getContent();
-    GfJsonObject sectionObject = topLevelContent.getJSONObject("__sections__-" + sectionIdx);
-    // This means we're just dealing with a regular ResultData object
-    if (sectionObject == null) {
-      return topLevelContent;
+    // Most common is receiving exactly one section index and one table index.
+    // Some results, however, will have subsections before the table listings.
+    assert (sectionAndTableIDs.length >= 2);
+
+    GfJsonObject sectionObject = topLevelContent;
+    for (int i = 0; i < sectionAndTableIDs.length - 1; i++) {
+      int idx = sectionAndTableIDs[i];
+      sectionObject = sectionObject.getJSONObject("__sections__-" + idx);
+      if (sectionObject == null) {
+        return topLevelContent;
+      }
     }
 
-    GfJsonObject tableContent = sectionObject.getJSONObject("__tables__-" + tableIdx);
+    int tableId = sectionAndTableIDs[sectionAndTableIDs.length - 1];
+    GfJsonObject tableContent = sectionObject.getJSONObject("__tables__-" + tableId);
     if (tableContent == null) {
       return topLevelContent;
     }
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/util/RegionAttributesDefault.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/util/RegionAttributesDefault.java
index 1cbb9e2982..34da600d62 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/util/RegionAttributesDefault.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/util/RegionAttributesDefault.java
@@ -14,17 +14,12 @@
  */
 package org.apache.geode.management.internal.cli.util;
 
-import java.util.List;
-
 import org.apache.geode.cache.DataPolicy;
 import org.apache.geode.cache.EvictionAction;
-import org.apache.geode.cache.EvictionAlgorithm;
 import org.apache.geode.cache.ExpirationAction;
 import org.apache.geode.cache.PartitionAttributesFactory;
 import org.apache.geode.cache.Scope;
 import org.apache.geode.internal.cache.AbstractRegion;
-import org.apache.geode.management.internal.cli.domain.EvictionAttributesInfo;
-import org.apache.geode.management.internal.cli.domain.PartitionAttributesInfo;
 
 /***
  * Contains the default values for the region attributes
@@ -36,26 +31,19 @@
   public static final boolean CLONING_ENABLED = false;
   public static final boolean CONCURRENCY_CHECK_ENABLED = true;
   public static final boolean ENABLE_ASYNC_CONFLATION = false;
-  public static final boolean ENABLE_GATEWAY = false;
   public static final boolean ENABLE_SUBSCRIPTION_CONFLATION = false;
   public static final boolean IGNORE_JTA = false;
   public static final boolean INDEX_MAINTENANCE_SYNCHRONOUS = true;
   public static final boolean MULTICAST_ENABLED = false;
   public static final int CONCURRENCY_LEVEL = 16;
   public static final String DISK_STORE_NAME = "";
-  public static final String GATEWAY_HUB_ID = "";
   public static final int INITIAL_CAPACITY = 16;
   public static final float LOAD_FACTOR = 0.75f;
   public static final String POOL_NAME = "";
   public static final boolean STATISTICS_ENABLED = false;
   public static final boolean IS_LOCK_GRANTOR = false;
-  public static final String cacheListenerClassNames = "";
-  public static final String cacheLoaderClassName = "";
-  public static final String cacheWriterClassName = "";
   public static final String COMPRESSOR_CLASS_NAME = null;
 
-  public static final PartitionAttributesInfo partitionAttributesInfo = null;
-  public static final EvictionAttributesInfo evictionAttributesInfo = null;
   public static final int ENTRY_TIME_TO_LIVE = 0;
   public static final int REGION_TIME_TO_LIVE = 0;
   public static final int ENTRY_IDLE_TIMEOUT = 0;
@@ -68,14 +56,12 @@
   // PA
   // Partition attributes
   public static final int REDUNDANT_COPIES = 0;
-  public static final long TOTAL_MAX_MEMORY = PartitionAttributesFactory.GLOBAL_MAX_MEMORY_DEFAULT;
   public static final int TOTAL_NUM_BUCKETS = PartitionAttributesFactory.GLOBAL_MAX_BUCKETS_DEFAULT;
   public static final String COLOCATED_WITH = "";
   public static final long RECOVERY_DELAY = PartitionAttributesFactory.RECOVERY_DELAY_DEFAULT;
   public static final long STARTUP_RECOVERY_DELAY =
       PartitionAttributesFactory.STARTUP_RECOVERY_DELAY_DEFAULT;
   public static final String PARTITION_RESOLVER = "";
-  public static final List<String> PARTITION_LISTENERS = null;
 
 
   // EVICTION ATTRIBUTES
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/util/RegionAttributesNames.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/util/RegionAttributesNames.java
index d5d89b6a15..341a126550 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/util/RegionAttributesNames.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/util/RegionAttributesNames.java
@@ -43,6 +43,8 @@
   public static final String POOL_NAME = "pool-name";
   public static final String COMPRESSOR = "compressor";
   public static final String OFF_HEAP = "off-heap";
+  public static final String ASYNC_EVENT_QUEUE_ID = "async-event-queue-id";
+  public static final String GATEWAY_SENDER_ID = "gateway-sender-id";
 
   // Partition attributes
   public static final String LOCAL_MAX_MEMORY = "local-max-memory";
diff --git a/geode-core/src/main/resources/org/apache/geode/internal/sanctioned-geode-core-serializables.txt b/geode-core/src/main/resources/org/apache/geode/internal/sanctioned-geode-core-serializables.txt
index e7cd276582..971db79b5b 100644
--- a/geode-core/src/main/resources/org/apache/geode/internal/sanctioned-geode-core-serializables.txt
+++ b/geode-core/src/main/resources/org/apache/geode/internal/sanctioned-geode-core-serializables.txt
@@ -500,8 +500,8 @@ org/apache/geode/management/internal/cli/domain/MemberConfigurationInfo,false,ca
 org/apache/geode/management/internal/cli/domain/MemberInformation,true,1,cacheServerList:java/util/List,cacheXmlFilePath:java/lang/String,clientCount:int,cpuUsage:double,groups:java/lang/String,heapUsage:java/lang/String,host:java/lang/String,hostedRegions:java/util/Set,id:java/lang/String,initHeapSize:java/lang/String,isServer:boolean,locatorBindAddress:java/lang/String,locatorPort:int,locators:java/lang/String,logFilePath:java/lang/String,maxHeapSize:java/lang/String,name:java/lang/String,offHeapMemorySize:java/lang/String,processId:java/lang/String,serverBindAddress:java/lang/String,statArchiveFilePath:java/lang/String,workingDirPath:java/lang/String
 org/apache/geode/management/internal/cli/domain/MemberResult,true,1,errorMessage:java/lang/String,exceptionMessage:java/lang/String,isSuccessful:boolean,memberNameOrId:java/lang/String,opPossible:boolean,successMessage:java/lang/String
 org/apache/geode/management/internal/cli/domain/PartitionAttributesInfo,true,1,colocatedWith:java/lang/String,fpaInfoList:java/util/List,localMaxMemory:int,nonDefaultAttributes:java/util/Map,partitionResolverName:java/lang/String,recoveryDelay:long,redundantCopies:int,startupRecoveryDelay:long,totalNumBuckets:int
-org/apache/geode/management/internal/cli/domain/RegionAttributesInfo,true,1,cacheListenerClassNames:java/util/List,cacheLoaderClassName:java/lang/String,cacheWriterClassName:java/lang/String,cloningEnabled:boolean,compressorClassName:java/lang/String,concurrencyChecksEnabled:boolean,concurrencyLevel:int,dataPolicy:org/apache/geode/cache/DataPolicy,diskStoreName:java/lang/String,enableAsyncConflation:boolean,enableSubscriptionConflation:boolean,entryIdleTimeout:int,entryIdleTimeoutAction:java/lang/String,entryTimeToLive:int,entryTimeToLiveAction:java/lang/String,evictionAttributesInfo:org/apache/geode/management/internal/cli/domain/EvictionAttributesInfo,ignoreJTA:boolean,indexMaintenanceSynchronous:boolean,initialCapacity:int,isLockGrantor:boolean,loadFactor:float,multicastEnabled:boolean,nonDefaultAttributes:java/util/Map,offHeap:boolean,partitionAttributesInfo:org/apache/geode/management/internal/cli/domain/PartitionAttributesInfo,poolName:java/lang/String,regionIdleTimeout:int,regionIdleTimeoutAction:java/lang/String,regionTimeToLive:int,regionTimeToLiveAction:java/lang/String,scope:org/apache/geode/cache/Scope,statisticsEnabled:boolean
-org/apache/geode/management/internal/cli/domain/RegionDescription,true,1,cndEvictionAttributes:java/util/Map,cndPartitionAttributes:java/util/Map,cndRegionAttributes:java/util/Map,dataPolicy:org/apache/geode/cache/DataPolicy,haslocalDataStorage:boolean,isAccessor:boolean,isLocal:boolean,isPartition:boolean,isPersistent:boolean,isReplicate:boolean,isReplicatedProxy:boolean,name:java/lang/String,regionDescPerMemberMap:java/util/Map,scope:org/apache/geode/cache/Scope
+org/apache/geode/management/internal/cli/domain/RegionAttributesInfo,true,336184564012988487,asyncEventQueueIDs:java/util/Set,cacheListenerClassNames:java/util/List,cacheLoaderClassName:java/lang/String,cacheWriterClassName:java/lang/String,cloningEnabled:boolean,compressorClassName:java/lang/String,concurrencyChecksEnabled:boolean,concurrencyLevel:int,dataPolicy:org/apache/geode/cache/DataPolicy,diskStoreName:java/lang/String,enableAsyncConflation:boolean,enableSubscriptionConflation:boolean,entryIdleTimeout:int,entryIdleTimeoutAction:java/lang/String,entryTimeToLive:int,entryTimeToLiveAction:java/lang/String,evictionAttributesInfo:org/apache/geode/management/internal/cli/domain/EvictionAttributesInfo,gatewaySenderIDs:java/util/Set,ignoreJTA:boolean,indexMaintenanceSynchronous:boolean,initialCapacity:int,isLockGrantor:boolean,loadFactor:float,multicastEnabled:boolean,nonDefaultAttributes:java/util/Map,offHeap:boolean,partitionAttributesInfo:org/apache/geode/management/internal/cli/domain/PartitionAttributesInfo,poolName:java/lang/String,regionIdleTimeout:int,regionIdleTimeoutAction:java/lang/String,regionTimeToLive:int,regionTimeToLiveAction:java/lang/String,scope:org/apache/geode/cache/Scope,statisticsEnabled:boolean
+org/apache/geode/management/internal/cli/domain/RegionDescription,true,6461449275798378332,cndEvictionAttributes:java/util/Map,cndPartitionAttributes:java/util/Map,cndRegionAttributes:java/util/Map,dataPolicy:org/apache/geode/cache/DataPolicy,isAccessor:boolean,isLocal:boolean,isPartition:boolean,isPersistent:boolean,isReplicate:boolean,name:java/lang/String,regionDescPerMemberMap:java/util/Map,scope:org/apache/geode/cache/Scope
 org/apache/geode/management/internal/cli/domain/RegionDescriptionPerMember,true,1,hostingMember:java/lang/String,isAccessor:boolean,name:java/lang/String,regionAttributesInfo:org/apache/geode/management/internal/cli/domain/RegionAttributesInfo,size:int
 org/apache/geode/management/internal/cli/domain/RegionInformation,true,1,dataPolicy:org/apache/geode/cache/DataPolicy,isRoot:boolean,name:java/lang/String,parentRegion:java/lang/String,path:java/lang/String,scope:org/apache/geode/cache/Scope,subRegionInformationSet:java/util/Set
 org/apache/geode/management/internal/cli/domain/StackTracesPerMember,true,1,memberNameOrId:java/lang/String,stackTraces:byte[]
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DescribeRegionDUnitTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DescribeRegionDUnitTest.java
index 8e223394cd..e4ddd3afad 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DescribeRegionDUnitTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DescribeRegionDUnitTest.java
@@ -14,23 +14,10 @@
  */
 package org.apache.geode.management.internal.cli.commands;
 
-import static org.apache.geode.distributed.ConfigurationProperties.ENABLE_TIME_STATISTICS;
-import static org.apache.geode.distributed.ConfigurationProperties.GROUPS;
-import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS;
-import static org.apache.geode.distributed.ConfigurationProperties.LOG_LEVEL;
-import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
-import static org.apache.geode.distributed.ConfigurationProperties.NAME;
-import static org.apache.geode.distributed.ConfigurationProperties.STATISTIC_SAMPLING_ENABLED;
 import static org.apache.geode.management.internal.cli.i18n.CliStrings.DESCRIBE_REGION;
 import static org.apache.geode.management.internal.cli.i18n.CliStrings.DESCRIBE_REGION__NAME;
-import static org.apache.geode.management.internal.cli.i18n.CliStrings.GROUP;
-import static org.apache.geode.management.internal.cli.i18n.CliStrings.LIST_REGION;
-import static org.apache.geode.management.internal.cli.i18n.CliStrings.MEMBER;
 import static org.assertj.core.api.Assertions.assertThat;
 
-import java.io.Serializable;
-import java.util.Properties;
-
 import org.junit.BeforeClass;
 import org.junit.ClassRule;
 import org.junit.Test;
@@ -55,11 +42,10 @@
 import org.apache.geode.test.dunit.rules.LocatorServerStartupRule;
 import org.apache.geode.test.dunit.rules.MemberVM;
 import org.apache.geode.test.junit.categories.DistributedTest;
-import org.apache.geode.test.junit.categories.FlakyTest;
 import org.apache.geode.test.junit.rules.GfshCommandRule;
 
 @Category(DistributedTest.class)
-public class DescribeRegionDUnitTest implements Serializable {
+public class DescribeRegionDUnitTest {
   private static final String REGION1 = "region1";
   private static final String REGION2 = "region2";
   private static final String REGION3 = "region3";
@@ -67,14 +53,8 @@
   private static final String SUBREGION1B = "subregion1B";
   private static final String SUBREGION1C = "subregion1C";
   private static final String PR1 = "PR1";
-  private static final String LOCALREGIONONMANAGER = "LocalRegionOnManager";
-
-  private static final String LOCATOR_NAME = "Locator";
-  private static final String SERVER1_NAME = "Server-1";
-  private static final String SERVER2_NAME = "Server-2";
-  private static final String GROUP1_NAME = "G1";
-  private static final String GROUP2_NAME = "G2";
-  private static final String GROUP3_NAME = "G3";
+  private static final String LOCAL_REGION = "LocalRegion";
+
   private static final String PART1_NAME = "Par1";
   private static final String PART2_NAME = "Par2";
 
@@ -82,22 +62,16 @@
   public static LocatorServerStartupRule lsRule = new LocatorServerStartupRule();
 
   @ClassRule
-  public static GfshCommandRule gfshCommandRule = new GfshCommandRule();
+  public static GfshCommandRule gfsh = new GfshCommandRule();
 
   @BeforeClass
   public static void setupSystem() throws Exception {
-    final Properties locatorProps = createProperties(LOCATOR_NAME, GROUP3_NAME);
-    MemberVM locator = lsRule.startLocatorVM(0, locatorProps);
-
-    final Properties managerProps = createProperties(SERVER1_NAME, GROUP1_NAME);
-    managerProps.setProperty(LOCATORS, "localhost[" + locator.getPort() + "]");
-    MemberVM manager = lsRule.startServerVM(1, managerProps, locator.getPort());
-
-    final Properties serverProps = createProperties(SERVER2_NAME, GROUP2_NAME);
-    MemberVM server = lsRule.startServerVM(2, serverProps, locator.getPort());
+    MemberVM locator = lsRule.startLocatorVM(0);
+    MemberVM server1 = lsRule.startServerVM(1, "group1", locator.getPort());
+    MemberVM server2 = lsRule.startServerVM(2, "group2", locator.getPort());
 
-    manager.invoke(() -> {
-      final Cache cache = CacheFactory.getAnyInstance();
+    server1.invoke(() -> {
+      final Cache cache = LocatorServerStartupRule.getCache();
       RegionFactory<String, Integer> dataRegionFactory =
           cache.createRegionFactory(RegionShortcut.PARTITION);
       dataRegionFactory.setConcurrencyLevel(4);
@@ -114,11 +88,11 @@ public static void setupSystem() throws Exception {
       dataRegionFactory.setPartitionAttributes(pa);
 
       dataRegionFactory.create(PR1);
-      createLocalRegion(LOCALREGIONONMANAGER);
+      createLocalRegion(LOCAL_REGION);
     });
 
-    server.invoke(() -> {
-      final Cache cache = CacheFactory.getAnyInstance();
+    server2.invoke(() -> {
+      final Cache cache = LocatorServerStartupRule.getCache();
       RegionFactory<String, Integer> dataRegionFactory =
           cache.createRegionFactory(RegionShortcut.PARTITION);
       dataRegionFactory.setConcurrencyLevel(4);
@@ -137,23 +111,31 @@ public static void setupSystem() throws Exception {
       createRegionsWithSubRegions();
     });
 
-    gfshCommandRule.connectAndVerify(locator);
+    gfsh.connectAndVerify(locator);
+    gfsh.executeAndAssertThat("create async-event-queue --id=queue1 --group=group1 "
+        + "--listener=org.apache.geode.internal.cache.wan.MyAsyncEventListener").statusIsSuccess();
+
+    locator.waitTillAsyncEventQueuesAreReadyOnServers("queue1", 1);
+    gfsh.executeAndAssertThat(
+        "create region --name=region4 --type=REPLICATE --async-event-queue-id=queue1")
+        .statusIsSuccess();
+
   }
 
   @Test
-  public void describeRegionsOnServer2() throws Exception {
+  public void describeRegionOnBothServers() throws Exception {
     CommandStringBuilder csb = new CommandStringBuilder(DESCRIBE_REGION);
     csb.addOption(DESCRIBE_REGION__NAME, PR1);
-    gfshCommandRule.executeAndAssertThat(csb.toString()).statusIsSuccess().containsOutput(PR1,
-        "Server");
+    gfsh.executeAndAssertThat(csb.toString()).statusIsSuccess().containsOutput(PR1, "server-1",
+        "server-2");
   }
 
   @Test
-  public void describeRegionsOnServer1() throws Exception {
+  public void describeLocalRegionOnlyOneServer1() throws Exception {
     CommandStringBuilder csb = new CommandStringBuilder(DESCRIBE_REGION);
-    csb.addOption(DESCRIBE_REGION__NAME, LOCALREGIONONMANAGER);
-    gfshCommandRule.executeAndAssertThat(csb.toString()).statusIsSuccess()
-        .containsOutput(LOCALREGIONONMANAGER, SERVER1_NAME);
+    csb.addOption(DESCRIBE_REGION__NAME, LOCAL_REGION);
+    gfsh.executeAndAssertThat(csb.toString()).statusIsSuccess()
+        .containsOutput(LOCAL_REGION, "server-1").doesNotContainOutput("server-2");
   }
 
   /**
@@ -172,7 +154,7 @@ public void describeRegionWithCompressionCodec() throws Exception {
     CommandStringBuilder csb = new CommandStringBuilder(DESCRIBE_REGION);
     csb.addOption(DESCRIBE_REGION__NAME, regionName);
     String commandString = csb.toString();
-    gfshCommandRule.executeAndAssertThat(commandString).statusIsSuccess().containsOutput(regionName,
+    gfsh.executeAndAssertThat(commandString).statusIsSuccess().containsOutput(regionName,
         RegionAttributesNames.COMPRESSOR, RegionEntryContext.DEFAULT_COMPRESSION_PROVIDER);
 
     // Destroy compressed region
@@ -183,15 +165,10 @@ public void describeRegionWithCompressionCodec() throws Exception {
     });
   }
 
-  private static Properties createProperties(String name, String groups) {
-    Properties props = new Properties();
-    props.setProperty(MCAST_PORT, "0");
-    props.setProperty(LOG_LEVEL, "info");
-    props.setProperty(STATISTIC_SAMPLING_ENABLED, "true");
-    props.setProperty(ENABLE_TIME_STATISTICS, "true");
-    props.setProperty(NAME, name);
-    props.setProperty(GROUPS, groups);
-    return props;
+  @Test
+  public void describeRegionWithAsyncEventQueue() throws Exception {
+    gfsh.executeAndAssertThat("describe region --name=region4").statusIsSuccess()
+        .containsOutput("async-event-queue-id", "queue1");
   }
 
   private static void createLocalRegion(final String regionName) {
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DescribeRegionIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DescribeRegionIntegrationTest.java
index e0f990f0e1..e455fff745 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DescribeRegionIntegrationTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DescribeRegionIntegrationTest.java
@@ -15,6 +15,7 @@
 
 package org.apache.geode.management.internal.cli.commands;
 
+import org.junit.Before;
 import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
@@ -35,35 +36,28 @@
   @ClassRule
   public static ServerStarterRule server = new ServerStarterRule()
       .withRegion(RegionShortcut.REPLICATE, REGION_NAME).withName(MEMBER_NAME)
-      .withProperty("groups", GROUP_NAME).withJMXManager().withEmbeddedLocator().withAutoStart();
+      .withProperty("groups", GROUP_NAME).withJMXManager().withAutoStart();
 
   @Rule
-  public GfshCommandRule gfsh = new GfshCommandRule();
+  public GfshCommandRule gfsh =
+      new GfshCommandRule(server::getJmxPort, PortType.jmxManager).withTimeout(2);
 
   @Test
   public void commandFailsWhenNotConnected() throws Exception {
+    gfsh.disconnect();
     gfsh.executeAndAssertThat("describe region").statusIsError()
         .containsOutput("was found but is not currently available");
   }
 
-  @Test
-  public void commandFailsWithoutNameOption() throws Exception {
-    String cmd = "describe region";
-    gfsh.connectAndVerify(server.getEmbeddedLocatorPort(), PortType.locator);
-    gfsh.executeAndAssertThat(cmd).statusIsError().containsOutput("You should specify option");
-  }
-
   @Test
   public void commandFailsWithBadNameOption() throws Exception {
     String cmd = "describe region --name=invalid-region-name";
-    gfsh.connectAndVerify(server.getEmbeddedLocatorPort(), PortType.locator);
     gfsh.executeAndAssertThat(cmd).statusIsError().containsOutput("invalid-region-name not found");
   }
 
   @Test
   public void commandSucceedsWithGoodNameOption() throws Exception {
     String cmd = "describe region --name=" + REGION_NAME;
-    gfsh.connectAndVerify(server.getEmbeddedLocatorPort(), PortType.locator);
     gfsh.executeAndAssertThat(cmd).statusIsSuccess().containsOutput("Name", "Data Policy",
         "Hosting Members");
   }
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DescribeRegionJUnitTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DescribeRegionJUnitTest.java
new file mode 100644
index 0000000000..0faca890e1
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DescribeRegionJUnitTest.java
@@ -0,0 +1,188 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.apache.geode.management.internal.cli.commands;
+
+import static org.apache.geode.cache.DataPolicy.NORMAL;
+import static org.apache.geode.cache.Scope.DISTRIBUTED_ACK;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.management.internal.cli.GfshParseResult;
+import org.apache.geode.management.internal.cli.domain.RegionDescriptionPerMember;
+import org.apache.geode.management.internal.cli.json.GfJsonObject;
+import org.apache.geode.management.internal.cli.result.CommandResult;
+import org.apache.geode.test.junit.assertions.CommandResultAssert;
+import org.apache.geode.test.junit.categories.UnitTest;
+import org.apache.geode.test.junit.rules.GfshParserRule;
+
+@Category(UnitTest.class)
+public class DescribeRegionJUnitTest {
+
+  @ClassRule
+  public static GfshParserRule gfsh = new GfshParserRule();
+
+  private DescribeRegionCommand command;
+  private static String COMMAND = "describe region";
+  private List<RegionDescriptionPerMember> functionResults;
+  private static final String regionName = "testRegion";
+
+  @Before
+  public void setup() {
+    command = spy(DescribeRegionCommand.class);
+    functionResults = new ArrayList<>();
+    doReturn(functionResults).when(command).getFunctionResultFromMembers(any());
+  }
+
+  private RegionDescriptionPerMember createRegionDescriptionPerMember(String memberName,
+      Map<String, String> evictionMap, Map<String, String> partitionMap,
+      Map<String, String> regionMap) {
+    RegionDescriptionPerMember descriptionPerMember = mock(RegionDescriptionPerMember.class);
+    when(descriptionPerMember.getNonDefaultEvictionAttributes()).thenReturn(evictionMap);
+    when(descriptionPerMember.getNonDefaultPartitionAttributes()).thenReturn(partitionMap);
+    when(descriptionPerMember.getNonDefaultRegionAttributes()).thenReturn(regionMap);
+    when(descriptionPerMember.getHostingMember()).thenReturn(memberName);
+    when(descriptionPerMember.getScope()).thenReturn(DISTRIBUTED_ACK);
+    when(descriptionPerMember.getDataPolicy()).thenReturn(NORMAL);
+    when(descriptionPerMember.getName()).thenReturn(regionName);
+
+    return descriptionPerMember;
+  }
+
+  @Test
+  public void nameIsMandatory() throws Exception {
+    gfsh.executeAndAssertThat(command, COMMAND).statusIsError().containsOutput("Invalid command");
+  }
+
+  @Test
+  public void regionPathConverted() throws Exception {
+    GfshParseResult parseResult = gfsh.parse(COMMAND + " --name=test");
+    assertThat(parseResult.getParamValueAsString("name")).isEqualTo("/test");
+  }
+
+  @Test
+  public void gettingDescriptionFromOneMember() throws Exception {
+    Map<String, String> evictionAttr = new HashMap<>();
+    Map<String, String> partitionAttr = new HashMap<>();
+    Map<String, String> regionAttr = new HashMap<>();
+
+    evictionAttr.put("evictKey", "evictVal");
+    partitionAttr.put("partKey", "partVal");
+    regionAttr.put("regKey", "regVal");
+
+    RegionDescriptionPerMember descriptionPerMember =
+        createRegionDescriptionPerMember("mockA", evictionAttr, partitionAttr, regionAttr);
+    functionResults.add(descriptionPerMember);
+
+    CommandResultAssert commandAssert =
+        gfsh.executeAndAssertThat(command, COMMAND + " --name=" + regionName).statusIsSuccess()
+            .doesNotContainOutput("Non-Default Attributes Specific To");
+
+    GfJsonObject shared = getSharedAttributedJson(commandAssert.getCommandResult());
+    GfJsonObject unique = getMemberSpecificAttributeJson(commandAssert.getCommandResult());
+
+    assertThat(shared.toString()).contains("regKey", "regVal", "evictKey", "evictVal", "partKey",
+        "partVal");
+    assertThat(unique.toString()).isEqualTo("{}");
+  }
+
+  @Test
+  public void gettingDescriptionFromTwoIdenticalMembers() throws Exception {
+    Map<String, String> evictionAttr = new HashMap<>();
+    Map<String, String> partitionAttr = new HashMap<>();
+    Map<String, String> regionAttr = new HashMap<>();
+
+    evictionAttr.put("evictKey", "evictVal");
+    partitionAttr.put("partKey", "partVal");
+    regionAttr.put("regKey", "regVal");
+
+    RegionDescriptionPerMember descriptionPerMemberA =
+        createRegionDescriptionPerMember("mockA", evictionAttr, partitionAttr, regionAttr);
+    RegionDescriptionPerMember descriptionPerMemberB =
+        createRegionDescriptionPerMember("mockB", evictionAttr, partitionAttr, regionAttr);
+    functionResults.add(descriptionPerMemberA);
+    functionResults.add(descriptionPerMemberB);
+
+    CommandResultAssert commandAssert =
+        gfsh.executeAndAssertThat(command, COMMAND + " --name=" + regionName).statusIsSuccess()
+            .doesNotContainOutput("Non-Default Attributes Specific To");
+
+    GfJsonObject shared = getSharedAttributedJson(commandAssert.getCommandResult());
+    GfJsonObject unique = getMemberSpecificAttributeJson(commandAssert.getCommandResult());
+
+    assertThat(shared.toString()).contains("regKey", "regVal", "evictKey", "evictVal", "partKey",
+        "partVal");
+    assertThat(unique.toString()).isEqualTo("{}");
+  }
+
+  @Test
+  public void gettingDescriptionFromTwoDifferentMembers() throws Exception {
+    Map<String, String> evictionAttrA = new HashMap<>();
+    Map<String, String> partitionAttrA = new HashMap<>();
+    Map<String, String> regionAttrA = new HashMap<>();
+
+    evictionAttrA.put("sharedEvictionKey", "sharedEvictionValue");
+    partitionAttrA.put("sharedPartitionKey", "uniquePartitionValue_A");
+    regionAttrA.put("uniqueRegionKey_A", "uniqueRegionValue_A");
+
+    Map<String, String> evictionAttrB = new HashMap<>();
+    Map<String, String> partitionAttrB = new HashMap<>();
+    Map<String, String> regionAttrB = new HashMap<>();
+
+    evictionAttrB.put("sharedEvictionKey", "sharedEvictionValue");
+    partitionAttrB.put("sharedPartitionKey", "uniquePartitionValue_B");
+    regionAttrB.put("uniqueRegionKey_B", "uniqueRegionValue_B");
+
+    RegionDescriptionPerMember descriptionPerMemberA =
+        createRegionDescriptionPerMember("mockA", evictionAttrA, partitionAttrA, regionAttrA);
+    RegionDescriptionPerMember descriptionPerMemberB =
+        createRegionDescriptionPerMember("mockB", evictionAttrB, partitionAttrB, regionAttrB);
+    functionResults.add(descriptionPerMemberA);
+    functionResults.add(descriptionPerMemberB);
+
+    CommandResultAssert commandAssert =
+        gfsh.executeAndAssertThat(command, COMMAND + " --name=" + regionName).statusIsSuccess();
+
+    GfJsonObject shared = getSharedAttributedJson(commandAssert.getCommandResult());
+    GfJsonObject unique = getMemberSpecificAttributeJson(commandAssert.getCommandResult());
+
+    assertThat(shared.toString()).contains("Eviction", "sharedEvictionKey", "sharedEvictionValue");
+    assertThat(unique.toString()).contains("sharedPartitionKey", "uniquePartitionValue_A",
+        "uniqueRegionKey_A", "uniqueRegionValue_A", "sharedPartitionKey", "uniquePartitionValue_B",
+        "uniqueRegionKey_B", "uniqueRegionValue_B");
+  }
+
+  private GfJsonObject getSharedAttributedJson(CommandResult commandResult) {
+    return commandResult.getTableContent(0, 0, 0);
+  }
+
+  private GfJsonObject getMemberSpecificAttributeJson(CommandResult commandResult) {
+    return commandResult.getTableContent(0, 1, 0);
+  }
+}
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/domain/RegionDescriptionJUnitTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/domain/RegionDescriptionJUnitTest.java
new file mode 100644
index 0000000000..94f7f6a35c
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/domain/RegionDescriptionJUnitTest.java
@@ -0,0 +1,255 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.apache.geode.management.internal.cli.domain;
+
+import static org.apache.geode.cache.DataPolicy.NORMAL;
+import static org.apache.geode.cache.Scope.DISTRIBUTED_ACK;
+import static org.apache.geode.cache.Scope.LOCAL;
+import static org.apache.geode.management.internal.cli.domain.RegionDescription.findCommon;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.test.junit.categories.UnitTest;
+
+@Category(UnitTest.class)
+public class RegionDescriptionJUnitTest {
+  private static final String evictionKeyShared = "sharedEvictionKey";
+  private static final String partKeyShared = "sharedPartitionKey";
+  private static final String regKeyShared = "sharedRegionKey";
+  private static final String evictionValueShared = "sharedEvictionValue";
+  private static final String partValueShared = "sharedPartitionValue";
+  private static final String regValueShared = "sharedRegionValue";
+
+  private static final String evictionKeyA = "uniqueEvictionKey_A";
+  private static final String partKeyA = "uniquePartitionKey_A";
+  private static final String regKeyA = "uniqueRegionKey_A";
+  private static final String evictionValueA = "uniqueEvictionValue_A";
+  private static final String partValueA = "uniquePartitionValue_A";
+  private static final String regValueA = "uniqueRegionValue_A";
+
+  private static final String evictionKeyB = "uniqueEvictionKey_B";
+  private static final String partKeyB = "uniquePartitionKey_B";
+  private static final String regKeyB = "uniqueRegionKey_B";
+  private static final String evictionValueB = "uniqueEvictionValue_B";
+  private static final String partValueB = "uniquePartitionValue_B";
+  private static final String regValueB = "uniqueRegionValue_B";
+
+  public static final String regionName = "mockRegion1";
+
+  @Test
+  public void findCommonRemovesUnsharedKeys() {
+    Map<String, String> commonMap = new HashMap<>();
+    commonMap.put(evictionKeyShared, evictionValueShared);
+    commonMap.put(partKeyShared, partValueShared);
+    commonMap.put(regKeyShared, regValueShared);
+    commonMap.put(evictionKeyA, evictionValueA);
+    commonMap.put(partKeyA, partValueA);
+
+    Map<String, String> comparisonMap = new HashMap<>();
+    comparisonMap.put(evictionKeyShared, evictionValueShared);
+    comparisonMap.put(partKeyShared, partValueShared);
+    comparisonMap.put(regKeyShared, regValueShared);
+    comparisonMap.put(evictionKeyB, evictionValueB);
+    comparisonMap.put(regKeyB, regValueB);
+
+    findCommon(commonMap, comparisonMap);
+
+    assertThat(commonMap).containsOnlyKeys(evictionKeyShared, partKeyShared, regKeyShared);
+  }
+
+  @Test
+  public void findCommonRemovesKeysWithDisagreeingValues() {
+    Map<String, String> commonMap = new HashMap<>();
+    commonMap.put(evictionKeyShared, evictionValueShared);
+    commonMap.put(partKeyShared, partValueA);
+    commonMap.put(regKeyShared, regValueA);
+
+    Map<String, String> comparisonMap = new HashMap<>();
+    comparisonMap.put(evictionKeyShared, evictionValueShared);
+    comparisonMap.put(partKeyShared, partValueB);
+    comparisonMap.put(regKeyShared, regValueB);
+
+    findCommon(commonMap, comparisonMap);
+
+    assertThat(commonMap).containsOnlyKeys(evictionKeyShared);
+  }
+
+  @Test
+  public void findCommonRemovesDisagreeingKeysInvolvingNull() {
+    Map<String, String> commonMap = new HashMap<>();
+    commonMap.put(evictionKeyShared, evictionValueShared);
+    commonMap.put(partKeyShared, partValueA);
+    commonMap.put(regKeyShared, null);
+
+    Map<String, String> comparisonMap = new HashMap<>();
+    comparisonMap.put(evictionKeyShared, evictionValueShared);
+    comparisonMap.put(partKeyShared, null);
+    comparisonMap.put(regKeyShared, regValueB);
+
+    findCommon(commonMap, comparisonMap);
+
+    assertThat(commonMap).containsOnlyKeys(evictionKeyShared);
+  }
+
+
+  @Test
+  public void singleAddDefinesDescription() {
+    RegionDescriptionPerMember mockA = getMockRegionDescriptionPerMember_A();
+    RegionDescription description = new RegionDescription();
+    description.add(mockA);
+
+    assertThat(description.getCndEvictionAttributes())
+        .isEqualTo(mockA.getNonDefaultEvictionAttributes());
+    assertThat(description.getCndPartitionAttributes())
+        .isEqualTo(mockA.getNonDefaultPartitionAttributes());
+    assertThat(description.getCndRegionAttributes())
+        .isEqualTo(mockA.getNonDefaultRegionAttributes());
+  }
+
+  @Test
+  public void multipleAddsMergeAsExpected() {
+    RegionDescriptionPerMember mockA = getMockRegionDescriptionPerMember_A();
+    RegionDescriptionPerMember mockB = getMockRegionDescriptionPerMember_B();
+    RegionDescription description = new RegionDescription();
+    description.add(mockA);
+    description.add(mockB);
+
+    Map<String, String> sharedEviction = new HashMap<>();
+    sharedEviction.put(evictionKeyShared, evictionValueShared);
+    Map<String, String> sharedRegion = new HashMap<>();
+    sharedRegion.put(regKeyShared, regValueShared);
+    Map<String, String> sharedPartition = new HashMap<>();
+    sharedPartition.put(partKeyShared, partValueShared);
+
+    assertThat(description.getCndEvictionAttributes()).isEqualTo(sharedEviction);
+    assertThat(description.getCndPartitionAttributes()).isEqualTo(sharedPartition);
+    assertThat(description.getCndRegionAttributes()).isEqualTo(sharedRegion);
+
+    assertThat(description.getRegionDescriptionPerMemberMap())
+        .containsOnlyKeys(mockA.getHostingMember(), mockB.getHostingMember())
+        .containsEntry(mockA.getHostingMember(), mockA)
+        .containsEntry(mockB.getHostingMember(), mockB);
+  }
+
+  @Test
+  public void outOfScopeAddGetsIgnored() {
+    RegionDescriptionPerMember mockA = getMockRegionDescriptionPerMember_A();
+    RegionDescriptionPerMember mockB = getMockRegionDescriptionPerMember_OutOfScope();
+    RegionDescription description = new RegionDescription();
+    description.add(mockA);
+    description.add(mockB);
+
+    assertThat(description.getCndEvictionAttributes())
+        .isEqualTo(mockA.getNonDefaultEvictionAttributes());
+    assertThat(description.getCndPartitionAttributes())
+        .isEqualTo(mockA.getNonDefaultPartitionAttributes());
+    assertThat(description.getCndRegionAttributes())
+        .isEqualTo(mockA.getNonDefaultRegionAttributes());
+  }
+
+  private RegionDescriptionPerMember getMockRegionDescriptionPerMember_A() {
+    Map<String, String> mockNonDefaultEvictionAttributes = new HashMap<>();
+    mockNonDefaultEvictionAttributes.put(evictionKeyShared, evictionValueShared);
+    mockNonDefaultEvictionAttributes.put(evictionKeyA, evictionValueA);
+
+    Map<String, String> mockNonDefaultPartitionAttributes = new HashMap<>();
+    mockNonDefaultPartitionAttributes.put(partKeyShared, partValueShared);
+    mockNonDefaultPartitionAttributes.put(partKeyA, partValueA);
+
+    Map<String, String> mockNonDefaultRegionAttributes = new HashMap<>();
+    mockNonDefaultRegionAttributes.put(regKeyShared, regValueShared);
+    mockNonDefaultRegionAttributes.put(regKeyA, regValueA);
+
+    RegionDescriptionPerMember mockDescPerMember = mock(RegionDescriptionPerMember.class);
+
+    when(mockDescPerMember.getNonDefaultEvictionAttributes())
+        .thenReturn(mockNonDefaultEvictionAttributes);
+    when(mockDescPerMember.getNonDefaultPartitionAttributes())
+        .thenReturn(mockNonDefaultPartitionAttributes);
+    when(mockDescPerMember.getNonDefaultRegionAttributes())
+        .thenReturn(mockNonDefaultRegionAttributes);
+    when(mockDescPerMember.getHostingMember()).thenReturn("mockMemberA");
+    when(mockDescPerMember.getScope()).thenReturn(DISTRIBUTED_ACK);
+    when(mockDescPerMember.getDataPolicy()).thenReturn(NORMAL);
+    when(mockDescPerMember.getName()).thenReturn(regionName);
+
+    return mockDescPerMember;
+  }
+
+  private RegionDescriptionPerMember getMockRegionDescriptionPerMember_B() {
+    Map<String, String> mockNonDefaultEvictionAttributes = new HashMap<>();
+    mockNonDefaultEvictionAttributes.put(evictionKeyShared, evictionValueShared);
+    mockNonDefaultEvictionAttributes.put(evictionKeyB, evictionValueB);
+
+    Map<String, String> mockNonDefaultPartitionAttributes = new HashMap<>();
+    mockNonDefaultPartitionAttributes.put(partKeyShared, partValueShared);
+    mockNonDefaultPartitionAttributes.put(partKeyB, partValueB);
+
+    Map<String, String> mockNonDefaultRegionAttributes = new HashMap<>();
+    mockNonDefaultRegionAttributes.put(regKeyShared, regValueShared);
+    mockNonDefaultRegionAttributes.put(regKeyB, regValueB);
+
+    RegionDescriptionPerMember mockDescPerMember = mock(RegionDescriptionPerMember.class);
+
+    when(mockDescPerMember.getNonDefaultEvictionAttributes())
+        .thenReturn(mockNonDefaultEvictionAttributes);
+    when(mockDescPerMember.getNonDefaultPartitionAttributes())
+        .thenReturn(mockNonDefaultPartitionAttributes);
+    when(mockDescPerMember.getNonDefaultRegionAttributes())
+        .thenReturn(mockNonDefaultRegionAttributes);
+    when(mockDescPerMember.getHostingMember()).thenReturn("mockMemberB");
+    when(mockDescPerMember.getScope()).thenReturn(DISTRIBUTED_ACK);
+    when(mockDescPerMember.getDataPolicy()).thenReturn(NORMAL);
+    when(mockDescPerMember.getName()).thenReturn(regionName);
+
+    return mockDescPerMember;
+  }
+
+  private RegionDescriptionPerMember getMockRegionDescriptionPerMember_OutOfScope() {
+    Map<String, String> mockNonDefaultEvictionAttributes = new HashMap<>();
+    mockNonDefaultEvictionAttributes.put(evictionKeyShared, evictionValueShared);
+
+    Map<String, String> mockNonDefaultPartitionAttributes = new HashMap<>();
+    mockNonDefaultPartitionAttributes.put(partKeyShared, partValueShared);
+
+    Map<String, String> mockNonDefaultRegionAttributes = new HashMap<>();
+    mockNonDefaultRegionAttributes.put(regKeyShared, regValueShared);
+
+    RegionDescriptionPerMember mockDescPerMember = mock(RegionDescriptionPerMember.class);
+
+    when(mockDescPerMember.getNonDefaultEvictionAttributes())
+        .thenReturn(mockNonDefaultEvictionAttributes);
+    when(mockDescPerMember.getNonDefaultPartitionAttributes())
+        .thenReturn(mockNonDefaultPartitionAttributes);
+    when(mockDescPerMember.getNonDefaultRegionAttributes())
+        .thenReturn(mockNonDefaultRegionAttributes);
+    when(mockDescPerMember.getHostingMember()).thenReturn("mockMemberC");
+    when(mockDescPerMember.getScope()).thenReturn(LOCAL);
+    when(mockDescPerMember.getDataPolicy()).thenReturn(NORMAL);
+    when(mockDescPerMember.getName()).thenReturn(regionName);
+
+    return mockDescPerMember;
+  }
+
+
+}
diff --git a/geode-core/src/test/java/org/apache/geode/test/dunit/rules/MemberVM.java b/geode-core/src/test/java/org/apache/geode/test/dunit/rules/MemberVM.java
index a61fabb5e3..71b3396a89 100644
--- a/geode-core/src/test/java/org/apache/geode/test/dunit/rules/MemberVM.java
+++ b/geode-core/src/test/java/org/apache/geode/test/dunit/rules/MemberVM.java
@@ -118,9 +118,8 @@ public void stopMember(boolean cleanWorkingDir) {
     } else
       // if using the dunit/vm dir as the preset working dir, need to cleanup dir except
       // the locator0view* file, so that regions/indexes won't get persisted across tests
-      Arrays.stream(getWorkingDir().listFiles((dir, name) -> {
-        return !name.startsWith("locator0view");
-      })).forEach(FileUtils::deleteQuietly);
+      Arrays.stream(getWorkingDir().listFiles((dir, name) -> !name.startsWith("locator0view")))
+          .forEach(FileUtils::deleteQuietly);
   }
 
   public static void invokeInEveryMember(SerializableRunnableIF runnableIF, MemberVM... members) {
@@ -131,10 +130,8 @@ public static void invokeInEveryMember(SerializableRunnableIF runnableIF, Member
    * this should called on a locatorVM or a serverVM with jmxManager enabled
    */
   public void waitTillRegionsAreReadyOnServers(String regionPath, int serverCount) {
-    vm.invoke(() -> {
-      LocatorServerStartupRule.memberStarter.waitTillRegionIsReadyOnServers(regionPath,
-          serverCount);
-    });
+    vm.invoke(() -> LocatorServerStartupRule.memberStarter
+        .waitTillRegionIsReadyOnServers(regionPath, serverCount));
   }
 
   public void waitTillDiskstoreIsReady(String diskstoreName, int serverCount) {
@@ -143,10 +140,12 @@ public void waitTillDiskstoreIsReady(String diskstoreName, int serverCount) {
   }
 
   public void waitTillAsyncEventQueuesAreReadyOnServers(String queueId, int serverCount) {
-    vm.invoke(() -> {
-      LocatorServerStartupRule.memberStarter.waitTillAsyncEventQueuesAreReadyOnServers(queueId,
-          serverCount);
-    });
+    vm.invoke(() -> LocatorServerStartupRule.memberStarter
+        .waitTillAsyncEventQueuesAreReadyOnServers(queueId, serverCount));
   }
 
+  public void waitTilGatewaySendersAreReady(int expectedGatewayObjectCount) throws Exception {
+    vm.invoke(() -> LocatorServerStartupRule.memberStarter
+        .waitTilGatewaySendersAreReady(expectedGatewayObjectCount));
+  }
 }
diff --git a/geode-core/src/test/java/org/apache/geode/test/junit/assertions/CommandResultAssert.java b/geode-core/src/test/java/org/apache/geode/test/junit/assertions/CommandResultAssert.java
index 382b65c941..40d1469c00 100644
--- a/geode-core/src/test/java/org/apache/geode/test/junit/assertions/CommandResultAssert.java
+++ b/geode-core/src/test/java/org/apache/geode/test/junit/assertions/CommandResultAssert.java
@@ -42,6 +42,10 @@ public CommandResultAssert(String output, CommandResult commandResult) {
     super(new CommandResultExecution(output, commandResult), CommandResultAssert.class);
   }
 
+  public CommandResult getCommandResult() {
+    return actual.getCommandResult();
+  }
+
   /**
    * Verifies that the gfsh output contains the given key, value pair.
    *
diff --git a/geode-core/src/test/java/org/apache/geode/test/junit/rules/MemberStarterRule.java b/geode-core/src/test/java/org/apache/geode/test/junit/rules/MemberStarterRule.java
index e2dcc9cc68..a817ef4500 100644
--- a/geode-core/src/test/java/org/apache/geode/test/junit/rules/MemberStarterRule.java
+++ b/geode-core/src/test/java/org/apache/geode/test/junit/rules/MemberStarterRule.java
@@ -259,6 +259,12 @@ private long getDiskStoreCount(String diskStoreName) {
     return count;
   }
 
+  public void waitTilGatewaySendersAreReady(int expectedGatewayObjectCount) throws Exception {
+    DistributedSystemMXBean dsMXBean = getManagementService().getDistributedSystemMXBean();
+    await().atMost(30, TimeUnit.SECONDS)
+        .until(() -> dsMXBean.listGatewaySenderObjectNames().length == expectedGatewayObjectCount);
+  }
+
   public void waitTillDiskStoreIsReady(String diskstoreName, int serverCount) {
     await().atMost(30, TimeUnit.SECONDS)
         .until(() -> getDiskStoreCount(diskstoreName) == serverCount);
diff --git a/geode-wan/src/test/java/org/apache/geode/management/internal/cli/commands/DescribeRegionDUnitTest.java b/geode-wan/src/test/java/org/apache/geode/management/internal/cli/commands/DescribeRegionDUnitTest.java
new file mode 100644
index 0000000000..24d686ef41
--- /dev/null
+++ b/geode-wan/src/test/java/org/apache/geode/management/internal/cli/commands/DescribeRegionDUnitTest.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.management.internal.cli.commands;
+
+import static org.apache.geode.distributed.ConfigurationProperties.DISTRIBUTED_SYSTEM_ID;
+import static org.apache.geode.distributed.ConfigurationProperties.REMOTE_LOCATORS;
+
+import java.util.Properties;
+
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.test.dunit.rules.LocatorServerStartupRule;
+import org.apache.geode.test.dunit.rules.MemberVM;
+import org.apache.geode.test.junit.categories.DistributedTest;
+import org.apache.geode.test.junit.rules.GfshCommandRule;
+
+@Category(DistributedTest.class)
+public class DescribeRegionDUnitTest {
+
+  @ClassRule
+  public static LocatorServerStartupRule lsRule = new LocatorServerStartupRule();
+
+  @ClassRule
+  public static GfshCommandRule gfsh = new GfshCommandRule();
+
+  @Test
+  public void describeRegionWithGatewayAndAsyncEventQueue() throws Exception {
+    Properties props = new Properties();
+    props.setProperty(DISTRIBUTED_SYSTEM_ID, "" + 1);
+    MemberVM sending_locator = lsRule.startLocatorVM(1, props);
+
+    props.setProperty(DISTRIBUTED_SYSTEM_ID, "" + 2);
+    props.setProperty(REMOTE_LOCATORS, "localhost[" + sending_locator.getPort() + "]");
+    lsRule.startLocatorVM(2, props);
+
+    lsRule.startServerVM(3, "group1", sending_locator.getPort());
+    lsRule.startServerVM(4, "group2", sending_locator.getPort());
+
+    gfsh.connectAndVerify(sending_locator);
+    gfsh.executeAndAssertThat("create async-event-queue --id=queue1 --group=group1 "
+        + "--listener=org.apache.geode.internal.cache.wan.MyAsyncEventListener").statusIsSuccess();
+    gfsh.executeAndAssertThat("create gateway-sender --id=sender1 --remote-distributed-system-id=2")
+        .statusIsSuccess();
+    sending_locator.waitTillAsyncEventQueuesAreReadyOnServers("queue1", 1);
+    sending_locator.waitTilGatewaySendersAreReady(2);
+
+    gfsh.executeAndAssertThat(
+        "create region --name=region4 --type=REPLICATE --async-event-queue-id=queue1 --gateway-sender-id=sender1")
+        .statusIsSuccess();
+
+    gfsh.executeAndAssertThat("describe region --name=region4").statusIsSuccess()
+        .containsOutput("gateway-sender-id", "sender1", "async-event-queue-id", "queue1");
+  }
+}


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


> The gfsh 'describe region' command doesn't include asyncEventQueueIds or gatewaySenderIds
> -----------------------------------------------------------------------------------------
>
>                 Key: GEODE-3955
>                 URL: https://issues.apache.org/jira/browse/GEODE-3955
>             Project: Geode
>          Issue Type: Improvement
>          Components: management
>            Reporter: Barry Oglesby
>            Priority: Minor
>             Fix For: 1.4.0
>
>         Attachments: geode-3955.diff
>
>
> The {{constructor}} and {{getNonDefaultAttributes}} methods in {{org.apache.geode.management.internal.cli.domain.RegionAttributesInfo}} class would have to be modified to include the {{asyncEventQueueIds}} and {{gatewaySenderIds}}. 
> I did a quick modification of this class (attached).
> With these changes, 'describe region' looks like:
> {noformat}
> gfsh>describe region --name=/data
> ..........................................................
> Name            : data
> Data Policy     : partition
> Hosting Members : ln-1
> Non-Default Attributes Shared By Hosting Members  
>   Type    |         Name          | Value
> --------- | --------------------- | ---------
> Region    | data-policy           | PARTITION
>           | async-event-queue-ids | db
>           | size                  | 0
>           | gateway-sender-ids    | ny
> Partition | redundant-copies      | 1
> {noformat}



--
This message was sent by Atlassian JIRA
(v6.4.14#64029)

Mime
View raw message