/*
* 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.update;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.index.IndexResponseTests;
import org.elasticsearch.action.support.replication.ReplicationResponse;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.get.GetField;
import org.elasticsearch.index.get.GetResult;
import org.elasticsearch.index.get.GetResultTests;
import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.RandomObjects;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import static org.elasticsearch.action.DocWriteResponse.Result.DELETED;
import static org.elasticsearch.action.DocWriteResponse.Result.NOT_FOUND;
import static org.elasticsearch.action.DocWriteResponse.Result.UPDATED;
import static org.elasticsearch.cluster.metadata.IndexMetaData.INDEX_UUID_NA_VALUE;
public class UpdateResponseTests extends ESTestCase {
public void testToXContent() throws IOException {
{
UpdateResponse updateResponse = new UpdateResponse(new ShardId("index", "index_uuid", 0), "type", "id", 0, NOT_FOUND);
String output = Strings.toString(updateResponse);
assertEquals("{\"_index\":\"index\",\"_type\":\"type\",\"_id\":\"id\",\"_version\":0,\"result\":\"not_found\"," +
"\"_shards\":{\"total\":0,\"successful\":0,\"failed\":0}}", output);
}
{
UpdateResponse updateResponse = new UpdateResponse(new ReplicationResponse.ShardInfo(10, 6),
new ShardId("index", "index_uuid", 1), "type", "id", 3, 17, 1, DELETED);
String output = Strings.toString(updateResponse);
assertEquals("{\"_index\":\"index\",\"_type\":\"type\",\"_id\":\"id\",\"_version\":1,\"result\":\"deleted\"," +
"\"_shards\":{\"total\":10,\"successful\":6,\"failed\":0},\"_seq_no\":3,\"_primary_term\":17}", output);
}
{
BytesReference source = new BytesArray("{\"title\":\"Book title\",\"isbn\":\"ABC-123\"}");
Map<String, GetField> fields = new HashMap<>();
fields.put("title", new GetField("title", Collections.singletonList("Book title")));
fields.put("isbn", new GetField("isbn", Collections.singletonList("ABC-123")));
UpdateResponse updateResponse = new UpdateResponse(new ReplicationResponse.ShardInfo(3, 2),
new ShardId("books", "books_uuid", 2), "book", "1", 7, 17, 2, UPDATED);
updateResponse.setGetResult(new GetResult("books", "book", "1", 2, true, source, fields));
String output = Strings.toString(updateResponse);
assertEquals("{\"_index\":\"books\",\"_type\":\"book\",\"_id\":\"1\",\"_version\":2,\"result\":\"updated\"," +
"\"_shards\":{\"total\":3,\"successful\":2,\"failed\":0},\"_seq_no\":7,\"_primary_term\":17,\"get\":{\"found\":true," +
"\"_source\":{\"title\":\"Book title\",\"isbn\":\"ABC-123\"},\"fields\":{\"isbn\":[\"ABC-123\"],\"title\":[\"Book " +
"title\"]}}}", output);
}
}
public void testToAndFromXContent() throws IOException {
final XContentType xContentType = randomFrom(XContentType.values());
final Tuple<UpdateResponse, UpdateResponse> tuple = randomUpdateResponse(xContentType);
UpdateResponse updateResponse = tuple.v1();
UpdateResponse expectedUpdateResponse = tuple.v2();
boolean humanReadable = randomBoolean();
BytesReference updateResponseBytes = toShuffledXContent(updateResponse, xContentType, ToXContent.EMPTY_PARAMS, humanReadable);
UpdateResponse parsedUpdateResponse;
try (XContentParser parser = createParser(xContentType.xContent(), updateResponseBytes)) {
parsedUpdateResponse = UpdateResponse.fromXContent(parser);
assertNull(parser.nextToken());
}
// 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.
assertUpdateResponse(expectedUpdateResponse, parsedUpdateResponse);
}
public static void assertUpdateResponse(UpdateResponse expected, UpdateResponse actual) {
IndexResponseTests.assertDocWriteResponse(expected, actual);
assertEquals(expected.getGetResult(), actual.getGetResult());
}
/**
* Returns a tuple of {@link UpdateResponse}s.
* <p>
* The left element is the actual {@link UpdateResponse} to serialize while the right element is the
* expected {@link UpdateResponse} after parsing.
*/
public static Tuple<UpdateResponse, UpdateResponse> randomUpdateResponse(XContentType xContentType) {
Tuple<GetResult, GetResult> getResults = GetResultTests.randomGetResult(xContentType);
GetResult actualGetResult = getResults.v1();
GetResult expectedGetResult = getResults.v2();
String index = actualGetResult.getIndex();
String type = actualGetResult.getType();
String id = actualGetResult.getId();
long version = actualGetResult.getVersion();
DocWriteResponse.Result result = actualGetResult.isExists() ? DocWriteResponse.Result.UPDATED : DocWriteResponse.Result.NOT_FOUND;
String indexUUid = randomAlphaOfLength(5);
int shardId = randomIntBetween(0, 5);
// We also want small number values (randomNonNegativeLong() tend to generate high numbers)
// in order to catch some conversion error that happen between int/long after parsing.
Long seqNo = randomFrom(randomNonNegativeLong(), (long) randomIntBetween(0, 10_000), null);
long primaryTerm = seqNo == null ? 0 : randomIntBetween(1, 16);
ShardId actualShardId = new ShardId(index, indexUUid, shardId);
ShardId expectedShardId = new ShardId(index, INDEX_UUID_NA_VALUE, -1);
UpdateResponse actual, expected;
if (seqNo != null) {
Tuple<ReplicationResponse.ShardInfo, ReplicationResponse.ShardInfo> shardInfos = RandomObjects.randomShardInfo(random());
actual = new UpdateResponse(shardInfos.v1(), actualShardId, type, id, seqNo, primaryTerm, version, result);
expected = new UpdateResponse(shardInfos.v2(), expectedShardId, type, id, seqNo, primaryTerm, version, result);
} else {
actual = new UpdateResponse(actualShardId, type, id, version, result);
expected = new UpdateResponse(expectedShardId, type, id, version, result);
}
if (actualGetResult.isExists()) {
actual.setGetResult(actualGetResult);
}
if (expectedGetResult.isExists()) {
expected.setGetResult(expectedGetResult);
}
boolean forcedRefresh = randomBoolean();
actual.setForcedRefresh(forcedRefresh);
expected.setForcedRefresh(forcedRefresh);
return Tuple.tuple(actual, expected);
}
}