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

jensdeppe 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 00e1cb1  GEODE-2566: Add --if-exists option to destroy index (#1014)
00e1cb1 is described below

commit 00e1cb1e254d4911f0f556cf63880fab1bc9b65d
Author: Jens Deppe <[email protected]>
AuthorDate: Tue Nov 7 13:24:18 2017 -0800

    GEODE-2566: Add --if-exists option to destroy index (#1014)
    
    * GEODE-2566: Add --if-exists option to destroy index
    
    * GEODE-2566: Review updates
---
 .../internal/cli/commands/DestroyIndexCommand.java |  84 +++------
 .../management/internal/cli/domain/IndexInfo.java  |   9 +
 .../cli/functions/DestroyIndexFunction.java        |  48 ++---
 .../commands/DestroyIndexCommandsDUnitTest.java    | 198 +++++++++++++++++++++
 .../cli/commands/IndexCommandsIntegrationTest.java |  45 ++++-
 .../geode/codeAnalysis/sanctionedSerializables.txt |   5 +-
 6 files changed, 303 insertions(+), 86 deletions(-)

diff --git 
a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/DestroyIndexCommand.java
 
b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/DestroyIndexCommand.java
index 413dbdd..3a8f5de 100644
--- 
a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/DestroyIndexCommand.java
+++ 
b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/DestroyIndexCommand.java
@@ -26,8 +26,6 @@ import org.apache.commons.lang.ArrayUtils;
 import org.springframework.shell.core.annotation.CliCommand;
 import org.springframework.shell.core.annotation.CliOption;
 
-import org.apache.geode.cache.Cache;
-import org.apache.geode.cache.CacheFactory;
 import org.apache.geode.cache.execute.ResultCollector;
 import org.apache.geode.distributed.DistributedMember;
 import org.apache.geode.internal.lang.StringUtils;
@@ -42,6 +40,7 @@ import 
org.apache.geode.management.internal.cli.i18n.CliStrings;
 import org.apache.geode.management.internal.cli.result.ErrorResultData;
 import org.apache.geode.management.internal.cli.result.InfoResultData;
 import org.apache.geode.management.internal.cli.result.ResultBuilder;
+import org.apache.geode.management.internal.cli.result.TabularResultData;
 import org.apache.geode.management.internal.configuration.domain.XmlEntity;
 import org.apache.geode.management.internal.security.ResourceOperation;
 import org.apache.geode.security.ResourcePermission;
@@ -56,19 +55,16 @@ public class DestroyIndexCommand implements GfshCommand {
   public Result destroyIndex(
       @CliOption(key = CliStrings.DESTROY_INDEX__NAME, unspecifiedDefaultValue 
= "",
           help = CliStrings.DESTROY_INDEX__NAME__HELP) final String indexName,
-
       @CliOption(key = CliStrings.DESTROY_INDEX__REGION, optionContext = 
ConverterHint.REGION_PATH,
           help = CliStrings.DESTROY_INDEX__REGION__HELP) final String 
regionPath,
-
       @CliOption(key = {CliStrings.MEMBER, CliStrings.MEMBERS},
           optionContext = ConverterHint.MEMBERIDNAME,
           help = CliStrings.DESTROY_INDEX__MEMBER__HELP) final String[] 
memberNameOrID,
-
       @CliOption(key = {CliStrings.GROUP, CliStrings.GROUPS},
           optionContext = ConverterHint.MEMBERGROUP,
-          help = CliStrings.DESTROY_INDEX__GROUP__HELP) final String[] group) {
-
-    Result result;
+          help = CliStrings.DESTROY_INDEX__GROUP__HELP) final String[] group,
+      @CliOption(key = CliStrings.IFEXISTS, specifiedDefaultValue = "true",
+          unspecifiedDefaultValue = "false", help = CliStrings.IFEXISTS_HELP) 
boolean ifExists) {
 
     if (StringUtils.isBlank(indexName) && StringUtils.isBlank(regionPath)
         && ArrayUtils.isEmpty(group) && ArrayUtils.isEmpty(memberNameOrID)) {
@@ -81,6 +77,7 @@ public class DestroyIndexCommand implements GfshCommand {
       regionName = regionPath.startsWith("/") ? regionPath.substring(1) : 
regionPath;
     }
     IndexInfo indexInfo = new IndexInfo(indexName, regionName);
+    indexInfo.setIfExists(ifExists);
     Set<DistributedMember> targetMembers = CliUtil.findMembers(group, 
memberNameOrID);
 
     if (targetMembers.isEmpty()) {
@@ -88,17 +85,30 @@ public class DestroyIndexCommand implements GfshCommand {
     }
 
     ResultCollector rc = CliUtil.executeFunction(destroyIndexFunction, 
indexInfo, targetMembers);
-    List<Object> funcResults = (List<Object>) rc.getResult();
+    List<CliFunctionResult> funcResults = (List<CliFunctionResult>) 
rc.getResult();
 
     Set<String> successfulMembers = new TreeSet<>();
     Map<String, Set<String>> indexOpFailMap = new HashMap<>();
 
     AtomicReference<XmlEntity> xmlEntity = new AtomicReference<>();
-    for (Object funcResult : funcResults) {
-      if (!(funcResult instanceof CliFunctionResult)) {
-        continue;
+
+    TabularResultData tabularResultData = 
ResultBuilder.createTabularResultData();
+    final String errorPrefix = "ERROR:";
+
+    for (CliFunctionResult cliFunctionResult : funcResults) {
+      boolean success = cliFunctionResult.isSuccessful();
+
+      tabularResultData.accumulate("Member", 
cliFunctionResult.getMemberIdOrName());
+      tabularResultData.accumulate("Status",
+          (success ? "" : errorPrefix) + cliFunctionResult.getMessage());
+
+      if (success) {
+        if (xmlEntity.get() == null) {
+          xmlEntity.set(cliFunctionResult.getXmlEntity());
+        }
+      } else {
+        tabularResultData.setStatus(Result.Status.ERROR);
       }
-      CliFunctionResult cliFunctionResult = (CliFunctionResult) funcResult;
 
       if (cliFunctionResult.isSuccessful()) {
         successfulMembers.add(cliFunctionResult.getMemberIdOrName());
@@ -116,54 +126,8 @@ public class DestroyIndexCommand implements GfshCommand {
         indexOpFailMap.put(exceptionMessage, failedMembers);
       }
     }
-    if (!successfulMembers.isEmpty()) {
-      InfoResultData infoResult = ResultBuilder.createInfoResultData();
-      if (StringUtils.isNotBlank(indexName)) {
-        if (StringUtils.isNotBlank(regionPath)) {
-          
infoResult.addLine(CliStrings.format(CliStrings.DESTROY_INDEX__ON__REGION__SUCCESS__MSG,
-              indexName, regionPath));
-        } else {
-          
infoResult.addLine(CliStrings.format(CliStrings.DESTROY_INDEX__SUCCESS__MSG, 
indexName));
-        }
-      } else {
-        if (StringUtils.isNotBlank(regionPath)) {
-          infoResult.addLine(CliStrings
-              
.format(CliStrings.DESTROY_INDEX__ON__REGION__ONLY__SUCCESS__MSG, regionPath));
-        } else {
-          
infoResult.addLine(CliStrings.DESTROY_INDEX__ON__MEMBERS__ONLY__SUCCESS__MSG);
-        }
-      }
-      int num = 0;
-      for (String memberId : successfulMembers) {
-        infoResult.addLine(CliStrings.format(
-            CliStrings.format(CliStrings.DESTROY_INDEX__NUMBER__AND__MEMBER, 
++num, memberId)));
-      }
-      result = ResultBuilder.buildResult(infoResult);
-    } else {
-      ErrorResultData erd = ResultBuilder.createErrorResultData();
-      if (StringUtils.isNotBlank(indexName)) {
-        erd.addLine(CliStrings.format(CliStrings.DESTROY_INDEX__FAILURE__MSG, 
indexName));
-      } else {
-        erd.addLine("Indexes could not be destroyed for following reasons");
-      }
+    Result result = ResultBuilder.buildResult(tabularResultData);
 
-      Set<String> exceptionMessages = indexOpFailMap.keySet();
-
-      for (String exceptionMessage : exceptionMessages) {
-        
erd.addLine(CliStrings.format(CliStrings.DESTROY_INDEX__REASON_MESSAGE, 
exceptionMessage));
-        erd.addLine(CliStrings.DESTROY_INDEX__EXCEPTION__OCCURRED__ON);
-
-        Set<String> memberIds = indexOpFailMap.get(exceptionMessage);
-        int num = 0;
-
-        for (String memberId : memberIds) {
-          erd.addLine(CliStrings.format(
-              CliStrings.format(CliStrings.DESTROY_INDEX__NUMBER__AND__MEMBER, 
++num, memberId)));
-        }
-        erd.addLine("");
-      }
-      result = ResultBuilder.buildResult(erd);
-    }
     if (xmlEntity.get() != null) {
       persistClusterConfiguration(result,
           () -> getSharedConfiguration().deleteXmlEntity(xmlEntity.get(), 
group));
diff --git 
a/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/IndexInfo.java
 
b/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/IndexInfo.java
index 24559c8..f99b1ce 100644
--- 
a/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/IndexInfo.java
+++ 
b/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/IndexInfo.java
@@ -30,6 +30,7 @@ public class IndexInfo implements Serializable {
   private String indexedExpression = null;
   private String regionPath = null;
   private IndexType indexType = IndexType.FUNCTIONAL;
+  private boolean ifExists;
 
   public IndexInfo(String indexName) {
     this.indexName = indexName;
@@ -92,6 +93,14 @@ public class IndexInfo implements Serializable {
     this.indexType = indexType;
   }
 
+  public boolean isIfExists() {
+    return ifExists;
+  }
+
+  public void setIfExists(boolean ifExists) {
+    this.ifExists = ifExists;
+  }
+
   public String toString() {
     StringBuffer sb = new StringBuffer();
     sb.append("Index Name : ");
diff --git 
a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/DestroyIndexFunction.java
 
b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/DestroyIndexFunction.java
index 6e45c56..e7488e7 100644
--- 
a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/DestroyIndexFunction.java
+++ 
b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/DestroyIndexFunction.java
@@ -19,7 +19,7 @@ import java.util.List;
 import org.apache.geode.cache.Cache;
 import org.apache.geode.cache.CacheClosedException;
 import org.apache.geode.cache.Region;
-import org.apache.geode.cache.execute.FunctionAdapter;
+import org.apache.geode.cache.execute.Function;
 import org.apache.geode.cache.execute.FunctionContext;
 import org.apache.geode.cache.query.Index;
 import org.apache.geode.cache.query.QueryService;
@@ -29,17 +29,15 @@ import 
org.apache.geode.management.internal.cli.domain.IndexInfo;
 import org.apache.geode.management.internal.cli.i18n.CliStrings;
 import org.apache.geode.management.internal.configuration.domain.XmlEntity;
 
-
-
-public class DestroyIndexFunction extends FunctionAdapter implements 
InternalEntity {
-
-  private static final long serialVersionUID = 1L;
+public class DestroyIndexFunction implements Function, InternalEntity {
+  private static final long serialVersionUID = -868082551095130315L;
 
   @Override
   public void execute(FunctionContext context) {
     IndexInfo indexInfo = (IndexInfo) context.getArguments();
     String memberId = null;
 
+    CliFunctionResult result;
     try {
       Cache cache = context.getCache();
       memberId = cache.getDistributedSystem().getDistributedMember().getId();
@@ -56,41 +54,51 @@ public class DestroyIndexFunction extends FunctionAdapter 
implements InternalEnt
         if (region != null) {
           if (indexName == null || indexName.isEmpty()) {
             queryService.removeIndexes(region);
-            context.getResultSender().lastResult(new 
CliFunctionResult(memberId, xmlEntity));
+            result = new CliFunctionResult(memberId, xmlEntity,
+                "Destroyed all indexes on region " + regionPath);
           } else {
             Index index = queryService.getIndex(region, indexName);
 
             if (index != null) {
               queryService.removeIndex(index);
-              context.getResultSender().lastResult(new 
CliFunctionResult(memberId, xmlEntity));
+              result = new CliFunctionResult(memberId, xmlEntity,
+                  "Destroyed index " + indexName + " on region " + regionPath);
+            } else if (indexInfo.isIfExists()) {
+              result = new CliFunctionResult(memberId, true,
+                  "Index " + indexName + " not found - skipped");
             } else {
-              context.getResultSender().lastResult(new 
CliFunctionResult(memberId, false,
-                  
CliStrings.format(CliStrings.DESTROY_INDEX__INDEX__NOT__FOUND, indexName)));
+              result = new CliFunctionResult(memberId, false,
+                  
CliStrings.format(CliStrings.DESTROY_INDEX__INDEX__NOT__FOUND, indexName));
             }
           }
         } else {
-          context.getResultSender().lastResult(new CliFunctionResult(memberId, 
false,
-              CliStrings.format(CliStrings.DESTROY_INDEX__REGION__NOT__FOUND, 
regionPath)));
+          result = new CliFunctionResult(memberId, false,
+              CliStrings.format(CliStrings.DESTROY_INDEX__REGION__NOT__FOUND, 
regionPath));
         }
-
       } else {
         if (indexName == null || indexName.isEmpty()) {
           queryService.removeIndexes();
-          context.getResultSender().lastResult(new CliFunctionResult(memberId, 
xmlEntity));
+          result = new CliFunctionResult(memberId, xmlEntity, "Destroyed all 
indexes");
         } else {
-          if (removeIndexByName(indexName, queryService)) {
-            context.getResultSender().lastResult(new 
CliFunctionResult(memberId, xmlEntity));
+          boolean indexRemoved = removeIndexByName(indexName, queryService);
+          if (indexRemoved) {
+            result = new CliFunctionResult(memberId, xmlEntity, "Destroyed 
index " + indexName);
+          } else if (indexInfo.isIfExists()) {
+            result = new CliFunctionResult(memberId, true,
+                "Index " + indexName + " not found - skipped");
           } else {
-            context.getResultSender().lastResult(new 
CliFunctionResult(memberId, false,
-                CliStrings.format(CliStrings.DESTROY_INDEX__INDEX__NOT__FOUND, 
indexName)));
+            result = new CliFunctionResult(memberId, false,
+                CliStrings.format(CliStrings.DESTROY_INDEX__INDEX__NOT__FOUND, 
indexName));
           }
         }
       }
     } catch (CacheClosedException e) {
-      context.getResultSender().lastResult(new CliFunctionResult(memberId, e, 
e.getMessage()));
+      result = new CliFunctionResult(memberId, e, e.getMessage());
     } catch (Exception e) {
-      context.getResultSender().lastResult(new CliFunctionResult(memberId, e, 
e.getMessage()));
+      result = new CliFunctionResult(memberId, e, e.getMessage());
     }
+
+    context.getResultSender().lastResult(result);
   }
 
   /***
diff --git 
a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DestroyIndexCommandsDUnitTest.java
 
b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DestroyIndexCommandsDUnitTest.java
new file mode 100644
index 0000000..96fbe71
--- /dev/null
+++ 
b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/DestroyIndexCommandsDUnitTest.java
@@ -0,0 +1,198 @@
+/*
+ * 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.assertj.core.api.Assertions.assertThat;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.cache.Cache;
+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.domain.Stock;
+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.GfshShellConnectionRule;
+
+@Category(DistributedTest.class)
+public class DestroyIndexCommandsDUnitTest {
+
+  private static final String REGION_1 = "REGION1";
+  private static final String INDEX_1 = "INDEX1";
+  private static final String INDEX_2 = "INDEX2";
+
+  private MemberVM locator;
+  private MemberVM server1;
+  private MemberVM server2;
+
+  @Rule
+  public LocatorServerStartupRule rule = new LocatorServerStartupRule();
+
+  @Rule
+  public GfshShellConnectionRule gfsh = new GfshShellConnectionRule();
+
+  @Before
+  public void before() throws Exception {
+    locator = rule.startLocatorVM(0);
+    server1 = rule.startServerVM(1, locator.getPort());
+    server2 = rule.startServerVM(2, locator.getPort());
+
+    server1.invoke(() -> {
+      createRegionAndIndex();
+    });
+
+    server2.invoke(() -> {
+      createRegionAndIndex();
+    });
+
+    gfsh.connectAndVerify(locator);
+  }
+
+  private static void createRegionAndIndex() throws Exception {
+    Cache cache = LocatorServerStartupRule.serverStarter.getCache();
+    RegionFactory factory = 
cache.createRegionFactory(RegionShortcut.REPLICATE);
+    Region region = factory.create(REGION_1);
+
+    cache.getQueryService().createIndex(INDEX_1, "key", "/" + REGION_1);
+    cache.getQueryService().createIndex(INDEX_2, "id", "/" + REGION_1);
+    region.put(1, new Stock("SUNW", 10));
+  }
+
+  @Test
+  public void testDestroyAllIndexesOnRegion() throws Exception {
+    gfsh.executeAndAssertThat("destroy index --region=" + 
REGION_1).statusIsSuccess()
+        .tableHasColumnWithExactValuesInAnyOrder("Status",
+            "Destroyed all indexes on region REGION1", "Destroyed all indexes 
on region REGION1");
+
+    server1.invoke(() -> {
+      Cache cache = LocatorServerStartupRule.serverStarter.getCache();
+      assertThat(cache.getQueryService().getIndexes()).isEmpty();
+    });
+
+    server2.invoke(() -> {
+      Cache cache = LocatorServerStartupRule.serverStarter.getCache();
+      assertThat(cache.getQueryService().getIndexes()).isEmpty();
+    });
+
+    // Check idempotency
+    gfsh.executeAndAssertThat("destroy index --if-exists --region=" + 
REGION_1).statusIsSuccess()
+        .tableHasColumnWithExactValuesInAnyOrder("Status",
+            "Destroyed all indexes on region REGION1", "Destroyed all indexes 
on region REGION1");
+  }
+
+  @Test
+  public void testDestroyOneIndexOnRegion() throws Exception {
+    gfsh.executeAndAssertThat("destroy index --name=" + INDEX_1 + " --region=" 
+ REGION_1)
+        .statusIsSuccess().tableHasColumnWithExactValuesInAnyOrder("Status",
+            "Destroyed index INDEX1 on region REGION1", "Destroyed index 
INDEX1 on region REGION1");
+
+    server1.invoke(() -> {
+      Cache cache = LocatorServerStartupRule.serverStarter.getCache();
+      assertThat(cache.getQueryService().getIndexes().size()).isEqualTo(1);
+    });
+
+    server2.invoke(() -> {
+      Cache cache = LocatorServerStartupRule.serverStarter.getCache();
+      assertThat(cache.getQueryService().getIndexes().size()).isEqualTo(1);
+    });
+
+    // Check idempotency
+    gfsh.executeAndAssertThat(
+        "destroy index --if-exists --name=" + INDEX_1 + " --region=" + 
REGION_1).statusIsSuccess()
+        .tableHasColumnWithExactValuesInAnyOrder("Status", "Index INDEX1 not 
found - skipped",
+            "Index INDEX1 not found - skipped");
+
+    // Check error result is correct
+    gfsh.executeAndAssertThat("destroy index --name=" + INDEX_1 + " --region=" 
+ REGION_1)
+        .statusIsError().tableHasColumnWithExactValuesInAnyOrder("Status",
+            "ERROR:Index named \"INDEX1\" not found", "ERROR:Index named 
\"INDEX1\" not found");
+  }
+
+  @Test
+  public void testDestroyAllIndexesOnOneMember() throws Exception {
+    gfsh.executeAndAssertThat("destroy index 
--member=server-1").statusIsSuccess()
+        .tableHasColumnWithExactValuesInAnyOrder("Status", "Destroyed all 
indexes");
+
+    server1.invoke(() -> {
+      Cache cache = LocatorServerStartupRule.serverStarter.getCache();
+      assertThat(cache.getQueryService().getIndexes()).isEmpty();
+    });
+
+    server2.invoke(() -> {
+      Cache cache = LocatorServerStartupRule.serverStarter.getCache();
+      assertThat(cache.getQueryService().getIndexes().size()).isEqualTo(2);
+    });
+
+    // Check idempotency
+    gfsh.executeAndAssertThat("destroy index --if-exists 
--member=server-1").statusIsSuccess()
+        .tableHasColumnWithExactValuesInAnyOrder("Status", "Destroyed all 
indexes");
+  }
+
+  @Test
+  public void testDestroyOneIndexOnOneMember() throws Exception {
+    gfsh.executeAndAssertThat("destroy index --name=" + INDEX_1 + " 
--member=server-1")
+        .statusIsSuccess()
+        .tableHasColumnWithExactValuesInAnyOrder("Status", "Destroyed index 
INDEX1");
+
+    server1.invoke(() -> {
+      Cache cache = LocatorServerStartupRule.serverStarter.getCache();
+      assertThat(cache.getQueryService().getIndexes().size()).isEqualTo(1);
+    });
+
+    server2.invoke(() -> {
+      Cache cache = LocatorServerStartupRule.serverStarter.getCache();
+      assertThat(cache.getQueryService().getIndexes().size()).isEqualTo(2);
+    });
+
+    // Check idempotency
+    gfsh.executeAndAssertThat("destroy index --if-exists --name=" + INDEX_1 + 
" --member=server-1")
+        .statusIsSuccess()
+        .tableHasColumnWithExactValuesInAnyOrder("Status", "Index INDEX1 not 
found - skipped");
+
+    // Check error result is correct
+    gfsh.executeAndAssertThat("destroy index --name=" + INDEX_1 + " 
--member=server-1")
+        .statusIsError().tableHasColumnWithExactValuesInAnyOrder("Status",
+            "ERROR:Index named \"INDEX1\" not found");
+  }
+
+  @Test
+  public void testVariableResultDestroyOneIndex() throws Exception {
+    gfsh.executeAndAssertThat("destroy index --name=" + INDEX_1 + " 
--member=server-1")
+        .statusIsSuccess()
+        .tableHasColumnWithExactValuesInAnyOrder("Status", "Destroyed index 
INDEX1");
+
+    server1.invoke(() -> {
+      Cache cache = LocatorServerStartupRule.serverStarter.getCache();
+      assertThat(cache.getQueryService().getIndexes().size()).isEqualTo(1);
+    });
+
+    server2.invoke(() -> {
+      Cache cache = LocatorServerStartupRule.serverStarter.getCache();
+      assertThat(cache.getQueryService().getIndexes().size()).isEqualTo(2);
+    });
+
+    // Check error on partial failure
+    gfsh.executeAndAssertThat("destroy index --name=" + 
INDEX_1).statusIsError()
+        .tableHasColumnWithExactValuesInAnyOrder("Status", "Destroyed index 
INDEX1",
+            "ERROR:Index named \"INDEX1\" not found");
+
+  }
+}
diff --git 
a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/IndexCommandsIntegrationTest.java
 
b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/IndexCommandsIntegrationTest.java
index 965dafb..0da3595 100644
--- 
a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/IndexCommandsIntegrationTest.java
+++ 
b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/IndexCommandsIntegrationTest.java
@@ -206,7 +206,7 @@ public class IndexCommandsIntegrationTest {
     csb.addOption(CliStrings.DESTROY_INDEX__REGION, "IncorrectRegion");
     CommandResult result = gfsh.executeCommand(csb.toString());
     assertThat(result.getStatus()).isEqualTo(Result.Status.ERROR);
-    assertThat(gfsh.getGfshOutput()).contains("Region \"IncorrectRegion\" not 
found.");
+    assertThat(gfsh.getGfshOutput()).contains("ERROR:Region 
\"IncorrectRegion\" not found");
   }
 
   @Test
@@ -237,7 +237,7 @@ public class IndexCommandsIntegrationTest {
     CommandStringBuilder csb = new 
CommandStringBuilder(CliStrings.DESTROY_INDEX);
     csb.addOption(CliStrings.DESTROY_INDEX__REGION, regionName);
     gfsh.executeAndAssertThat(csb.toString()).statusIsSuccess()
-        .containsOutput("Indexes on region : /regionA successfully destroyed");
+        .containsOutput("Destroyed all indexes on region regionA");
   }
 
   @Test
@@ -247,7 +247,46 @@ public class IndexCommandsIntegrationTest {
     CommandStringBuilder csb = new 
CommandStringBuilder(CliStrings.DESTROY_INDEX);
     csb.addOption(CliStrings.GROUP, groupName);
     gfsh.executeAndAssertThat(csb.toString()).statusIsSuccess()
-        .containsOutput("Indexes successfully destroyed");
+        .containsOutput("Destroyed all indexes");
+  }
+
+  @Test
+  public void testFailWhenDestroyIndexIsNotIdempotent() throws Exception {
+    createSimpleIndexA();
+
+    CommandStringBuilder csb = new 
CommandStringBuilder(CliStrings.DESTROY_INDEX);
+    csb.addOption(CliStrings.DESTROY_INDEX__NAME, indexName);
+    csb.addOption(CliStrings.IFEXISTS, "false");
+    gfsh.executeAndAssertThat(csb.toString()).statusIsSuccess()
+        .containsOutput("Destroyed index " + indexName);
+    gfsh.executeAndAssertThat(csb.toString()).statusIsError()
+        .containsOutput("Index named \"" + indexName + "\" not found");
+  }
+
+  @Test
+  public void testDestroyIndexOnRegionIsIdempotent() throws Exception {
+    createSimpleIndexA();
+
+    CommandStringBuilder csb = new 
CommandStringBuilder(CliStrings.DESTROY_INDEX);
+    csb.addOption(CliStrings.DESTROY_INDEX__REGION, regionName);
+    csb.addOption(CliStrings.IFEXISTS, "true");
+    gfsh.executeAndAssertThat(csb.toString()).statusIsSuccess()
+        .containsOutput("Destroyed all indexes on region regionA");
+    gfsh.executeAndAssertThat(csb.toString()).statusIsSuccess()
+        .containsOutput("Destroyed all indexes on region regionA");
+  }
+
+  @Test
+  public void testDestroyIndexByNameIsIdempotent() throws Exception {
+    createSimpleIndexA();
+
+    CommandStringBuilder csb = new 
CommandStringBuilder(CliStrings.DESTROY_INDEX);
+    csb.addOption(CliStrings.DESTROY_INDEX__NAME, indexName);
+    csb.addOption(CliStrings.IFEXISTS);
+    gfsh.executeAndAssertThat(csb.toString()).statusIsSuccess()
+        .containsOutput("Destroyed index " + indexName);
+    gfsh.executeAndAssertThat(csb.toString()).statusIsSuccess()
+        .containsOutput("Index " + indexName + " not found - skipped");
   }
 
   private void createSimpleIndexA() throws Exception {
diff --git 
a/geode-core/src/test/resources/org/apache/geode/codeAnalysis/sanctionedSerializables.txt
 
b/geode-core/src/test/resources/org/apache/geode/codeAnalysis/sanctionedSerializables.txt
index 8ea1efc..37a4224 100755
--- 
a/geode-core/src/test/resources/org/apache/geode/codeAnalysis/sanctionedSerializables.txt
+++ 
b/geode-core/src/test/resources/org/apache/geode/codeAnalysis/sanctionedSerializables.txt
@@ -341,7 +341,6 @@ 
org/apache/geode/internal/cache/tier/sockets/CacheClientNotifier$2,false,this$0:
 
org/apache/geode/internal/cache/tier/sockets/CacheClientProxy$MessageDispatcher$1,true,0,this$0:org/apache/geode/internal/cache/tier/sockets/CacheClientProxy$MessageDispatcher
 
org/apache/geode/internal/cache/tier/sockets/ClientTombstoneMessage$TOperation,false
 
org/apache/geode/internal/cache/tier/sockets/MessageTooLargeException,true,-8970585803331525833
-org/apache/geode/internal/cache/tier/sockets/ServiceLoadingFailureException,false
 
org/apache/geode/internal/cache/tier/sockets/UnregisterAllInterest,true,5026160621257178459
 
org/apache/geode/internal/cache/tx/TransactionalOperation$ServerRegionOperation,false
 
org/apache/geode/internal/cache/versions/ConcurrentCacheModificationException,true,2316928221010347462
@@ -480,7 +479,7 @@ 
org/apache/geode/management/internal/cli/domain/EvictionAttributesInfo,true,1,ev
 
org/apache/geode/management/internal/cli/domain/FixedPartitionAttributesInfo,true,1,isPrimary:boolean,numBuckets:int,partitionName:java/lang/String
 
org/apache/geode/management/internal/cli/domain/IndexDetails,true,-2198907141534201288,fromClause:java/lang/String,indexName:java/lang/String,indexStatisticsDetails:org/apache/geode/management/internal/cli/domain/IndexDetails$IndexStatisticsDetails,indexType:org/apache/geode/cache/query/IndexType,indexedExpression:java/lang/String,isValid:boolean,memberId:java/lang/String,memberName:java/lang/String,projectionAttributes:java/lang/String,regionName:java/lang/String,regionPath:java/lang/String
 
org/apache/geode/management/internal/cli/domain/IndexDetails$IndexStatisticsDetails,false,numberOfKeys:java/lang/Long,numberOfUpdates:java/lang/Long,numberOfValues:java/lang/Long,totalUpdateTime:java/lang/Long,totalUses:java/lang/Long
-org/apache/geode/management/internal/cli/domain/IndexInfo,true,1,indexName:java/lang/String,indexType:org/apache/geode/cache/query/IndexType,indexedExpression:java/lang/String,regionPath:java/lang/String
+org/apache/geode/management/internal/cli/domain/IndexInfo,true,1,ifExists:boolean,indexName:java/lang/String,indexType:org/apache/geode/cache/query/IndexType,indexedExpression:java/lang/String,regionPath:java/lang/String
 
org/apache/geode/management/internal/cli/domain/MemberConfigurationInfo,false,cacheAttributes:java/util/Map,cacheServerAttributes:java/util/List,gfePropsRuntime:java/util/Map,gfePropsSetFromFile:java/util/Map,gfePropsSetUsingApi:java/util/Map,gfePropsSetWithDefaults:java/util/Map,jvmInputArguments:java/util/List,pdxAttributes:java/util/Map,systemProperties:java/util/Properties
 
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
@@ -509,7 +508,7 @@ 
org/apache/geode/management/internal/cli/functions/DataCommandFunction,true,1,op
 org/apache/geode/management/internal/cli/functions/DeployFunction,true,1
 
org/apache/geode/management/internal/cli/functions/DescribeDiskStoreFunction,false
 
org/apache/geode/management/internal/cli/functions/DestroyDiskStoreFunction,true,1
-org/apache/geode/management/internal/cli/functions/DestroyIndexFunction,true,1
+org/apache/geode/management/internal/cli/functions/DestroyIndexFunction,true,-868082551095130315
 org/apache/geode/management/internal/cli/functions/ExportConfigFunction,true,1
 org/apache/geode/management/internal/cli/functions/ExportDataFunction,true,1
 org/apache/geode/management/internal/cli/functions/ExportLogsFunction,true,1

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

Reply via email to