You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by pr...@apache.org on 2017/11/20 17:27:17 UTC

[geode] branch develop updated: GEODE-3539: Add missing test coverage for 'list regions' and 'describe region' commands

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


The following commit(s) were added to refs/heads/develop by this push:
     new 526bcfc  GEODE-3539: Add missing test coverage for 'list regions' and 'describe region' commands
526bcfc is described below

commit 526bcfc073d5cdc448d072269717743292248402
Author: Patrick Rhomberg <Pu...@users.noreply.github.com>
AuthorDate: Mon Nov 20 09:27:15 2017 -0800

    GEODE-3539: Add missing test coverage for 'list regions' and 'describe region' commands
    
    * Command logic flattened to stream.
    * Testing of 'list region' and 'describe region' separated into distinct DUnit and Integration tests.  'list region' DUnit simplified.
    * Removed @Flaky annotation from 'describe region' DUnit test
---
 .../internal/cli/commands/ListRegionCommand.java   |  23 ++-
 .../management/internal/cli/HeadlessGfsh.java      |   6 +-
 ...DUnitTest.java => DescribeRegionDUnitTest.java} |  77 +++------
 .../commands/DescribeRegionIntegrationTest.java    |  70 ++++++++
 .../internal/cli/commands/ListRegionDUnitTest.java | 176 +++++++++++++++++++++
 .../cli/commands/ListRegionIntegrationTest.java    |  84 ++++++++++
 .../geode/test/junit/rules/GfshCommandRule.java    |   6 +-
 7 files changed, 372 insertions(+), 70 deletions(-)

diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ListRegionCommand.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ListRegionCommand.java
index 1ca310c..cd58449 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ListRegionCommand.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ListRegionCommand.java
@@ -16,9 +16,12 @@
 package org.apache.geode.management.internal.cli.commands;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.LinkedHashSet;
+import java.util.Objects;
 import java.util.Set;
 import java.util.TreeSet;
+import java.util.stream.Collectors;
 
 import org.springframework.shell.core.annotation.CliCommand;
 import org.springframework.shell.core.annotation.CliOption;
@@ -29,7 +32,9 @@ import org.apache.geode.distributed.DistributedMember;
 import org.apache.geode.management.cli.CliMetaData;
 import org.apache.geode.management.cli.ConverterHint;
 import org.apache.geode.management.cli.Result;
+import org.apache.geode.management.internal.cli.AbstractCliAroundInterceptor;
 import org.apache.geode.management.internal.cli.CliUtil;
+import org.apache.geode.management.internal.cli.GfshParseResult;
 import org.apache.geode.management.internal.cli.domain.RegionInformation;
 import org.apache.geode.management.internal.cli.functions.GetRegionsFunction;
 import org.apache.geode.management.internal.cli.i18n.CliStrings;
@@ -67,19 +72,11 @@ public class ListRegionCommand implements GfshCommand {
       ArrayList<?> resultList = (ArrayList<?>) rc.getResult();
 
       if (resultList != null) {
-
-        for (Object resultObj : resultList) {
-          if (resultObj != null) {
-            if (resultObj instanceof Object[]) {
-              Object[] resultObjectArray = (Object[]) resultObj;
-              for (Object regionInfo : resultObjectArray) {
-                if (regionInfo instanceof RegionInformation) {
-                  regionInfoSet.add((RegionInformation) regionInfo);
-                }
-              }
-            }
-          }
-        }
+        // Gather all RegionInformation into a flat set.
+        regionInfoSet.addAll(resultList.stream().filter(Objects::nonNull)
+            .filter(Object[].class::isInstance).map(Object[].class::cast).flatMap(Arrays::stream)
+            .filter(RegionInformation.class::isInstance).map(RegionInformation.class::cast)
+            .collect(Collectors.toSet()));
 
         Set<String> regionNames = new TreeSet<>();
 
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/HeadlessGfsh.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/HeadlessGfsh.java
index 340712c..97f600b 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/HeadlessGfsh.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/HeadlessGfsh.java
@@ -121,7 +121,7 @@ public class HeadlessGfsh implements ResultHandler {
   }
 
   public Object getResult() throws InterruptedException {
-    // Dont wait for when some command calls gfsh.stop();
+    // Don't wait for when some command calls gfsh.stop();
     if (shell.stopCalledThroughAPI)
       return null;
     try {
@@ -146,6 +146,10 @@ public class HeadlessGfsh implements ResultHandler {
     outputString = null;
   }
 
+  public void setTimeout(long timeout) {
+    this.timeout = timeout;
+  }
+
   public void clearEvents() {
     queue.clear();
     outputString = null;
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ListAndDescribeRegionDUnitTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DescribeRegionDUnitTest.java
similarity index 78%
rename from geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ListAndDescribeRegionDUnitTest.java
rename to geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DescribeRegionDUnitTest.java
index f85816e..8e22339 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ListAndDescribeRegionDUnitTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DescribeRegionDUnitTest.java
@@ -59,7 +59,7 @@ import org.apache.geode.test.junit.categories.FlakyTest;
 import org.apache.geode.test.junit.rules.GfshCommandRule;
 
 @Category(DistributedTest.class)
-public class ListAndDescribeRegionDUnitTest implements Serializable {
+public class DescribeRegionDUnitTest implements Serializable {
   private static final String REGION1 = "region1";
   private static final String REGION2 = "region2";
   private static final String REGION3 = "region3";
@@ -69,6 +69,15 @@ public class ListAndDescribeRegionDUnitTest implements Serializable {
   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 PART1_NAME = "Par1";
+  private static final String PART2_NAME = "Par2";
+
   @ClassRule
   public static LocatorServerStartupRule lsRule = new LocatorServerStartupRule();
 
@@ -77,14 +86,14 @@ public class ListAndDescribeRegionDUnitTest implements Serializable {
 
   @BeforeClass
   public static void setupSystem() throws Exception {
-    final Properties locatorProps = createProperties("Locator", "G3");
+    final Properties locatorProps = createProperties(LOCATOR_NAME, GROUP3_NAME);
     MemberVM locator = lsRule.startLocatorVM(0, locatorProps);
 
-    final Properties managerProps = createProperties("Manager", "G1");
+    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("Server", "G2");
+    final Properties serverProps = createProperties(SERVER2_NAME, GROUP2_NAME);
     MemberVM server = lsRule.startServerVM(2, serverProps, locator.getPort());
 
     manager.invoke(() -> {
@@ -97,7 +106,8 @@ public class ListAndDescribeRegionDUnitTest implements Serializable {
       dataRegionFactory.setEvictionAttributes(ea);
       dataRegionFactory.setEnableAsyncConflation(true);
 
-      FixedPartitionAttributes fpa = FixedPartitionAttributes.createFixedPartition("Par1", true);
+      FixedPartitionAttributes fpa =
+          FixedPartitionAttributes.createFixedPartition(PART1_NAME, true);
       PartitionAttributes pa = new PartitionAttributesFactory().setLocalMaxMemory(100)
           .setRecoveryDelay(2).setTotalMaxMemory(200).setRedundantCopies(1)
           .addFixedPartitionAttributes(fpa).create();
@@ -117,7 +127,7 @@ public class ListAndDescribeRegionDUnitTest implements Serializable {
       dataRegionFactory.setEvictionAttributes(ea);
       dataRegionFactory.setEnableAsyncConflation(true);
 
-      FixedPartitionAttributes fpa = FixedPartitionAttributes.createFixedPartition("Par2", 4);
+      FixedPartitionAttributes fpa = FixedPartitionAttributes.createFixedPartition(PART2_NAME, 4);
       PartitionAttributes pa = new PartitionAttributesFactory().setLocalMaxMemory(150)
           .setRecoveryDelay(4).setTotalMaxMemory(200).setRedundantCopies(1)
           .addFixedPartitionAttributes(fpa).create();
@@ -131,46 +141,7 @@ public class ListAndDescribeRegionDUnitTest implements Serializable {
   }
 
   @Test
-  public void listAllRegions() throws Exception {
-    String listRegions = new CommandStringBuilder(LIST_REGION).toString();
-    gfshCommandRule.executeAndAssertThat(listRegions).statusIsSuccess().containsOutput(PR1,
-        LOCALREGIONONMANAGER, REGION1, REGION2, REGION3);
-  }
-
-  @Test
-  public void listRegionsOnManager() throws Exception {
-    String listRegions =
-        new CommandStringBuilder(LIST_REGION).addOption(MEMBER, "Manager").toString();
-    gfshCommandRule.executeAndAssertThat(listRegions).statusIsSuccess().containsOutput(PR1,
-        LOCALREGIONONMANAGER);
-  }
-
-  @Test
-  public void listRegionsOnServer() throws Exception {
-    CommandStringBuilder csb = new CommandStringBuilder(LIST_REGION);
-    csb.addOption(MEMBER, "Server");
-    gfshCommandRule.executeAndAssertThat(csb.toString()).statusIsSuccess().containsOutput(PR1,
-        REGION1, REGION2, REGION3, SUBREGION1A);
-  }
-
-  @Test
-  public void listRegionsInGroup1() throws Exception {
-    CommandStringBuilder csb = new CommandStringBuilder(LIST_REGION);
-    csb.addOption(GROUP, "G1");
-    gfshCommandRule.executeAndAssertThat(csb.toString()).statusIsSuccess().containsOutput(PR1,
-        LOCALREGIONONMANAGER);
-  }
-
-  @Test
-  public void listRegionsInGroup2() throws Exception {
-    CommandStringBuilder csb = new CommandStringBuilder(LIST_REGION);
-    csb.addOption(GROUP, "G2");
-    gfshCommandRule.executeAndAssertThat(csb.toString()).statusIsSuccess().containsOutput(PR1,
-        REGION1, REGION2, REGION3, SUBREGION1A);
-  }
-
-  @Test
-  public void describeRegionsOnManager() throws Exception {
+  public void describeRegionsOnServer2() throws Exception {
     CommandStringBuilder csb = new CommandStringBuilder(DESCRIBE_REGION);
     csb.addOption(DESCRIBE_REGION__NAME, PR1);
     gfshCommandRule.executeAndAssertThat(csb.toString()).statusIsSuccess().containsOutput(PR1,
@@ -178,35 +149,31 @@ public class ListAndDescribeRegionDUnitTest implements Serializable {
   }
 
   @Test
-  public void describeRegionsOnServer() throws Exception {
+  public void describeRegionsOnServer1() throws Exception {
     CommandStringBuilder csb = new CommandStringBuilder(DESCRIBE_REGION);
     csb.addOption(DESCRIBE_REGION__NAME, LOCALREGIONONMANAGER);
     gfshCommandRule.executeAndAssertThat(csb.toString()).statusIsSuccess()
-        .containsOutput(LOCALREGIONONMANAGER, "Manager");
+        .containsOutput(LOCALREGIONONMANAGER, SERVER1_NAME);
   }
 
   /**
    * Asserts that a describe region command issued on a region with compression returns the correct
    * non default region attribute for compression and the correct codec value.
    */
-  @Category(FlakyTest.class) // GEODE-1033: HeadlesssGFSH, random port, Snappy dependency
   @Test
   public void describeRegionWithCompressionCodec() throws Exception {
     final String regionName = "compressedRegion";
     VM vm = Host.getHost(0).getVM(1);
 
     // Create compressed region
-    vm.invoke(() -> {
-      createCompressedRegion(regionName);
-    });
+    vm.invoke(() -> createCompressedRegion(regionName));
 
     // Test the describe command; look for compression
     CommandStringBuilder csb = new CommandStringBuilder(DESCRIBE_REGION);
     csb.addOption(DESCRIBE_REGION__NAME, regionName);
     String commandString = csb.toString();
-    gfshCommandRule.executeAndAssertThat(csb.toString()).statusIsSuccess().containsOutput(
-        regionName, RegionAttributesNames.COMPRESSOR,
-        RegionEntryContext.DEFAULT_COMPRESSION_PROVIDER);
+    gfshCommandRule.executeAndAssertThat(commandString).statusIsSuccess().containsOutput(regionName,
+        RegionAttributesNames.COMPRESSOR, RegionEntryContext.DEFAULT_COMPRESSION_PROVIDER);
 
     // Destroy compressed region
     vm.invoke(() -> {
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
new file mode 100644
index 0000000..e0f990f
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DescribeRegionIntegrationTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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 org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.cache.RegionShortcut;
+import org.apache.geode.test.junit.categories.IntegrationTest;
+import org.apache.geode.test.junit.rules.GfshCommandRule;
+import org.apache.geode.test.junit.rules.GfshCommandRule.PortType;
+import org.apache.geode.test.junit.rules.ServerStarterRule;
+
+@Category(IntegrationTest.class)
+public class DescribeRegionIntegrationTest {
+  private static String MEMBER_NAME = "test-server";
+  private static String REGION_NAME = "test-region";
+  private static String GROUP_NAME = "test-group";
+
+  @ClassRule
+  public static ServerStarterRule server = new ServerStarterRule()
+      .withRegion(RegionShortcut.REPLICATE, REGION_NAME).withName(MEMBER_NAME)
+      .withProperty("groups", GROUP_NAME).withJMXManager().withEmbeddedLocator().withAutoStart();
+
+  @Rule
+  public GfshCommandRule gfsh = new GfshCommandRule();
+
+  @Test
+  public void commandFailsWhenNotConnected() throws Exception {
+    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/ListRegionDUnitTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ListRegionDUnitTest.java
new file mode 100644
index 0000000..4c4a528
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ListRegionDUnitTest.java
@@ -0,0 +1,176 @@
+/*
+ * 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.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.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 java.util.Properties;
+
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.cache.Cache;
+import org.apache.geode.cache.CacheFactory;
+import org.apache.geode.cache.Region;
+import org.apache.geode.cache.RegionFactory;
+import org.apache.geode.cache.RegionShortcut;
+import org.apache.geode.management.internal.cli.util.CommandStringBuilder;
+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 ListRegionDUnitTest {
+  private static final String REGION1 = "region1";
+  private static final String REGION2 = "region2";
+  private static final String REGION3 = "region3";
+  private static final String SUBREGION1A = "subregion1A";
+  private static final String SUBREGION1B = "subregion1B";
+  private static final String SUBREGION1C = "subregion1C";
+  private static final String PR1 = "PR1";
+  private static final String LOCALREGIONONSERVER1 = "LocalRegionOnServer1";
+
+  private static final String SERVER1_NAME = "Server-1";
+  private static final String SERVER2_NAME = "Server-2";
+  private static final String LOCATOR_NAME = "Locator";
+  private static final String GROUP1_NAME = "G1";
+  private static final String GROUP2_NAME = "G2";
+  private static final String GROUP3_NAME = "G3";
+
+  @ClassRule
+  public static LocatorServerStartupRule lsRule = new LocatorServerStartupRule();
+
+  @ClassRule
+  public static GfshCommandRule gfshShellConnectionRule = 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 server1Props = createProperties(SERVER1_NAME, GROUP1_NAME);
+    server1Props.setProperty(LOCATORS, "localhost[" + locator.getPort() + "]");
+    MemberVM server1 = lsRule.startServerVM(1, server1Props, locator.getPort());
+
+    final Properties server2Props = createProperties(SERVER2_NAME, GROUP2_NAME);
+    MemberVM server = lsRule.startServerVM(2, server2Props, locator.getPort());
+
+    server1.invoke(() -> {
+      final Cache cache = CacheFactory.getAnyInstance();
+      RegionFactory<String, Integer> dataRegionFactory =
+          cache.createRegionFactory(RegionShortcut.PARTITION);
+      dataRegionFactory.create(PR1);
+      createLocalRegion(LOCALREGIONONSERVER1);
+    });
+
+    server.invoke(() -> {
+      final Cache cache = CacheFactory.getAnyInstance();
+      RegionFactory<String, Integer> dataRegionFactory =
+          cache.createRegionFactory(RegionShortcut.PARTITION);
+      dataRegionFactory.create(PR1);
+      createRegionsWithSubRegions();
+    });
+
+    gfshShellConnectionRule.connectAndVerify(locator);
+  }
+
+  @Test
+  public void listAllRegions() throws Exception {
+    String listRegions = new CommandStringBuilder(LIST_REGION).toString();
+    gfshShellConnectionRule.executeAndAssertThat(listRegions).statusIsSuccess().containsOutput(PR1,
+        LOCALREGIONONSERVER1, REGION1, REGION2, REGION3);
+  }
+
+  @Test
+  public void listRegionsOnManager() throws Exception {
+    String listRegions =
+        new CommandStringBuilder(LIST_REGION).addOption(MEMBER, SERVER1_NAME).toString();
+    gfshShellConnectionRule.executeAndAssertThat(listRegions).statusIsSuccess().containsOutput(PR1,
+        LOCALREGIONONSERVER1);
+  }
+
+  @Test
+  public void listRegionsOnServer() throws Exception {
+    CommandStringBuilder csb = new CommandStringBuilder(LIST_REGION);
+    csb.addOption(MEMBER, SERVER2_NAME);
+    gfshShellConnectionRule.executeAndAssertThat(csb.toString()).statusIsSuccess()
+        .containsOutput(PR1, REGION1, REGION2, REGION3, SUBREGION1A);
+  }
+
+  @Test
+  public void listRegionsInGroup1() throws Exception {
+    CommandStringBuilder csb = new CommandStringBuilder(LIST_REGION);
+    csb.addOption(GROUP, GROUP1_NAME);
+    gfshShellConnectionRule.executeAndAssertThat(csb.toString()).statusIsSuccess()
+        .containsOutput(PR1, LOCALREGIONONSERVER1);
+  }
+
+  @Test
+  public void listRegionsInGroup2() throws Exception {
+    CommandStringBuilder csb = new CommandStringBuilder(LIST_REGION);
+    csb.addOption(GROUP, GROUP2_NAME);
+    gfshShellConnectionRule.executeAndAssertThat(csb.toString()).statusIsSuccess()
+        .containsOutput(PR1, REGION1, REGION2, REGION3, SUBREGION1A);
+  }
+
+
+  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;
+  }
+
+  private static void createLocalRegion(final String regionName) {
+    final Cache cache = CacheFactory.getAnyInstance();
+    // Create the data region
+    RegionFactory<String, Integer> dataRegionFactory =
+        cache.createRegionFactory(RegionShortcut.LOCAL);
+    dataRegionFactory.create(regionName);
+  }
+
+  private static void createRegionsWithSubRegions() {
+    final Cache cache = CacheFactory.getAnyInstance();
+
+    RegionFactory<String, Integer> dataRegionFactory =
+        cache.createRegionFactory(RegionShortcut.REPLICATE);
+    dataRegionFactory.setConcurrencyLevel(3);
+    Region<String, Integer> region1 = dataRegionFactory.create(REGION1);
+    region1.createSubregion(SUBREGION1C, region1.getAttributes());
+    Region<String, Integer> subregion2 =
+        region1.createSubregion(SUBREGION1A, region1.getAttributes());
+
+    subregion2.createSubregion(SUBREGION1B, subregion2.getAttributes());
+    dataRegionFactory.create(REGION2);
+    dataRegionFactory.create(REGION3);
+  }
+}
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ListRegionIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ListRegionIntegrationTest.java
new file mode 100644
index 0000000..673ebf0
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ListRegionIntegrationTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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 org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.cache.RegionShortcut;
+import org.apache.geode.test.junit.categories.IntegrationTest;
+import org.apache.geode.test.junit.rules.GfshCommandRule;
+import org.apache.geode.test.junit.rules.GfshCommandRule.PortType;
+import org.apache.geode.test.junit.rules.ServerStarterRule;
+
+@Category(IntegrationTest.class)
+public class ListRegionIntegrationTest {
+  private static String MEMBER_NAME = "test-server";
+  private static String REGION_NAME = "test-region";
+  private static String GROUP_NAME = "test-group";
+  private static String OUTPUT_HEADER = "List of regions";
+
+  @ClassRule
+  public static ServerStarterRule server = new ServerStarterRule()
+      .withRegion(RegionShortcut.REPLICATE, REGION_NAME).withName(MEMBER_NAME)
+      .withProperty("groups", GROUP_NAME).withJMXManager().withAutoStart();
+
+  @Rule
+  public GfshCommandRule gfsh = new GfshCommandRule(server::getJmxPort, PortType.jmxManager);
+
+  @Before
+  public void setup() {
+    gfsh.setTimeout(2);
+  }
+
+  @Test
+  public void commandFailsWhenNotConnected() throws Exception {
+    gfsh.disconnect();
+    gfsh.executeAndAssertThat("list regions").statusIsError()
+        .containsOutput("was found but is not currently available");
+  }
+
+  @Test
+  public void memberAndGroupAreMutuallyExclusive() throws Exception {
+    String cmd = "list regions --member=" + MEMBER_NAME + " --group=" + GROUP_NAME;
+    gfsh.executeAndAssertThat(cmd).statusIsError()
+        .containsOutput("Please provide either \"member\" or \"group\" option.");
+  }
+
+  @Test
+  public void commandWithNoOptionsSucceeds() throws Exception {
+    String cmd = "list regions";
+    gfsh.executeAndAssertThat(cmd).statusIsSuccess()
+        .tableHasColumnWithValuesContaining(OUTPUT_HEADER, REGION_NAME);
+  }
+
+  @Test
+  public void commandWithMemberSucceeds() throws Exception {
+    String cmd = "list regions --member=" + MEMBER_NAME;
+    gfsh.executeAndAssertThat(cmd).statusIsSuccess()
+        .tableHasColumnWithValuesContaining(OUTPUT_HEADER, REGION_NAME);
+  }
+
+  @Test
+  public void commandWithGroupSucceeds() throws Exception {
+    String cmd = "list regions --group=" + GROUP_NAME;
+    gfsh.executeAndAssertThat(cmd).statusIsSuccess()
+        .tableHasColumnWithValuesContaining(OUTPUT_HEADER, REGION_NAME);
+  }
+}
diff --git a/geode-core/src/test/java/org/apache/geode/test/junit/rules/GfshCommandRule.java b/geode-core/src/test/java/org/apache/geode/test/junit/rules/GfshCommandRule.java
index dd1a453..a3d448a 100644
--- a/geode-core/src/test/java/org/apache/geode/test/junit/rules/GfshCommandRule.java
+++ b/geode-core/src/test/java/org/apache/geode/test/junit/rules/GfshCommandRule.java
@@ -216,7 +216,7 @@ public class GfshCommandRule extends DescribedExternalResource {
 
   public CommandResult executeCommand(String command) {
     gfsh.executeCommand(command);
-    CommandResult result = null;
+    CommandResult result;
     try {
       result = (CommandResult) gfsh.getResult();
     } catch (InterruptedException e) {
@@ -264,6 +264,10 @@ public class GfshCommandRule extends DescribedExternalResource {
     return workingDir;
   }
 
+  public void setTimeout(long timeoutInSeconds) {
+    gfsh.setTimeout(timeoutInSeconds);
+  }
+
   public enum PortType {
     locator, jmxManager, http
   }

-- 
To stop receiving notification emails like this one, please contact
['"commits@geode.apache.org" <co...@geode.apache.org>'].