From e1425e29ee244ef1916f6e1e6931a7f4e78b3d78 Mon Sep 17 00:00:00 2001 From: David Pilato Date: Fri, 20 Jan 2017 09:46:58 +0100 Subject: [PATCH 1/2] Add fromxcontent methods to delete response This commit adds the parsing fromXContent() methods to the DeleteResponse class. The method is based on a ObjectParser because it is easier to use when parsing parent abstract classes like DocWriteResponse. It also changes the ReplicationResponse.ShardInfo so that it now implements ToXContentObject. This way, the ShardInfo.fromXContent() method can be used by the DeleteResponse's ObjectParser. Backport of #22680 in 5.x branch --- .../action/delete/DeleteResponse.java | 34 +++++- .../action/delete/DeleteResponseTests.java | 105 ++++++++++++++++++ 2 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 core/src/test/java/org/elasticsearch/action/delete/DeleteResponseTests.java diff --git a/core/src/main/java/org/elasticsearch/action/delete/DeleteResponse.java b/core/src/main/java/org/elasticsearch/action/delete/DeleteResponse.java index 9051989a8a560..ac086a8c8b4e7 100644 --- a/core/src/main/java/org/elasticsearch/action/delete/DeleteResponse.java +++ b/core/src/main/java/org/elasticsearch/action/delete/DeleteResponse.java @@ -20,12 +20,19 @@ package org.elasticsearch.action.delete; import org.elasticsearch.action.DocWriteResponse; +import org.elasticsearch.cluster.metadata.IndexMetaData; +import org.elasticsearch.common.ParseField; +import org.elasticsearch.common.xcontent.ConstructingObjectParser; import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.index.Index; import org.elasticsearch.index.shard.ShardId; import org.elasticsearch.rest.RestStatus; import java.io.IOException; +import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg; + /** * The response of the delete action. * @@ -34,6 +41,8 @@ */ public class DeleteResponse extends DocWriteResponse { + private static final String FOUND = "found"; + public DeleteResponse() { } @@ -49,11 +58,34 @@ public RestStatus status() { @Override public XContentBuilder innerToXContent(XContentBuilder builder, Params params) throws IOException { - builder.field("found", result == Result.DELETED); + builder.field(FOUND, result == Result.DELETED); super.innerToXContent(builder, params); return builder; } + private static final ConstructingObjectParser PARSER; + static { + PARSER = new ConstructingObjectParser<>(DeleteResponse.class.getName(), + args -> { + // index uuid and shard id are unknown and can't be parsed back for now. + ShardId shardId = new ShardId(new Index((String) args[0], IndexMetaData.INDEX_UUID_NA_VALUE), -1); + String type = (String) args[1]; + String id = (String) args[2]; + long version = (long) args[3]; + ShardInfo shardInfo = (ShardInfo) args[5]; + boolean found = (boolean) args[6]; + DeleteResponse deleteResponse = new DeleteResponse(shardId, type, id, version, found); + deleteResponse.setShardInfo(shardInfo); + return deleteResponse; + }); + DocWriteResponse.declareParserFields(PARSER); + PARSER.declareBoolean(constructorArg(), new ParseField(FOUND)); + } + + public static DeleteResponse fromXContent(XContentParser parser) throws IOException { + return PARSER.apply(parser, null); + } + @Override public String toString() { StringBuilder builder = new StringBuilder(); diff --git a/core/src/test/java/org/elasticsearch/action/delete/DeleteResponseTests.java b/core/src/test/java/org/elasticsearch/action/delete/DeleteResponseTests.java new file mode 100644 index 0000000000000..5a5d1dd1a1304 --- /dev/null +++ b/core/src/test/java/org/elasticsearch/action/delete/DeleteResponseTests.java @@ -0,0 +1,105 @@ +/* + * 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.action.delete; + +import org.elasticsearch.action.DocWriteResponse; +import org.elasticsearch.action.support.replication.ReplicationResponse; +import org.elasticsearch.common.Strings; +import org.elasticsearch.common.bytes.BytesReference; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.index.shard.ShardId; +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.test.RandomObjects; + +import java.io.IOException; +import java.util.Map; + +import static org.elasticsearch.action.index.IndexResponseTests.assertDocWriteResponse; +import static org.elasticsearch.common.xcontent.XContentHelper.toXContent; + +public class DeleteResponseTests extends ESTestCase { + + public void testToXContent() throws IOException { + { + DeleteResponse response = new DeleteResponse(new ShardId("index", "index_uuid", 0), "type", "id", 5, true); + String output = Strings.toString(response); + assertEquals("{\"found\":true,\"_index\":\"index\",\"_type\":\"type\",\"_id\":\"id\",\"_version\":5,\"result\":\"deleted\"," + + "\"_shards\":null}", output); + } + { + DeleteResponse response = new DeleteResponse(new ShardId("index", "index_uuid", 0), "type", "id", 7, true); + response.setForcedRefresh(true); + response.setShardInfo(new ReplicationResponse.ShardInfo(10, 5)); + String output = Strings.toString(response); + assertEquals("{\"found\":true,\"_index\":\"index\",\"_type\":\"type\",\"_id\":\"id\",\"_version\":7,\"result\":\"deleted\"," + + "\"forced_refresh\":true,\"_shards\":{\"total\":10,\"successful\":5,\"failed\":0}}", output); + } + } + + public void testToAndFromXContent() throws IOException { + final XContentType xContentType = randomFrom(XContentType.values()); + + // Create a random DeleteResponse and converts it to XContent in bytes + DeleteResponse deleteResponse = randomDeleteResponse(); + BytesReference deleteResponseBytes = toXContent(deleteResponse, xContentType); + + // Parse the XContent bytes to obtain a parsed + DeleteResponse parsedDeleteResponse; + try (XContentParser parser = createParser(xContentType.xContent(), deleteResponseBytes)) { + parsedDeleteResponse = DeleteResponse.fromXContent(parser); + assertNull(parser.nextToken()); + } + + // We can't use equals() to compare the original and the parsed index response + // because the random index response can contain shard failures with exceptions, + // and those exceptions are not parsed back with the same types. + + // Print the parsed object out and test that the output is the same as the original output + BytesReference parsedDeleteResponseBytes = toXContent(parsedDeleteResponse, xContentType); + try (XContentParser parser = createParser(xContentType.xContent(), parsedDeleteResponseBytes)) { + assertDeleteResponse(deleteResponse, parser.map()); + } + } + + private static void assertDeleteResponse(DeleteResponse expected, Map actual) { + assertDocWriteResponse(expected, actual); + if (expected.getResult() == DocWriteResponse.Result.DELETED) { + assertTrue((boolean) actual.get("found")); + } else { + assertFalse((boolean) actual.get("found")); + } + } + + private static DeleteResponse randomDeleteResponse() { + ShardId shardId = new ShardId(randomAsciiOfLength(5), randomAsciiOfLength(5), randomIntBetween(0, 5)); + String type = randomAsciiOfLength(5); + String id = randomAsciiOfLength(5); + long seqNo = randomIntBetween(-2, 5); + long version = (long) randomIntBetween(0, 5); + boolean found = randomBoolean(); + + DeleteResponse response = new DeleteResponse(shardId, type, id, version, found); + response.setForcedRefresh(randomBoolean()); + response.setShardInfo(RandomObjects.randomShardInfo(random(), randomBoolean())); + return response; + } + +} From b4851e8b3347751b9daa8f6bbf3d85814a9d8e55 Mon Sep 17 00:00:00 2001 From: David Pilato Date: Fri, 20 Jan 2017 10:10:12 +0100 Subject: [PATCH 2/2] Fix comment and remove non needed seq number --- .../org/elasticsearch/action/delete/DeleteResponseTests.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/core/src/test/java/org/elasticsearch/action/delete/DeleteResponseTests.java b/core/src/test/java/org/elasticsearch/action/delete/DeleteResponseTests.java index 5a5d1dd1a1304..a170fb7659e38 100644 --- a/core/src/test/java/org/elasticsearch/action/delete/DeleteResponseTests.java +++ b/core/src/test/java/org/elasticsearch/action/delete/DeleteResponseTests.java @@ -68,8 +68,8 @@ public void testToAndFromXContent() throws IOException { assertNull(parser.nextToken()); } - // We can't use equals() to compare the original and the parsed index response - // because the random index response can contain shard failures with exceptions, + // We can't use equals() to compare the original and the parsed delete response + // because the random delete response can contain shard failures with exceptions, // and those exceptions are not parsed back with the same types. // Print the parsed object out and test that the output is the same as the original output @@ -92,7 +92,6 @@ private static DeleteResponse randomDeleteResponse() { ShardId shardId = new ShardId(randomAsciiOfLength(5), randomAsciiOfLength(5), randomIntBetween(0, 5)); String type = randomAsciiOfLength(5); String id = randomAsciiOfLength(5); - long seqNo = randomIntBetween(-2, 5); long version = (long) randomIntBetween(0, 5); boolean found = randomBoolean();