1
0
Эх сурвалжийг харах

Add CloseIndexResponse to HLRC (#44349)

The CloseIndexResponse was improved in #39687; this commit 
exposes it in the HLRC.
Tanguy Leroux 6 жил өмнө
parent
commit
a69baf6b77
17 өөрчлөгдсөн 761 нэмэгдсэн , 123 устгасан
  1. 6 5
      client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java
  2. 1 1
      client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesRequestConverters.java
  3. 113 0
      client/rest-high-level/src/main/java/org/elasticsearch/client/indices/CloseIndexRequest.java
  4. 213 0
      client/rest-high-level/src/main/java/org/elasticsearch/client/indices/CloseIndexResponse.java
  5. 1 1
      client/rest-high-level/src/main/java/org/elasticsearch/client/indices/FreezeIndexRequest.java
  6. 1 1
      client/rest-high-level/src/test/java/org/elasticsearch/client/CCRIT.java
  7. 33 13
      client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java
  8. 3 8
      client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesRequestConvertersTests.java
  9. 1 1
      client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/CCRDocumentationIT.java
  10. 6 8
      client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java
  11. 76 0
      client/rest-high-level/src/test/java/org/elasticsearch/client/indices/CloseIndexRequestTests.java
  12. 221 0
      client/rest-high-level/src/test/java/org/elasticsearch/client/indices/CloseIndexResponseTests.java
  13. 0 3
      docs/java-rest/high-level/indices/close_index.asciidoc
  14. 1 2
      libs/x-content/src/main/java/org/elasticsearch/common/xcontent/AbstractObjectParser.java
  15. 7 3
      server/src/main/java/org/elasticsearch/action/support/DefaultShardOperationFailedException.java
  16. 1 1
      server/src/main/java/org/elasticsearch/action/support/master/ShardsAcknowledgedResponse.java
  17. 77 76
      server/src/test/java/org/elasticsearch/action/admin/indices/close/CloseIndexResponseTests.java

+ 6 - 5
client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java

@@ -24,7 +24,6 @@ import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
 import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
 import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheRequest;
 import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheResponse;
-import org.elasticsearch.action.admin.indices.close.CloseIndexRequest;
 import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
 import org.elasticsearch.action.admin.indices.flush.FlushRequest;
 import org.elasticsearch.action.admin.indices.flush.FlushResponse;
@@ -47,6 +46,8 @@ import org.elasticsearch.action.support.master.AcknowledgedResponse;
 import org.elasticsearch.client.core.ShardsAcknowledgedResponse;
 import org.elasticsearch.client.indices.AnalyzeRequest;
 import org.elasticsearch.client.indices.AnalyzeResponse;
+import org.elasticsearch.client.indices.CloseIndexRequest;
+import org.elasticsearch.client.indices.CloseIndexResponse;
 import org.elasticsearch.client.indices.CreateIndexRequest;
 import org.elasticsearch.client.indices.CreateIndexResponse;
 import org.elasticsearch.client.indices.FreezeIndexRequest;
@@ -471,9 +472,9 @@ public final class IndicesClient {
      * @return the response
      * @throws IOException in case there is a problem sending the request or parsing back the response
      */
-    public AcknowledgedResponse close(CloseIndexRequest closeIndexRequest, RequestOptions options) throws IOException {
+    public CloseIndexResponse close(CloseIndexRequest closeIndexRequest, RequestOptions options) throws IOException {
         return restHighLevelClient.performRequestAndParseEntity(closeIndexRequest, IndicesRequestConverters::closeIndex, options,
-            AcknowledgedResponse::fromXContent, emptySet());
+            CloseIndexResponse::fromXContent, emptySet());
     }
 
     /**
@@ -484,9 +485,9 @@ public final class IndicesClient {
      * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
      * @param listener the listener to be notified upon request completion
      */
-    public void closeAsync(CloseIndexRequest closeIndexRequest, RequestOptions options, ActionListener<AcknowledgedResponse> listener) {
+    public void closeAsync(CloseIndexRequest closeIndexRequest, RequestOptions options, ActionListener<CloseIndexResponse> listener) {
         restHighLevelClient.performRequestAsyncAndParseEntity(closeIndexRequest, IndicesRequestConverters::closeIndex, options,
-            AcknowledgedResponse::fromXContent, listener, emptySet());
+            CloseIndexResponse::fromXContent, listener, emptySet());
     }
 
 

+ 1 - 1
client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesRequestConverters.java

@@ -27,7 +27,6 @@ import org.apache.http.client.methods.HttpPut;
 import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
 import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
 import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheRequest;
-import org.elasticsearch.action.admin.indices.close.CloseIndexRequest;
 import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
 import org.elasticsearch.action.admin.indices.flush.FlushRequest;
 import org.elasticsearch.action.admin.indices.flush.SyncedFlushRequest;
@@ -41,6 +40,7 @@ import org.elasticsearch.action.admin.indices.shrink.ResizeType;
 import org.elasticsearch.action.admin.indices.template.delete.DeleteIndexTemplateRequest;
 import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryRequest;
 import org.elasticsearch.client.indices.AnalyzeRequest;
+import org.elasticsearch.client.indices.CloseIndexRequest;
 import org.elasticsearch.client.indices.CreateIndexRequest;
 import org.elasticsearch.client.indices.FreezeIndexRequest;
 import org.elasticsearch.client.indices.GetFieldMappingsRequest;

+ 113 - 0
client/rest-high-level/src/main/java/org/elasticsearch/client/indices/CloseIndexRequest.java

@@ -0,0 +1,113 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch 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.elasticsearch.client.indices;
+
+import org.elasticsearch.action.admin.indices.open.OpenIndexResponse;
+import org.elasticsearch.action.support.ActiveShardCount;
+import org.elasticsearch.action.support.IndicesOptions;
+import org.elasticsearch.client.TimedRequest;
+import org.elasticsearch.client.Validatable;
+import org.elasticsearch.client.ValidationException;
+
+import java.util.Optional;
+
+/**
+ * A request to close an index.
+ */
+public class CloseIndexRequest extends TimedRequest implements Validatable {
+
+    private String[] indices;
+    private IndicesOptions indicesOptions = IndicesOptions.strictExpandOpen();
+    private ActiveShardCount waitForActiveShards = ActiveShardCount.DEFAULT;
+
+    /**
+     * Creates a new close index request
+     *
+     * @param indices the indices to close
+     */
+    public CloseIndexRequest(String... indices) {
+        this.indices = indices;
+    }
+
+    /**
+     * Returns the indices to close
+     */
+    public String[] indices() {
+        return indices;
+    }
+
+    /**
+     * Specifies what type of requested indices to ignore and how to deal with wildcard expressions.
+     * For example indices that don't exist.
+     *
+     * @return the current behaviour when it comes to index names and wildcard indices expressions
+     */
+    public IndicesOptions indicesOptions() {
+        return indicesOptions;
+    }
+
+    /**
+     * Specifies what type of requested indices to ignore and how to deal with wildcard expressions.
+     * For example indices that don't exist.
+     *
+     * @param indicesOptions the desired behaviour regarding indices to ignore and wildcard indices expressions
+     */
+    public CloseIndexRequest indicesOptions(IndicesOptions indicesOptions) {
+        this.indicesOptions = indicesOptions;
+        return this;
+    }
+
+    /**
+     * Returns the wait for active shard count or null if the default should be used
+     */
+    public ActiveShardCount waitForActiveShards() {
+        return waitForActiveShards;
+    }
+
+    /**
+     * Sets the number of shard copies that should be active for indices opening to return.
+     * Defaults to {@link ActiveShardCount#DEFAULT}, which will wait for one shard copy
+     * (the primary) to become active. Set this value to {@link ActiveShardCount#ALL} to
+     * wait for all shards (primary and all replicas) to be active before returning.
+     * Otherwise, use {@link ActiveShardCount#from(int)} to set this value to any
+     * non-negative integer, up to the number of copies per shard (number of replicas + 1),
+     * to wait for the desired amount of shard copies to become active before returning.
+     * Indices opening will only wait up until the timeout value for the number of shard copies
+     * to be active before returning.  Check {@link OpenIndexResponse#isShardsAcknowledged()} to
+     * determine if the requisite shard copies were all started before returning or timing out.
+     *
+     * @param waitForActiveShards number of active shard copies to wait on
+     */
+    public CloseIndexRequest waitForActiveShards(ActiveShardCount waitForActiveShards) {
+        this.waitForActiveShards = waitForActiveShards;
+        return this;
+    }
+
+    @Override
+    public Optional<ValidationException> validate() {
+        if (indices == null || indices.length == 0) {
+            ValidationException validationException = new ValidationException();
+            validationException.addValidationError("index is missing");
+            return Optional.of(validationException);
+        } else {
+            return Optional.empty();
+        }
+    }
+}

+ 213 - 0
client/rest-high-level/src/main/java/org/elasticsearch/client/indices/CloseIndexResponse.java

@@ -0,0 +1,213 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch 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.elasticsearch.client.indices;
+
+import org.elasticsearch.ElasticsearchException;
+import org.elasticsearch.action.support.DefaultShardOperationFailedException;
+import org.elasticsearch.action.support.master.ShardsAcknowledgedResponse;
+import org.elasticsearch.common.Nullable;
+import org.elasticsearch.common.ParseField;
+import org.elasticsearch.common.xcontent.ConstructingObjectParser;
+import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.common.xcontent.XContentParserUtils;
+
+import java.util.List;
+import java.util.Objects;
+
+import static java.util.Collections.emptyList;
+import static java.util.Collections.unmodifiableList;
+import static org.elasticsearch.common.xcontent.ConstructingObjectParser.optionalConstructorArg;
+import static org.elasticsearch.common.xcontent.ObjectParser.ValueType;
+
+public class CloseIndexResponse extends ShardsAcknowledgedResponse {
+
+    @SuppressWarnings("unchecked")
+    private static final ConstructingObjectParser<CloseIndexResponse, Void> PARSER = new ConstructingObjectParser<>("close_index_response",
+        true, args -> {
+        boolean acknowledged = (boolean) args[0];
+        boolean shardsAcknowledged = args[1] != null ? (boolean) args[1] : acknowledged;
+        List<CloseIndexResponse.IndexResult> indices = args[2] != null ? (List<CloseIndexResponse.IndexResult>) args[2] : emptyList();
+        return new CloseIndexResponse(acknowledged, shardsAcknowledged, indices);
+    });
+
+    static {
+        declareAcknowledgedField(PARSER);
+        PARSER.declareField(optionalConstructorArg(), (parser, context) -> parser.booleanValue(), SHARDS_ACKNOWLEDGED, ValueType.BOOLEAN);
+        PARSER.declareNamedObjects(optionalConstructorArg(), (p, c, name) -> IndexResult.fromXContent(p, name), new ParseField("indices"));
+    }
+
+    private final List<CloseIndexResponse.IndexResult> indices;
+
+    public CloseIndexResponse(final boolean acknowledged, final boolean shardsAcknowledged, final List<IndexResult> indices) {
+        super(acknowledged, shardsAcknowledged);
+        this.indices = unmodifiableList(Objects.requireNonNull(indices));
+    }
+
+    public List<IndexResult> getIndices() {
+        return indices;
+    }
+
+    public static CloseIndexResponse fromXContent(final XContentParser parser) {
+        return PARSER.apply(parser, null);
+    }
+
+    public static class IndexResult {
+
+        @SuppressWarnings("unchecked")
+        private static final ConstructingObjectParser<IndexResult, String> PARSER = new ConstructingObjectParser<>("index_result", true,
+            (args, index) -> {
+                Exception exception = (Exception) args[1];
+                if (exception != null) {
+                    assert (boolean) args[0] == false;
+                    return new IndexResult(index, exception);
+                }
+                ShardResult[] shardResults = args[2] != null ? ((List<ShardResult>) args[2]).toArray(new ShardResult[0]) : null;
+                if (shardResults != null) {
+                    assert (boolean) args[0] == false;
+                    return new IndexResult(index, shardResults);
+                }
+                assert (boolean) args[0];
+                return new IndexResult(index);
+            });
+        static {
+            PARSER.declareBoolean(optionalConstructorArg(), new ParseField("closed"));
+            PARSER.declareObject(optionalConstructorArg(), (p, c) -> {
+                XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, p.currentToken(), p::getTokenLocation);
+                XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, p.nextToken(), p::getTokenLocation);
+                Exception e = ElasticsearchException.failureFromXContent(p);
+                XContentParserUtils.ensureExpectedToken(XContentParser.Token.END_OBJECT, p.nextToken(), p::getTokenLocation);
+                return e;
+            }, new ParseField("exception"));
+            PARSER.declareNamedObjects(optionalConstructorArg(),
+                (p, c, id) -> ShardResult.fromXContent(p, id), new ParseField("failedShards"));
+        }
+
+        private final String index;
+        private final @Nullable Exception exception;
+        private final @Nullable ShardResult[] shards;
+
+        IndexResult(final String index) {
+            this(index, null, null);
+        }
+
+        IndexResult(final String index, final Exception failure) {
+            this(index, Objects.requireNonNull(failure), null);
+        }
+
+        IndexResult(final String index, final ShardResult[] shards) {
+            this(index, null, Objects.requireNonNull(shards));
+        }
+
+        private IndexResult(final String index, @Nullable final Exception exception, @Nullable final ShardResult[] shards) {
+            this.index = Objects.requireNonNull(index);
+            this.exception = exception;
+            this.shards = shards;
+        }
+
+        public String getIndex() {
+            return index;
+        }
+
+        public @Nullable Exception getException() {
+            return exception;
+        }
+
+        public @Nullable ShardResult[] getShards() {
+            return shards;
+        }
+
+        public boolean hasFailures() {
+            if (exception != null) {
+                return true;
+            }
+            if (shards != null) {
+                for (ShardResult shard : shards) {
+                    if (shard.hasFailures()) {
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+
+        static IndexResult fromXContent(final XContentParser parser, final String name) {
+            return PARSER.apply(parser, name);
+        }
+    }
+
+    public static class ShardResult {
+
+        @SuppressWarnings("unchecked")
+        private static final ConstructingObjectParser<ShardResult, String> PARSER = new ConstructingObjectParser<>("shard_result", true,
+            (arg, id) -> {
+                Failure[] failures = arg[0] != null ? ((List<Failure>) arg[0]).toArray(new Failure[0]) : new Failure[0];
+                return new ShardResult(Integer.parseInt(id), failures);
+            });
+
+        static {
+            PARSER.declareObjectArray(optionalConstructorArg(), (p, c) -> Failure.PARSER.apply(p, null), new ParseField("failures"));
+        }
+
+        private final int id;
+        private final Failure[] failures;
+
+        ShardResult(final int id, final Failure[] failures) {
+            this.id = id;
+            this.failures = failures;
+        }
+
+        public boolean hasFailures() {
+            return failures != null && failures.length > 0;
+        }
+
+        public int getId() {
+            return id;
+        }
+
+        public Failure[] getFailures() {
+            return failures;
+        }
+
+        static ShardResult fromXContent(final XContentParser parser, final String id) {
+            return PARSER.apply(parser, id);
+        }
+
+        public static class Failure extends DefaultShardOperationFailedException {
+
+            static final ConstructingObjectParser<Failure, Void> PARSER = new ConstructingObjectParser<>("failure", true,
+                arg -> new Failure((String) arg[0], (int) arg[1], (Throwable) arg[2], (String) arg[3]));
+
+            static {
+                declareFields(PARSER);
+                PARSER.declareStringOrNull(optionalConstructorArg(), new ParseField("node"));
+            }
+
+            private @Nullable String nodeId;
+
+            Failure(final String index, final int shardId, final Throwable reason, final String nodeId) {
+                super(index, shardId, reason);
+                this.nodeId = nodeId;
+            }
+
+            public String getNodeId() {
+                return nodeId;
+            }
+        }
+    }
+}

+ 1 - 1
client/rest-high-level/src/main/java/org/elasticsearch/client/indices/FreezeIndexRequest.java

@@ -70,7 +70,7 @@ public final class FreezeIndexRequest extends TimedRequest {
     }
 
     /**
-     * Returns the wait for active shard cound or null if the default should be used
+     * Returns the wait for active shard count or null if the default should be used
      */
     public ActiveShardCount getWaitForActiveShards() {
         return waitForActiveShards;

+ 1 - 1
client/rest-high-level/src/test/java/org/elasticsearch/client/CCRIT.java

@@ -23,7 +23,6 @@ import org.apache.http.util.EntityUtils;
 import org.apache.logging.log4j.message.ParameterizedMessage;
 import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest;
 import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsResponse;
-import org.elasticsearch.action.admin.indices.close.CloseIndexRequest;
 import org.elasticsearch.action.index.IndexRequest;
 import org.elasticsearch.action.search.SearchRequest;
 import org.elasticsearch.action.search.SearchResponse;
@@ -49,6 +48,7 @@ import org.elasticsearch.client.ccr.ResumeFollowRequest;
 import org.elasticsearch.client.ccr.UnfollowRequest;
 import org.elasticsearch.client.core.AcknowledgedResponse;
 import org.elasticsearch.client.core.BroadcastResponse;
+import org.elasticsearch.client.indices.CloseIndexRequest;
 import org.elasticsearch.client.indices.CreateIndexRequest;
 import org.elasticsearch.client.indices.CreateIndexResponse;
 import org.elasticsearch.common.xcontent.XContentHelper;

+ 33 - 13
client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java

@@ -30,7 +30,6 @@ import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasA
 import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
 import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheRequest;
 import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheResponse;
-import org.elasticsearch.action.admin.indices.close.CloseIndexRequest;
 import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
 import org.elasticsearch.action.admin.indices.flush.FlushRequest;
 import org.elasticsearch.action.admin.indices.flush.FlushResponse;
@@ -58,6 +57,8 @@ import org.elasticsearch.action.support.master.AcknowledgedResponse;
 import org.elasticsearch.client.core.ShardsAcknowledgedResponse;
 import org.elasticsearch.client.indices.AnalyzeRequest;
 import org.elasticsearch.client.indices.AnalyzeResponse;
+import org.elasticsearch.client.indices.CloseIndexRequest;
+import org.elasticsearch.client.indices.CloseIndexResponse;
 import org.elasticsearch.client.indices.CreateIndexRequest;
 import org.elasticsearch.client.indices.CreateIndexResponse;
 import org.elasticsearch.client.indices.FreezeIndexRequest;
@@ -81,6 +82,7 @@ import org.elasticsearch.client.indices.rollover.RolloverResponse;
 import org.elasticsearch.cluster.metadata.AliasMetaData;
 import org.elasticsearch.cluster.metadata.IndexMetaData;
 import org.elasticsearch.cluster.metadata.MappingMetaData;
+import org.elasticsearch.common.Strings;
 import org.elasticsearch.common.ValidationException;
 import org.elasticsearch.common.bytes.BytesArray;
 import org.elasticsearch.common.settings.Setting;
@@ -127,6 +129,7 @@ import static org.hamcrest.Matchers.greaterThanOrEqualTo;
 import static org.hamcrest.Matchers.hasEntry;
 import static org.hamcrest.Matchers.hasItems;
 import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.not;
 import static org.hamcrest.Matchers.notNullValue;
 import static org.hamcrest.Matchers.nullValue;
@@ -872,20 +875,29 @@ public class IndicesClientIT extends ESRestHighLevelClientTestCase {
     }
 
     public void testCloseExistingIndex() throws IOException {
-        String index = "index";
-        createIndex(index, Settings.EMPTY);
-        Response response = client().performRequest(new Request(HttpGet.METHOD_NAME, index + "/_search"));
-        assertThat(response.getStatusLine().getStatusCode(), equalTo(RestStatus.OK.getStatus()));
+        final String[] indices = new String[randomIntBetween(1, 5)];
+        for (int i = 0; i < indices.length; i++) {
+            String index = "index-" + i;
+            createIndex(index, Settings.EMPTY);
+            indices[i] = index;
+        }
 
-        CloseIndexRequest closeIndexRequest = new CloseIndexRequest(index);
-        AcknowledgedResponse closeIndexResponse = execute(closeIndexRequest, highLevelClient().indices()::close,
-                highLevelClient().indices()::closeAsync);
+        CloseIndexRequest closeIndexRequest = new CloseIndexRequest(indices);
+        CloseIndexResponse closeIndexResponse = execute(closeIndexRequest,
+            highLevelClient().indices()::close, highLevelClient().indices()::closeAsync);
         assertTrue(closeIndexResponse.isAcknowledged());
-
-        ResponseException exception = expectThrows(ResponseException.class,
-                () -> client().performRequest(new Request(HttpGet.METHOD_NAME, index + "/_search")));
-        assertThat(exception.getResponse().getStatusLine().getStatusCode(), equalTo(RestStatus.BAD_REQUEST.getStatus()));
-        assertThat(exception.getMessage().contains(index), equalTo(true));
+        assertTrue(closeIndexResponse.isShardsAcknowledged());
+        assertThat(closeIndexResponse.getIndices(), notNullValue());
+        assertThat(closeIndexResponse.getIndices(), hasSize(indices.length));
+        closeIndexResponse.getIndices().forEach(indexResult -> {
+            assertThat(indexResult.getIndex(), startsWith("index-"));
+            assertThat(indexResult.hasFailures(), is(false));
+
+            ResponseException exception = expectThrows(ResponseException.class,
+                () -> client().performRequest(new Request(HttpGet.METHOD_NAME, indexResult.getIndex() + "/_search")));
+            assertThat(exception.getResponse().getStatusLine().getStatusCode(), equalTo(RestStatus.BAD_REQUEST.getStatus()));
+            assertThat(exception.getMessage().contains(indexResult.getIndex()), equalTo(true));
+        });
     }
 
     public void testCloseNonExistentIndex() throws IOException {
@@ -898,6 +910,14 @@ public class IndicesClientIT extends ESRestHighLevelClientTestCase {
         assertEquals(RestStatus.NOT_FOUND, exception.status());
     }
 
+    public void testCloseEmptyOrNullIndex() {
+        String[] indices = randomBoolean() ? Strings.EMPTY_ARRAY : null;
+        CloseIndexRequest closeIndexRequest = new CloseIndexRequest(indices);
+        org.elasticsearch.client.ValidationException exception = expectThrows(org.elasticsearch.client.ValidationException.class,
+            () -> execute(closeIndexRequest, highLevelClient().indices()::close, highLevelClient().indices()::closeAsync));
+        assertThat(exception.validationErrors().get(0), equalTo("index is missing"));
+    }
+
     public void testRefresh() throws IOException {
         {
             String index = "index";

+ 3 - 8
client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesRequestConvertersTests.java

@@ -30,7 +30,6 @@ import org.elasticsearch.action.admin.indices.alias.Alias;
 import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
 import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
 import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheRequest;
-import org.elasticsearch.action.admin.indices.close.CloseIndexRequest;
 import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
 import org.elasticsearch.action.admin.indices.flush.FlushRequest;
 import org.elasticsearch.action.admin.indices.flush.SyncedFlushRequest;
@@ -45,6 +44,7 @@ import org.elasticsearch.action.admin.indices.template.delete.DeleteIndexTemplat
 import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryRequest;
 import org.elasticsearch.action.support.master.AcknowledgedRequest;
 import org.elasticsearch.client.indices.AnalyzeRequest;
+import org.elasticsearch.client.indices.CloseIndexRequest;
 import org.elasticsearch.client.indices.CreateIndexRequest;
 import org.elasticsearch.client.indices.GetFieldMappingsRequest;
 import org.elasticsearch.client.indices.GetIndexRequest;
@@ -603,7 +603,8 @@ public class IndicesRequestConvertersTests extends ESTestCase {
         CloseIndexRequest closeIndexRequest = new CloseIndexRequest(indices);
 
         Map<String, String> expectedParams = new HashMap<>();
-        RequestConvertersTests.setRandomTimeout(closeIndexRequest::timeout, AcknowledgedRequest.DEFAULT_ACK_TIMEOUT, expectedParams);
+        RequestConvertersTests.setRandomTimeout(timeout -> closeIndexRequest.setTimeout(TimeValue.parseTimeValue(timeout, "test")),
+            AcknowledgedRequest.DEFAULT_ACK_TIMEOUT, expectedParams);
         RequestConvertersTests.setRandomMasterTimeout(closeIndexRequest, expectedParams);
         RequestConvertersTests.setRandomIndicesOptions(closeIndexRequest::indicesOptions, closeIndexRequest::indicesOptions,
             expectedParams);
@@ -616,12 +617,6 @@ public class IndicesRequestConvertersTests extends ESTestCase {
         Assert.assertThat(request.getEntity(), nullValue());
     }
 
-    public void testCloseIndexEmptyIndices() {
-        String[] indices = ESTestCase.randomBoolean() ? null : Strings.EMPTY_ARRAY;
-        ActionRequestValidationException validationException = new CloseIndexRequest(indices).validate();
-        Assert.assertNotNull(validationException);
-    }
-
     public void testRefresh() {
         String[] indices = ESTestCase.randomBoolean() ? null : RequestConvertersTests.randomIndicesNames(0, 5);
         RefreshRequest refreshRequest;

+ 1 - 1
client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/CCRDocumentationIT.java

@@ -24,7 +24,6 @@ import org.elasticsearch.action.ActionListener;
 import org.elasticsearch.action.LatchedActionListener;
 import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest;
 import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsResponse;
-import org.elasticsearch.action.admin.indices.close.CloseIndexRequest;
 import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
 import org.elasticsearch.action.support.ActiveShardCount;
 import org.elasticsearch.client.ESRestHighLevelClientTestCase;
@@ -53,6 +52,7 @@ import org.elasticsearch.client.ccr.ResumeFollowRequest;
 import org.elasticsearch.client.ccr.UnfollowRequest;
 import org.elasticsearch.client.core.AcknowledgedResponse;
 import org.elasticsearch.client.core.BroadcastResponse;
+import org.elasticsearch.client.indices.CloseIndexRequest;
 import org.elasticsearch.client.indices.CreateIndexRequest;
 import org.elasticsearch.client.indices.CreateIndexResponse;
 import org.elasticsearch.common.xcontent.XContentHelper;

+ 6 - 8
client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java

@@ -28,7 +28,6 @@ import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasA
 import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
 import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheRequest;
 import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheResponse;
-import org.elasticsearch.action.admin.indices.close.CloseIndexRequest;
 import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
 import org.elasticsearch.action.admin.indices.flush.FlushRequest;
 import org.elasticsearch.action.admin.indices.flush.FlushResponse;
@@ -62,6 +61,8 @@ import org.elasticsearch.client.core.BroadcastResponse.Shards;
 import org.elasticsearch.client.core.ShardsAcknowledgedResponse;
 import org.elasticsearch.client.indices.AnalyzeRequest;
 import org.elasticsearch.client.indices.AnalyzeResponse;
+import org.elasticsearch.client.indices.CloseIndexRequest;
+import org.elasticsearch.client.indices.CloseIndexResponse;
 import org.elasticsearch.client.indices.CreateIndexRequest;
 import org.elasticsearch.client.indices.CreateIndexResponse;
 import org.elasticsearch.client.indices.DetailAnalyzeResponse;
@@ -1458,12 +1459,10 @@ public class IndicesClientDocumentationIT extends ESRestHighLevelClientTestCase
             // end::close-index-request
 
             // tag::close-index-request-timeout
-            request.timeout(TimeValue.timeValueMinutes(2)); // <1>
-            request.timeout("2m"); // <2>
+            request.setTimeout(TimeValue.timeValueMinutes(2)); // <1>
             // end::close-index-request-timeout
             // tag::close-index-request-masterTimeout
-            request.masterNodeTimeout(TimeValue.timeValueMinutes(1)); // <1>
-            request.masterNodeTimeout("1m"); // <2>
+            request.setMasterTimeout(TimeValue.timeValueMinutes(1)); // <1>
             // end::close-index-request-masterTimeout
 
             // tag::close-index-request-indicesOptions
@@ -1480,10 +1479,9 @@ public class IndicesClientDocumentationIT extends ESRestHighLevelClientTestCase
             assertTrue(acknowledged);
 
             // tag::close-index-execute-listener
-            ActionListener<AcknowledgedResponse> listener =
-                    new ActionListener<AcknowledgedResponse>() {
+            ActionListener<CloseIndexResponse> listener = new ActionListener<>() {
                 @Override
-                public void onResponse(AcknowledgedResponse closeIndexResponse) {
+                public void onResponse(CloseIndexResponse closeIndexResponse) {
                     // <1>
                 }
 

+ 76 - 0
client/rest-high-level/src/test/java/org/elasticsearch/client/indices/CloseIndexRequestTests.java

@@ -0,0 +1,76 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch 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.elasticsearch.client.indices;
+
+import org.elasticsearch.action.support.ActiveShardCount;
+import org.elasticsearch.action.support.IndicesOptions;
+import org.elasticsearch.client.TimedRequest;
+import org.elasticsearch.client.ValidationException;
+import org.elasticsearch.common.Strings;
+import org.elasticsearch.common.unit.TimeValue;
+import org.elasticsearch.test.ESTestCase;
+
+import java.util.Optional;
+
+import static org.hamcrest.Matchers.equalTo;
+
+public class CloseIndexRequestTests extends ESTestCase {
+
+    public void testIndices() {
+        String[] indices = generateRandomStringArray(5, 5, false, true);
+        CloseIndexRequest request = new CloseIndexRequest(indices);
+        assertArrayEquals(indices, request.indices());
+    }
+
+    public void testValidate() {
+        String[] indices = randomBoolean() ? null : Strings.EMPTY_ARRAY;
+        CloseIndexRequest request = new CloseIndexRequest(indices);
+        Optional<ValidationException> validation = request.validate();
+        assertTrue(validation.isPresent());
+        assertThat(validation.get().validationErrors().get(0), equalTo("index is missing"));
+    }
+
+    public void testIndicesOptions() {
+        IndicesOptions indicesOptions = IndicesOptions.fromOptions(randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean());
+        CloseIndexRequest request = new CloseIndexRequest().indicesOptions(indicesOptions);
+        assertEquals(indicesOptions, request.indicesOptions());
+    }
+
+    public void testWaitForActiveShards() {
+        final CloseIndexRequest request = new CloseIndexRequest("index");
+        final int count = randomIntBetween(0, 10);
+        request.waitForActiveShards(ActiveShardCount.from(count));
+        assertEquals(request.waitForActiveShards(), ActiveShardCount.from(count));
+    }
+
+    public void testTimeout() {
+        final CloseIndexRequest request = new CloseIndexRequest("index");
+        assertEquals(request.timeout(), TimedRequest.DEFAULT_ACK_TIMEOUT);
+        assertEquals(request.masterNodeTimeout(), TimedRequest.DEFAULT_MASTER_NODE_TIMEOUT);
+
+        final TimeValue timeout = TimeValue.timeValueSeconds(randomIntBetween(0, 1000));
+        request.setTimeout(timeout);
+
+        final TimeValue masterTimeout = TimeValue.timeValueSeconds(randomIntBetween(0,1000));
+        request.setMasterTimeout(masterTimeout);
+
+        assertEquals(request.timeout(), timeout);
+        assertEquals(request.masterNodeTimeout(), masterTimeout);
+    }
+}

+ 221 - 0
client/rest-high-level/src/test/java/org/elasticsearch/client/indices/CloseIndexResponseTests.java

@@ -0,0 +1,221 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch 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.elasticsearch.client.indices;
+
+import org.elasticsearch.ElasticsearchStatusException;
+import org.elasticsearch.action.support.master.AcknowledgedResponse;
+import org.elasticsearch.action.support.master.ShardsAcknowledgedResponse;
+import org.elasticsearch.client.AbstractResponseTestCase;
+import org.elasticsearch.common.bytes.BytesReference;
+import org.elasticsearch.common.xcontent.LoggingDeprecationHandler;
+import org.elasticsearch.common.xcontent.NamedXContentRegistry;
+import org.elasticsearch.common.xcontent.XContent;
+import org.elasticsearch.common.xcontent.XContentFactory;
+import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.common.xcontent.XContentType;
+import org.elasticsearch.index.Index;
+import org.elasticsearch.index.IndexNotFoundException;
+import org.elasticsearch.rest.RestStatus;
+import org.elasticsearch.transport.ActionNotFoundTransportException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.hamcrest.Matchers.nullValue;
+
+public class CloseIndexResponseTests extends
+    AbstractResponseTestCase<org.elasticsearch.action.admin.indices.close.CloseIndexResponse, CloseIndexResponse> {
+
+    @Override
+    protected org.elasticsearch.action.admin.indices.close.CloseIndexResponse createServerTestInstance() {
+        boolean acknowledged = true;
+        final String[] indicesNames = generateRandomStringArray(10, 10, false, true);
+
+        final List<org.elasticsearch.action.admin.indices.close.CloseIndexResponse.IndexResult> indexResults = new ArrayList<>();
+        for (String indexName : indicesNames) {
+            final Index index = new Index(indexName, randomAlphaOfLength(5));
+            if (randomBoolean()) {
+                indexResults.add(new org.elasticsearch.action.admin.indices.close.CloseIndexResponse.IndexResult(index));
+            } else {
+                if (randomBoolean()) {
+                    acknowledged = false;
+                    Exception exception = randomFrom(new IndexNotFoundException(index), new ActionNotFoundTransportException("test"));
+                    indexResults.add(new org.elasticsearch.action.admin.indices.close.CloseIndexResponse.IndexResult(index, exception));
+                } else {
+                    final int nbShards = randomIntBetween(1, 5);
+                    org.elasticsearch.action.admin.indices.close.CloseIndexResponse.ShardResult[] shards =
+                        new org.elasticsearch.action.admin.indices.close.CloseIndexResponse.ShardResult[nbShards];
+                    for (int i = 0; i < nbShards; i++) {
+                        org.elasticsearch.action.admin.indices.close.CloseIndexResponse.ShardResult.Failure[] failures = null;
+                        if (randomBoolean()) {
+                            acknowledged = false;
+                            int nbFailures = randomIntBetween(1, 3);
+                            failures = new org.elasticsearch.action.admin.indices.close.CloseIndexResponse.ShardResult.Failure[nbFailures];
+                            for (int j = 0; j < failures.length; j++) {
+                                String nodeId = null;
+                                if (frequently()) {
+                                    nodeId = randomAlphaOfLength(5);
+                                }
+                                failures[j] = newFailure(indexName, i, nodeId);
+                            }
+                        }
+                        shards[i] = new org.elasticsearch.action.admin.indices.close.CloseIndexResponse.ShardResult(i, failures);
+                    }
+                    indexResults.add(new org.elasticsearch.action.admin.indices.close.CloseIndexResponse.IndexResult(index, shards));
+                }
+            }
+        }
+
+        final boolean shardsAcknowledged = acknowledged ? randomBoolean() : false;
+        return new org.elasticsearch.action.admin.indices.close.CloseIndexResponse(acknowledged, shardsAcknowledged, indexResults);
+    }
+
+    @Override
+    protected CloseIndexResponse doParseToClientInstance(final XContentParser parser) throws IOException {
+        return CloseIndexResponse.fromXContent(parser);
+    }
+
+    @Override
+    protected void assertInstances(final org.elasticsearch.action.admin.indices.close.CloseIndexResponse serverInstance,
+                                   final CloseIndexResponse clientInstance) {
+        assertNotSame(serverInstance, clientInstance);
+        assertThat(clientInstance.isAcknowledged(), equalTo(serverInstance.isAcknowledged()));
+        assertThat(clientInstance.isShardsAcknowledged(), equalTo(serverInstance.isShardsAcknowledged()));
+
+        assertThat(clientInstance.getIndices(), hasSize(serverInstance.getIndices().size()));
+        serverInstance.getIndices().forEach(expectedIndexResult -> {
+            List<CloseIndexResponse.IndexResult> actualIndexResults = clientInstance.getIndices().stream()
+                .filter(result -> result.getIndex().equals(expectedIndexResult.getIndex().getName()))
+                .collect(Collectors.toList());
+            assertThat(actualIndexResults, hasSize(1));
+
+            final CloseIndexResponse.IndexResult actualIndexResult = actualIndexResults.get(0);
+            assertThat(actualIndexResult.hasFailures(), equalTo(expectedIndexResult.hasFailures()));
+
+            if (expectedIndexResult.hasFailures() == false) {
+                assertThat(actualIndexResult.getException(), nullValue());
+                assertThat(actualIndexResult.getShards(), nullValue());
+            }
+            if (expectedIndexResult.getException() != null) {
+                assertThat(actualIndexResult.hasFailures(), is(true));
+                assertThat(actualIndexResult.getShards(), nullValue());
+                assertThat(actualIndexResult.getException(), notNullValue());
+                assertThat(actualIndexResult.getException().getMessage(), containsString(expectedIndexResult.getException().getMessage()));
+            }
+            if (expectedIndexResult.getShards() != null) {
+                assertThat(actualIndexResult.getException(), nullValue());
+
+                List<org.elasticsearch.action.admin.indices.close.CloseIndexResponse.ShardResult> failedShardResults =
+                    Arrays.stream(expectedIndexResult.getShards())
+                        .filter(org.elasticsearch.action.admin.indices.close.CloseIndexResponse.ShardResult::hasFailures)
+                        .collect(Collectors.toList());
+
+                if (failedShardResults.isEmpty()) {
+                    assertThat(actualIndexResult.hasFailures(), is(false));
+                    assertThat(actualIndexResult.getShards(), nullValue());
+                    return;
+                }
+
+                assertThat(actualIndexResult.hasFailures(), is(true));
+                assertThat(actualIndexResult.getShards(), notNullValue());
+                assertThat(actualIndexResult.getShards().length, equalTo(failedShardResults.size()));
+
+                failedShardResults.forEach(failedShardResult -> {
+                    List<CloseIndexResponse.ShardResult> actualShardResults = Arrays.stream(actualIndexResult.getShards())
+                        .filter(result -> result.getId() == failedShardResult.getId())
+                        .collect(Collectors.toList());
+                    assertThat(actualShardResults, hasSize(1));
+
+                    final CloseIndexResponse.ShardResult actualShardResult = actualShardResults.get(0);
+                    assertThat(actualShardResult.hasFailures(), is(true));
+                    assertThat(actualShardResult.getFailures(), notNullValue());
+                    assertThat(actualShardResult.getFailures().length, equalTo(failedShardResult.getFailures().length));
+
+                    for (int i = 0; i < failedShardResult.getFailures().length; i++) {
+                        org.elasticsearch.action.admin.indices.close.CloseIndexResponse.ShardResult.Failure expectedFailure =
+                            failedShardResult.getFailures()[i];
+                        CloseIndexResponse.ShardResult.Failure actualFailure = actualShardResult.getFailures()[i];
+                        assertThat(actualFailure.getNodeId(), equalTo(expectedFailure.getNodeId()));
+                        assertThat(actualFailure.index(), equalTo(expectedFailure.index()));
+                        assertThat(actualFailure.shardId(), equalTo(expectedFailure.shardId()));
+                        assertThat(actualFailure.getCause().getMessage(), containsString(expectedFailure.getCause().getMessage()));
+                    }
+                });
+            }
+        });
+    }
+
+    public final void testBwcFromXContent() throws IOException {
+        {
+            final boolean acknowledged = randomBoolean();
+            final AcknowledgedResponse expected = new AcknowledgedResponse(acknowledged);
+
+            final XContentType xContentType = randomFrom(XContentType.values());
+            final BytesReference bytes = toShuffledXContent(expected, xContentType, getParams(), randomBoolean());
+            final XContent xContent = XContentFactory.xContent(xContentType);
+            final XContentParser parser = xContent.createParser(
+                NamedXContentRegistry.EMPTY,
+                LoggingDeprecationHandler.INSTANCE,
+                bytes.streamInput());
+
+            final CloseIndexResponse actual = doParseToClientInstance(parser);
+            assertThat(actual, notNullValue());
+            assertThat(actual.isAcknowledged(), equalTo(expected.isAcknowledged()));
+            assertThat(actual.isShardsAcknowledged(), equalTo(expected.isAcknowledged()));
+            assertThat(actual.getIndices(), hasSize(0));
+        }
+        {
+            final boolean acknowledged = randomBoolean();
+            final boolean shardsAcknowledged = acknowledged ? randomBoolean() : false;
+            final ShardsAcknowledgedResponse expected = new ShardsAcknowledgedResponse(acknowledged, shardsAcknowledged){};
+
+            final XContentType xContentType = randomFrom(XContentType.values());
+            final BytesReference bytes = toShuffledXContent(expected, xContentType, getParams(), randomBoolean());
+            final XContent xContent = XContentFactory.xContent(xContentType);
+            final XContentParser parser = xContent.createParser(
+                NamedXContentRegistry.EMPTY,
+                LoggingDeprecationHandler.INSTANCE,
+                bytes.streamInput());
+
+            final CloseIndexResponse actual = doParseToClientInstance(parser);
+            assertThat(actual, notNullValue());
+            assertThat(actual.isAcknowledged(), equalTo(expected.isAcknowledged()));
+            assertThat(actual.isShardsAcknowledged(), equalTo(expected.isShardsAcknowledged()));
+            assertThat(actual.getIndices(), hasSize(0));
+        }
+    }
+
+    private org.elasticsearch.action.admin.indices.close.CloseIndexResponse.ShardResult.Failure newFailure(final String indexName,
+                                                                                                           final int shard,
+                                                                                                           final String nodeId) {
+        Exception exception = randomFrom(new IndexNotFoundException(indexName),
+            new ActionNotFoundTransportException("test"),
+            new IOException("boom", new NullPointerException()),
+            new ElasticsearchStatusException("something", RestStatus.TOO_MANY_REQUESTS));
+        return new org.elasticsearch.action.admin.indices.close.CloseIndexResponse.ShardResult.Failure(indexName, shard, exception, nodeId);
+    }
+}

+ 0 - 3
docs/java-rest/high-level/indices/close_index.asciidoc

@@ -27,15 +27,12 @@ include-tagged::{doc-tests-file}[{api}-request-timeout]
 --------------------------------------------------
 <1> Timeout to wait for the all the nodes to acknowledge the index is closed
 as a `TimeValue`
-<2> Timeout to wait for the all the nodes to acknowledge the index is closed
-as a `String`
 
 ["source","java",subs="attributes,callouts,macros"]
 --------------------------------------------------
 include-tagged::{doc-tests-file}[{api}-request-masterTimeout]
 --------------------------------------------------
 <1> Timeout to connect to the master node as a `TimeValue`
-<2> Timeout to connect to the master node as a `String`
 
 ["source","java",subs="attributes,callouts,macros"]
 --------------------------------------------------

+ 1 - 2
libs/x-content/src/main/java/org/elasticsearch/common/xcontent/AbstractObjectParser.java

@@ -179,8 +179,7 @@ public abstract class AbstractObjectParser<Value, Context>
         declareField(consumer, XContentParser::booleanValue, field, ValueType.BOOLEAN);
     }
 
-    public <T> void declareObjectArray(BiConsumer<Value, List<T>> consumer, ContextParser<Context, T> objectParser,
-            ParseField field) {
+    public <T> void declareObjectArray(BiConsumer<Value, List<T>> consumer, ContextParser<Context, T> objectParser, ParseField field) {
         declareFieldArray(consumer, (p, c) -> objectParser.parse(p, c), field, ValueType.OBJECT_ARRAY);
     }
 

+ 7 - 3
server/src/main/java/org/elasticsearch/action/support/DefaultShardOperationFailedException.java

@@ -45,10 +45,14 @@ public class DefaultShardOperationFailedException extends ShardOperationFailedEx
     public static final ConstructingObjectParser<DefaultShardOperationFailedException, Void> PARSER = new ConstructingObjectParser<>(
         "failures", true, arg -> new DefaultShardOperationFailedException((String) arg[0], (int) arg[1] ,(Throwable) arg[2]));
 
+    protected static <T extends DefaultShardOperationFailedException> void declareFields(ConstructingObjectParser<T, Void> objectParser) {
+        objectParser.declareString(constructorArg(), new ParseField(INDEX));
+        objectParser.declareInt(constructorArg(), new ParseField(SHARD_ID));
+        objectParser.declareObject(constructorArg(), (p, c) -> ElasticsearchException.fromXContent(p), new ParseField(REASON));
+    }
+
     static {
-        PARSER.declareString(constructorArg(), new ParseField(INDEX));
-        PARSER.declareInt(constructorArg(), new ParseField(SHARD_ID));
-        PARSER.declareObject(constructorArg(), (p, c) -> ElasticsearchException.fromXContent(p), new ParseField(REASON));
+        declareFields(PARSER);
     }
 
     protected DefaultShardOperationFailedException() {}

+ 1 - 1
server/src/main/java/org/elasticsearch/action/support/master/ShardsAcknowledgedResponse.java

@@ -33,7 +33,7 @@ import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constru
 
 public abstract class ShardsAcknowledgedResponse extends AcknowledgedResponse {
 
-    private static final ParseField SHARDS_ACKNOWLEDGED = new ParseField("shards_acknowledged");
+    protected static final ParseField SHARDS_ACKNOWLEDGED = new ParseField("shards_acknowledged");
 
     protected static <T extends ShardsAcknowledgedResponse> void declareAcknowledgedAndShardsAcknowledgedFields(
             ConstructingObjectParser<T, Void> objectParser) {

+ 77 - 76
server/src/test/java/org/elasticsearch/action/admin/indices/close/CloseIndexResponseTests.java

@@ -27,13 +27,14 @@ import org.elasticsearch.action.support.master.AcknowledgedResponse;
 import org.elasticsearch.common.Strings;
 import org.elasticsearch.common.io.stream.BytesStreamOutput;
 import org.elasticsearch.common.io.stream.StreamInput;
+import org.elasticsearch.common.io.stream.Writeable;
 import org.elasticsearch.common.xcontent.ToXContent;
 import org.elasticsearch.common.xcontent.XContentBuilder;
 import org.elasticsearch.common.xcontent.XContentType;
 import org.elasticsearch.index.Index;
 import org.elasticsearch.index.IndexNotFoundException;
 import org.elasticsearch.index.shard.ShardId;
-import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.test.AbstractWireSerializingTestCase;
 import org.elasticsearch.transport.ActionNotFoundTransportException;
 
 import java.io.IOException;
@@ -51,7 +52,80 @@ import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.notNullValue;
 import static org.hamcrest.Matchers.nullValue;
 
-public class CloseIndexResponseTests extends ESTestCase {
+public class CloseIndexResponseTests extends AbstractWireSerializingTestCase<CloseIndexResponse> {
+
+    @Override
+    protected CloseIndexResponse createTestInstance() {
+        return randomResponse();
+    }
+
+    @Override
+    protected Writeable.Reader<CloseIndexResponse> instanceReader() {
+        return CloseIndexResponse::new;
+    }
+
+    @Override
+    protected void assertEqualInstances(CloseIndexResponse expected, CloseIndexResponse actual) {
+        assertNotSame(expected, actual);
+        assertThat(actual.isAcknowledged(), equalTo(expected.isAcknowledged()));
+        assertThat(actual.isShardsAcknowledged(), equalTo(expected.isShardsAcknowledged()));
+
+        for (int i = 0; i < expected.getIndices().size(); i++) {
+            CloseIndexResponse.IndexResult expectedIndexResult = expected.getIndices().get(i);
+            CloseIndexResponse.IndexResult actualIndexResult = actual.getIndices().get(i);
+            assertNotSame(expectedIndexResult, actualIndexResult);
+            assertThat(actualIndexResult.getIndex(), equalTo(expectedIndexResult.getIndex()));
+            assertThat(actualIndexResult.hasFailures(), equalTo(expectedIndexResult.hasFailures()));
+
+            if (expectedIndexResult.hasFailures() == false) {
+                assertThat(actualIndexResult.getException(), nullValue());
+                if (actualIndexResult.getShards() != null) {
+                    assertThat(Arrays.stream(actualIndexResult.getShards())
+                        .allMatch(shardResult -> shardResult.hasFailures() == false), is(true));
+                }
+            }
+
+            if (expectedIndexResult.getException() != null) {
+                assertThat(actualIndexResult.getShards(), nullValue());
+                assertThat(actualIndexResult.getException(), notNullValue());
+                assertThat(actualIndexResult.getException().getMessage(), equalTo(expectedIndexResult.getException().getMessage()));
+                assertThat(actualIndexResult.getException().getClass(), equalTo(expectedIndexResult.getException().getClass()));
+                assertArrayEquals(actualIndexResult.getException().getStackTrace(), expectedIndexResult.getException().getStackTrace());
+            } else {
+                assertThat(actualIndexResult.getException(), nullValue());
+            }
+
+            if (expectedIndexResult.getShards() != null) {
+                assertThat(actualIndexResult.getShards().length, equalTo(expectedIndexResult.getShards().length));
+
+                for (int j = 0; j < expectedIndexResult.getShards().length; j++) {
+                    CloseIndexResponse.ShardResult expectedShardResult = expectedIndexResult.getShards()[j];
+                    CloseIndexResponse.ShardResult actualShardResult = actualIndexResult.getShards()[j];
+                    assertThat(actualShardResult.getId(), equalTo(expectedShardResult.getId()));
+                    assertThat(actualShardResult.hasFailures(), equalTo(expectedShardResult.hasFailures()));
+
+                    if (expectedShardResult.hasFailures()) {
+                        assertThat(actualShardResult.getFailures().length, equalTo(expectedShardResult.getFailures().length));
+
+                        for (int k = 0; k < expectedShardResult.getFailures().length; k++) {
+                            CloseIndexResponse.ShardResult.Failure expectedFailure = expectedShardResult.getFailures()[k];
+                            CloseIndexResponse.ShardResult.Failure actualFailure = actualShardResult.getFailures()[k];
+                            assertThat(actualFailure.getNodeId(), equalTo(expectedFailure.getNodeId()));
+                            assertThat(actualFailure.index(), equalTo(expectedFailure.index()));
+                            assertThat(actualFailure.shardId(), equalTo(expectedFailure.shardId()));
+                            assertThat(actualFailure.getCause().getMessage(), equalTo(expectedFailure.getCause().getMessage()));
+                            assertThat(actualFailure.getCause().getClass(), equalTo(expectedFailure.getCause().getClass()));
+                            assertArrayEquals(actualFailure.getCause().getStackTrace(), expectedFailure.getCause().getStackTrace());
+                        }
+                    } else {
+                        assertThat(actualShardResult.getFailures(), nullValue());
+                    }
+                }
+            } else {
+                assertThat(actualIndexResult.getShards(), nullValue());
+            }
+        }
+    }
 
     /**
      * Test that random responses can be written to xcontent without errors.
@@ -85,18 +159,6 @@ public class CloseIndexResponseTests extends ESTestCase {
                 Strings.toString(closeIndexResponse));
     }
 
-    public void testSerialization() throws Exception {
-        final CloseIndexResponse response = randomResponse();
-        try (BytesStreamOutput out = new BytesStreamOutput()) {
-            response.writeTo(out);
-
-            try (StreamInput in = out.bytes().streamInput()) {
-                final CloseIndexResponse deserializedResponse = new CloseIndexResponse(in);
-                assertCloseIndexResponse(deserializedResponse, response);
-            }
-        }
-    }
-
     public void testBwcSerialization() throws Exception {
         {
             final CloseIndexResponse response = randomResponse();
@@ -150,7 +212,7 @@ public class CloseIndexResponseTests extends ESTestCase {
 
         final List<CloseIndexResponse.IndexResult> indexResults = new ArrayList<>();
         for (String indexName : indicesNames) {
-            final Index index = new Index(indexName, "_na_");
+            final Index index = new Index(indexName, randomAlphaOfLength(5));
             if (randomBoolean()) {
                 indexResults.add(new CloseIndexResponse.IndexResult(index));
             } else {
@@ -178,7 +240,6 @@ public class CloseIndexResponseTests extends ESTestCase {
                     indexResults.add(new CloseIndexResponse.IndexResult(index, shards));
                 }
             }
-
         }
 
         final boolean shardsAcknowledged = acknowledged ? randomBoolean() : false;
@@ -191,64 +252,4 @@ public class CloseIndexResponseTests extends ESTestCase {
             new ActionNotFoundTransportException("test"),
             new NoShardAvailableActionException(new ShardId(index, id)));
     }
-
-    private static void assertCloseIndexResponse(final CloseIndexResponse actual, final CloseIndexResponse expected) {
-        assertThat(actual.isAcknowledged(), equalTo(expected.isAcknowledged()));
-        assertThat(actual.isShardsAcknowledged(), equalTo(expected.isShardsAcknowledged()));
-
-        for (int i = 0; i < expected.getIndices().size(); i++) {
-            CloseIndexResponse.IndexResult expectedIndexResult = expected.getIndices().get(i);
-            CloseIndexResponse.IndexResult actualIndexResult = actual.getIndices().get(i);
-            assertThat(actualIndexResult.getIndex(), equalTo(expectedIndexResult.getIndex()));
-            assertThat(actualIndexResult.hasFailures(), equalTo(expectedIndexResult.hasFailures()));
-
-            if (expectedIndexResult.hasFailures() == false) {
-                assertThat(actualIndexResult.getException(), nullValue());
-                if (actualIndexResult.getShards() != null) {
-                    assertThat(Arrays.stream(actualIndexResult.getShards())
-                        .allMatch(shardResult -> shardResult.hasFailures() == false), is(true));
-                }
-            }
-
-            if (expectedIndexResult.getException() != null) {
-                assertThat(actualIndexResult.getShards(), nullValue());
-                assertThat(actualIndexResult.getException(), notNullValue());
-                assertThat(actualIndexResult.getException().getMessage(), equalTo(expectedIndexResult.getException().getMessage()));
-                assertThat(actualIndexResult.getException().getClass(), equalTo(expectedIndexResult.getException().getClass()));
-                assertArrayEquals(actualIndexResult.getException().getStackTrace(), expectedIndexResult.getException().getStackTrace());
-            } else {
-                assertThat(actualIndexResult.getException(), nullValue());
-            }
-
-            if (expectedIndexResult.getShards() != null) {
-                assertThat(actualIndexResult.getShards().length, equalTo(expectedIndexResult.getShards().length));
-
-                for (int j = 0; j < expectedIndexResult.getShards().length; j++) {
-                    CloseIndexResponse.ShardResult expectedShardResult = expectedIndexResult.getShards()[j];
-                    CloseIndexResponse.ShardResult actualShardResult = actualIndexResult.getShards()[j];
-                    assertThat(actualShardResult.getId(), equalTo(expectedShardResult.getId()));
-                    assertThat(actualShardResult.hasFailures(), equalTo(expectedShardResult.hasFailures()));
-
-                    if (expectedShardResult.hasFailures()) {
-                        assertThat(actualShardResult.getFailures().length, equalTo(expectedShardResult.getFailures().length));
-
-                        for (int k = 0; k < expectedShardResult.getFailures().length; k++) {
-                            CloseIndexResponse.ShardResult.Failure expectedFailure = expectedShardResult.getFailures()[k];
-                            CloseIndexResponse.ShardResult.Failure actualFailure = actualShardResult.getFailures()[k];
-                            assertThat(actualFailure.getNodeId(), equalTo(expectedFailure.getNodeId()));
-                            assertThat(actualFailure.index(), equalTo(expectedFailure.index()));
-                            assertThat(actualFailure.shardId(), equalTo(expectedFailure.shardId()));
-                            assertThat(actualFailure.getCause().getMessage(), equalTo(expectedFailure.getCause().getMessage()));
-                            assertThat(actualFailure.getCause().getClass(), equalTo(expectedFailure.getCause().getClass()));
-                            assertArrayEquals(actualFailure.getCause().getStackTrace(), expectedFailure.getCause().getStackTrace());
-                        }
-                    } else {
-                        assertThat(actualShardResult.getFailures(), nullValue());
-                    }
-                }
-            } else {
-                assertThat(actualIndexResult.getShards(), nullValue());
-            }
-        }
-    }
 }