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

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

commit 9636d670fc4cbdef2b614132d6c9721005db4731
Author: Patrick Rhomberg <[email protected]>
AuthorDate: Tue Nov 28 16:19:19 2017 -0800

    GEODE-3955: Add AEQ and Gateway Sender information to 'describe region' 
output.
    
    * Add DUnit test coverage for 'describe region' command
    * Add JUnit test coverage for RegionDescription class
    * Expansion and refactoring of touched classes.
    
    - This closes #1099.
---
 .../cli/commands/DescribeRegionCommand.java        |  28 +-
 .../internal/cli/domain/RegionAttributesInfo.java  | 283 +++++++++++----------
 .../internal/cli/domain/RegionDescription.java     |  44 ++--
 .../internal/cli/result/CommandResult.java         |  25 +-
 .../internal/cli/util/RegionAttributesNames.java   |   2 +
 .../sanctioned-geode-core-serializables.txt        |   4 +-
 .../cli/commands/DescribeRegionDUnitTest.java      |  89 +++----
 .../commands/DescribeRegionIntegrationTest.java    |  16 +-
 .../cli/commands/DescribeRegionJUnitTest.java      | 188 ++++++++++++++
 .../cli/domain/RegionDescriptionJUnitTest.java     | 255 +++++++++++++++++++
 .../apache/geode/test/dunit/rules/MemberVM.java    |   4 -
 .../test/junit/assertions/CommandResultAssert.java |   4 +
 .../cli/commands/DescribeRegionDUnitTest.java      |  68 +++++
 13 files changed, 755 insertions(+), 255 deletions(-)

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 971f54e..0abe36a 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
@@ -20,16 +20,17 @@ 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;
@@ -43,6 +44,8 @@ import 
org.apache.geode.management.internal.security.ResourceOperation;
 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();
 
@@ -54,15 +57,11 @@ public class DescribeRegionCommand implements GfshCommand {
       @CliOption(key = CliStrings.DESCRIBE_REGION__NAME, optionContext = 
ConverterHint.REGION_PATH,
           help = CliStrings.DESCRIBE_REGION__NAME__HELP, mandatory = true) 
String regionName) {
 
-    InternalCache cache = getCache();
-    ResultCollector<?, ?> rc =
-        CliUtil.executeFunction(getRegionDescription, regionName, 
getAllNormalMembers(cache));
-
-    List<?> resultList = (List<?>) rc.getResult();
+    List<?> resultList = getFunctionResultFromMembers(regionName);
 
     // Log any errors received.
     
resultList.stream().filter(Throwable.class::isInstance).map(Throwable.class::cast)
-        .forEach(t -> LogWrapper.getInstance().info(t.getMessage(), t));
+        .forEach(t -> logger.info(t.getMessage(), t));
 
     // Aggregate PerMember data to to a single RegionDescription
     RegionDescription regionDescription = new RegionDescription();
@@ -83,6 +82,14 @@ public class DescribeRegionCommand implements GfshCommand {
     return buildDescriptionResult(regionName, regionDescription);
   }
 
+  List<?> getFunctionResultFromMembers(String regionName) {
+    InternalCache cache = getCache();
+    ResultCollector<?, ?> rc =
+        executeFunction(getRegionDescription, regionName, 
getAllNormalMembers(cache));
+
+    return (List<?>) rc.getResult();
+  }
+
   public Result buildDescriptionResult(String regionName, RegionDescription 
regionDescription) {
     if (regionDescription.isEmpty()) {
       return ResultBuilder
@@ -157,7 +164,8 @@ public class DescribeRegionCommand implements GfshCommand {
 
       List<FixedPartitionAttributesInfo> fpaList = 
regDescPerMem.getFixedPartitionAttributes();
 
-      if (!ndRa.isEmpty() || !ndEa.isEmpty() || !ndPa.isEmpty() || fpaList != 
null) {
+      if (!ndRa.isEmpty() || !ndEa.isEmpty() || !ndPa.isEmpty()
+          || (fpaList != null && !fpaList.isEmpty())) {
         setHeader = true;
         boolean memberNameAdded;
         memberNameAdded = writeAttributesToTable(table,
@@ -172,8 +180,8 @@ public class DescribeRegionCommand implements GfshCommand {
     }
 
     if (setHeader) {
-      table.setHeader(CliStrings.format(
-          CliStrings.DESCRIBE_REGION__NONDEFAULT__PERMEMBERATTRIBUTES__HEADER, 
memberType));
+      table.setHeader(CliStrings
+          
.format(CliStrings.DESCRIBE_REGION__NONDEFAULT__PERMEMBERATTRIBUTES__HEADER, 
memberType));
     }
 
     return ResultBuilder.buildResult(crd);
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 64201eb..faaa919 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.io.Serializable;
 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 @@ import 
org.apache.geode.management.internal.cli.util.RegionAttributesNames;
 
 
 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 @@ public class RegionAttributesInfo implements Serializable {
 
   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 class RegionAttributesInfo implements Serializable {
       regionIdleTimeoutAction = expAction.toString();
     }
 
-
+    asyncEventQueueIDs = ra.getAsyncEventQueueIds();
+    gatewaySenderIDs = ra.getGatewaySenderIds();
 
     // Collecting information about all the CacheListeners, CacheWriters, 
CacheLoaders
     CacheListener<?, ?>[] cacheListeners = ra.getCacheListeners();
@@ -258,6 +260,14 @@ public class RegionAttributesInfo implements Serializable {
     return initialCapacity;
   }
 
+  public Set<String> getAsyncEventQueueIDs() {
+    return asyncEventQueueIDs;
+  }
+
+  public Set<String> getGatewaySenderIDs() {
+    return gatewaySenderIDs;
+  }
+
   public float getLoadFactor() {
     return loadFactor;
   }
@@ -323,175 +333,166 @@ public class RegionAttributesInfo implements 
Serializable {
    */
   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 9f829b7..2f25afc 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
@@ -29,7 +29,7 @@ import org.apache.geode.cache.Scope;
  */
 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;
@@ -37,11 +37,11 @@ public class RegionDescription implements Serializable {
   private boolean isLocal = 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;
@@ -68,29 +68,23 @@ public class RegionDescription implements Serializable {
     if (regionDescPerMemberMap == null) {
       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();
-      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<>();
-      
this.cndRegionAttributes.putAll(regionDescPerMember.getNonDefaultRegionAttributes());
-
-      this.cndPartitionAttributes = new HashMap<>();
-      
this.cndPartitionAttributes.putAll(regionDescPerMember.getNonDefaultPartitionAttributes());
-
-      this.cndEvictionAttributes = new HashMap<>();
-      
this.cndEvictionAttributes.putAll(regionDescPerMember.getNonDefaultEvictionAttributes());
+      
cndRegionAttributes.putAll(regionDescPerMember.getNonDefaultRegionAttributes());
+      
cndPartitionAttributes.putAll(regionDescPerMember.getNonDefaultPartitionAttributes());
+      
cndEvictionAttributes.putAll(regionDescPerMember.getNonDefaultEvictionAttributes());
 
       isAdded = true;
-    } else if (this.scope.equals(regionDescPerMember.getScope())
-        && this.name.equals(regionDescPerMember.getName())
-        && this.dataPolicy.equals(regionDescPerMember.getDataPolicy())
-        && this.isAccessor == regionDescPerMember.isAccessor()) {
+    } 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());
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 13153ec..b7aac06 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 class CommandResult implements Result {
     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/RegionAttributesNames.java
 
b/geode-core/src/main/java/org/apache/geode/management/internal/cli/util/RegionAttributesNames.java
index d5d89b6..341a126 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 class RegionAttributesNames {
   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 e7cd276..971db79 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/Str
 [...]
 
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:
 [...]
-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:bo
 [...]
+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 8e22339..e4ddd3a 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.VM;
 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 @@ public class DescribeRegionDUnitTest implements Serializable 
{
   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 class DescribeRegionDUnitTest implements 
Serializable {
   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 class DescribeRegionDUnitTest implements 
Serializable {
       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 class DescribeRegionDUnitTest implements 
Serializable {
       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 class DescribeRegionDUnitTest implements 
Serializable {
     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 class DescribeRegionDUnitTest implements 
Serializable {
     });
   }
 
-  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 e0f990f..e455fff7 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 @@ public class DescribeRegionIntegrationTest {
   @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 0000000..0faca89
--- /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 0000000..94f7f6a
--- /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 2f0d729..71b3396 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
@@ -15,15 +15,11 @@
 
 package org.apache.geode.test.dunit.rules;
 
-import static org.awaitility.Awaitility.await;
-
 import java.io.File;
 import java.util.Arrays;
-import java.util.concurrent.TimeUnit;
 
 import org.apache.commons.io.FileUtils;
 
-import org.apache.geode.management.DistributedSystemMXBean;
 import org.apache.geode.test.dunit.AsyncInvocation;
 import org.apache.geode.test.dunit.SerializableCallableIF;
 import org.apache.geode.test.dunit.SerializableRunnableIF;
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 382b65c..40d1469 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 class CommandResultAssert
     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-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 0000000..24d686e
--- /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");
+  }
+}

-- 
To stop receiving notification emails like this one, please contact
"[email protected]" <[email protected]>.

Reply via email to