From 15d58d91f1abb75764428fdb5e436edbe0f4181d Mon Sep 17 00:00:00 2001 From: Simon Willnauer Date: Fri, 24 Apr 2015 09:36:10 +0200 Subject: [PATCH] [REST] Render REST errors in a structural way This commit adds support for structural errors / failures / exceptions on the elasticsearch REST layer. Exceptions are rendering with at least a `type` and a `reason` corresponding to the exception name and the message. Some expcetions like the ones associated with an index or a shard will have additional information about the index the exception was triggered on or the shard respectivly. Each rendered response will also contain a list of root causes which is a list of distinct shard level errors returned for the request. Root causes are the lowest level elasticsearch exception found per shard response and are intended to be displayed to the user to indicate the soruce of the exception. Shard level response are by-default grouped by their type and reason to reduce the amount of duplicates retunred. Yet, the same exception retunred from different indices will not be grouped. Closes #3303 --- rest-api-spec/test/create/50_parent.yaml | 2 +- rest-api-spec/test/create/75_ttl.yaml | 2 +- .../test/delete/42_missing_parent.yml | 2 +- rest-api-spec/test/index/50_parent.yaml | 2 +- rest-api-spec/test/index/75_ttl.yaml | 2 +- .../test/mget/13_missing_metadata.yaml | 8 +- rest-api-spec/test/mget/15_ids.yaml | 4 +- rest-api-spec/test/mpercolate/10_basic.yaml | 2 +- rest-api-spec/test/msearch/10_basic.yaml | 2 +- rest-api-spec/test/script/10_basic.yaml | 4 +- rest-api-spec/test/template/10_basic.yaml | 2 +- rest-api-spec/test/template/20_search.yaml | 2 +- rest-api-spec/test/update/50_parent.yaml | 2 +- rest-api-spec/test/update/75_ttl.yaml | 2 +- .../elasticsearch/ElasticsearchException.java | 136 ++++++++--- .../org/elasticsearch/ExceptionsHelper.java | 8 +- .../action/ActionWriteResponse.java | 20 +- .../action/bulk/BulkItemResponse.java | 2 +- .../action/bulk/TransportShardBulkAction.java | 8 +- .../search/SearchPhaseExecutionException.java | 101 ++++++++- .../action/search/ShardSearchFailure.java | 36 ++- .../DefaultShardOperationFailedException.java | 22 +- ...nsportIndexReplicationOperationAction.java | 10 +- ...nsportShardReplicationOperationAction.java | 5 +- .../common/io/stream/BytesStreamOutput.java | 5 - .../common/io/stream/StreamInput.java | 11 + .../common/io/stream/StreamOutput.java | 11 +- .../elasticsearch/index/IndexException.java | 24 +- .../index/percolator/PercolatorException.java | 4 - .../index/query/QueryParsingException.java | 1 + .../index/shard/IndexShardException.java | 18 +- .../indices/AliasFilterParsingException.java | 4 - .../indices/IndexMissingException.java | 2 +- .../indices/TypeMissingException.java | 5 - .../elasticsearch/rest/BytesRestResponse.java | 25 ++- .../search/SearchContextException.java | 15 +- .../search/SearchParseException.java | 4 +- .../ElasticsearchExceptionTests.java | 212 ++++++++++++++++++ .../BulkProcessorClusterSettingsTests.java | 2 +- .../cluster/metadata/MetaDataTests.java | 3 +- .../deleteByQuery/DeleteByQueryTests.java | 2 +- .../org/elasticsearch/document/BulkTests.java | 8 +- .../query/SimpleIndexQueryParserTests.java | 4 +- .../breaker/CircuitBreakerServiceTests.java | 12 +- .../template/SimpleIndexTemplateTests.java | 4 +- .../nested/SimpleNestedTests.java | 2 +- .../rest/BytesRestResponseTests.java | 64 +++++- .../script/GroovySandboxScriptTests.java | 3 +- .../script/GroovyScriptTests.java | 24 +- .../script/IndexLookupTests.java | 4 +- .../script/IndexedScriptTests.java | 6 +- .../script/OnDiskScriptTests.java | 8 +- .../script/SandboxDisabledTests.java | 2 +- .../expression/ExpressionScriptTests.java | 58 ++--- .../AggregationsIntegrationTests.java | 2 +- .../bucket/DateHistogramTests.java | 2 +- .../aggregations/bucket/HistogramTests.java | 2 +- .../aggregations/bucket/NestedTests.java | 2 +- .../aggregations/bucket/TopHitsTests.java | 4 +- .../child/SimpleChildQuerySearchTests.java | 25 +-- .../DecayFunctionScoreTests.java | 16 +- .../search/query/SearchQueryTests.java | 8 +- .../search/simple/SimpleSearchTests.java | 2 +- .../search/sort/SimpleSortTests.java | 2 +- .../suggest/CompletionSuggestSearchTests.java | 12 +- .../hamcrest/ElasticsearchAssertions.java | 2 +- 66 files changed, 737 insertions(+), 275 deletions(-) diff --git a/rest-api-spec/test/create/50_parent.yaml b/rest-api-spec/test/create/50_parent.yaml index dcd24d99346f0..6fe64b7bbed2c 100644 --- a/rest-api-spec/test/create/50_parent.yaml +++ b/rest-api-spec/test/create/50_parent.yaml @@ -14,7 +14,7 @@ wait_for_status: yellow - do: - catch: /RoutingMissingException/ + catch: /routing_missing_exception/ create: index: test_1 type: test diff --git a/rest-api-spec/test/create/75_ttl.yaml b/rest-api-spec/test/create/75_ttl.yaml index 099ed279020fa..3354e3b0517d4 100644 --- a/rest-api-spec/test/create/75_ttl.yaml +++ b/rest-api-spec/test/create/75_ttl.yaml @@ -89,7 +89,7 @@ type: test id: 1 - do: - catch: /AlreadyExpiredException/ + catch: /already_expired_exception/ create: index: test_1 type: test diff --git a/rest-api-spec/test/delete/42_missing_parent.yml b/rest-api-spec/test/delete/42_missing_parent.yml index 8247f8885e98c..d72c5a83d599f 100644 --- a/rest-api-spec/test/delete/42_missing_parent.yml +++ b/rest-api-spec/test/delete/42_missing_parent.yml @@ -21,7 +21,7 @@ body: { foo: bar } - do: - catch: /RoutingMissingException/ + catch: /routing_missing_exception/ delete: index: test_1 type: test diff --git a/rest-api-spec/test/index/50_parent.yaml b/rest-api-spec/test/index/50_parent.yaml index 551d30d95d7ac..28ab61cb49b7d 100644 --- a/rest-api-spec/test/index/50_parent.yaml +++ b/rest-api-spec/test/index/50_parent.yaml @@ -13,7 +13,7 @@ wait_for_status: yellow - do: - catch: /RoutingMissingException/ + catch: /routing_missing_exception/ index: index: test_1 type: test diff --git a/rest-api-spec/test/index/75_ttl.yaml b/rest-api-spec/test/index/75_ttl.yaml index 1d73d4ed40fdc..554933654fb50 100644 --- a/rest-api-spec/test/index/75_ttl.yaml +++ b/rest-api-spec/test/index/75_ttl.yaml @@ -74,7 +74,7 @@ # with timestamp - do: - catch: /AlreadyExpiredException/ + catch: /already_expired_exception/ index: index: test_1 type: test diff --git a/rest-api-spec/test/mget/13_missing_metadata.yaml b/rest-api-spec/test/mget/13_missing_metadata.yaml index 11b4a129406df..8d986a330bfcb 100644 --- a/rest-api-spec/test/mget/13_missing_metadata.yaml +++ b/rest-api-spec/test/mget/13_missing_metadata.yaml @@ -13,27 +13,27 @@ wait_for_status: yellow - do: - catch: /ActionRequestValidationException.+ id is missing/ + catch: /action_request_validation_exception.+ id is missing/ mget: body: docs: - { _index: test_1, _type: test} - do: - catch: /ActionRequestValidationException.+ index is missing/ + catch: /action_request_validation_exception.+ index is missing/ mget: body: docs: - { _type: test, _id: 1} - do: - catch: /ActionRequestValidationException.+ no documents to get/ + catch: /action_request_validation_exception.+ no documents to get/ mget: body: docs: [] - do: - catch: /ActionRequestValidationException.+ no documents to get/ + catch: /action_request_validation_exception.+ no documents to get/ mget: body: {} diff --git a/rest-api-spec/test/mget/15_ids.yaml b/rest-api-spec/test/mget/15_ids.yaml index a86fc2cdc6e98..cdd6c5724febe 100644 --- a/rest-api-spec/test/mget/15_ids.yaml +++ b/rest-api-spec/test/mget/15_ids.yaml @@ -59,14 +59,14 @@ - do: - catch: /ActionRequestValidationException.+ no documents to get/ + catch: /action_request_validation_exception.+ no documents to get/ mget: index: test_1 body: ids: [] - do: - catch: /ActionRequestValidationException.+ no documents to get/ + catch: /action_request_validation_exception.+ no documents to get/ mget: index: test_1 body: {} diff --git a/rest-api-spec/test/mpercolate/10_basic.yaml b/rest-api-spec/test/mpercolate/10_basic.yaml index 70118c93da142..9f949c21cd642 100644 --- a/rest-api-spec/test/mpercolate/10_basic.yaml +++ b/rest-api-spec/test/mpercolate/10_basic.yaml @@ -37,5 +37,5 @@ foo: bar - match: { responses.0.total: 1 } - - match: { responses.1.error: "IndexMissingException[[percolator_index1] missing]" } + - match: { responses.1.error: "/IndexMissingException.no.such.index./" } - match: { responses.2.total: 1 } diff --git a/rest-api-spec/test/msearch/10_basic.yaml b/rest-api-spec/test/msearch/10_basic.yaml index c0786229926ea..a028853429e95 100644 --- a/rest-api-spec/test/msearch/10_basic.yaml +++ b/rest-api-spec/test/msearch/10_basic.yaml @@ -39,7 +39,7 @@ match: {foo: bar} - match: { responses.0.hits.total: 3 } - - match: { responses.1.error: "IndexMissingException[[test_2] missing]" } + - match: { responses.1.error: "/IndexMissingException.no.such.index./" } - match: { responses.2.hits.total: 1 } diff --git a/rest-api-spec/test/script/10_basic.yaml b/rest-api-spec/test/script/10_basic.yaml index 822d887977106..ee977429b59f6 100644 --- a/rest-api-spec/test/script/10_basic.yaml +++ b/rest-api-spec/test/script/10_basic.yaml @@ -60,7 +60,7 @@ - do: - catch: /ElasticsearchIllegalArgumentException.Unable.to.parse.*/ + catch: /Unable.to.parse.*/ put_script: id: "1" lang: "groovy" @@ -74,7 +74,7 @@ body: { "script" : "_score * doc[\"myParent.weight\"].value" } - do: - catch: /ElasticsearchIllegalArgumentException.script_lang.not.supported/ + catch: /script_lang.not.supported/ put_script: id: "1" lang: "foobar" diff --git a/rest-api-spec/test/template/10_basic.yaml b/rest-api-spec/test/template/10_basic.yaml index 838a21d5a5607..bd1fd4366489b 100644 --- a/rest-api-spec/test/template/10_basic.yaml +++ b/rest-api-spec/test/template/10_basic.yaml @@ -50,7 +50,7 @@ body: { "template": { "query": { "match{{}}_all": {}}, "size": "{{my_size}}" } } - do: - catch: /ElasticsearchIllegalArgumentException\SUnable\sto\sparse.*/ + catch: /Unable\sto\sparse.*/ put_template: id: "1" body: { "template": { "query": { "match{{}}_all": {}}, "size": "{{my_size}}" } } diff --git a/rest-api-spec/test/template/20_search.yaml b/rest-api-spec/test/template/20_search.yaml index 55f886c64125a..d8e7364d54557 100644 --- a/rest-api-spec/test/template/20_search.yaml +++ b/rest-api-spec/test/template/20_search.yaml @@ -37,7 +37,7 @@ - match: { hits.total: 1 } - do: - catch: /ElasticsearchIllegalArgumentException.Unable.to.find.on.disk.script.simple1/ + catch: /Unable.to.find.on.disk.script.simple1/ search_template: body: { "template" : "simple1" } diff --git a/rest-api-spec/test/update/50_parent.yaml b/rest-api-spec/test/update/50_parent.yaml index 3d15ea9f2a89f..bc64665e9194c 100644 --- a/rest-api-spec/test/update/50_parent.yaml +++ b/rest-api-spec/test/update/50_parent.yaml @@ -15,7 +15,7 @@ setup: "Parent": - do: - catch: /RoutingMissingException/ + catch: /routing_missing_exception/ update: index: test_1 type: test diff --git a/rest-api-spec/test/update/75_ttl.yaml b/rest-api-spec/test/update/75_ttl.yaml index f6b05b9eca25c..8072c4d400f2e 100644 --- a/rest-api-spec/test/update/75_ttl.yaml +++ b/rest-api-spec/test/update/75_ttl.yaml @@ -81,7 +81,7 @@ # with timestamp - do: - catch: /AlreadyExpiredException/ + catch: /already_expired_exception/ index: index: test_1 type: test diff --git a/src/main/java/org/elasticsearch/ElasticsearchException.java b/src/main/java/org/elasticsearch/ElasticsearchException.java index fd7c9186875f5..eed4040793c10 100644 --- a/src/main/java/org/elasticsearch/ElasticsearchException.java +++ b/src/main/java/org/elasticsearch/ElasticsearchException.java @@ -22,18 +22,23 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; -import org.elasticsearch.common.Nullable; +import org.elasticsearch.common.Strings; import org.elasticsearch.common.collect.Tuple; +import org.elasticsearch.common.xcontent.ToXContent; +import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.rest.HasRestHeaders; import org.elasticsearch.rest.RestStatus; +import java.io.IOException; import java.util.List; import java.util.Map; /** * A base class for all elasticsearch exceptions. */ -public class ElasticsearchException extends RuntimeException { +public class ElasticsearchException extends RuntimeException implements ToXContent { + + public static final String REST_EXCEPTION_SKIP_CAUSE = "rest.exception.skip_cause"; /** * Construct a ElasticsearchException with the specified detail message. @@ -62,12 +67,8 @@ public RestStatus status() { Throwable cause = unwrapCause(); if (cause == this) { return RestStatus.INTERNAL_SERVER_ERROR; - } else if (cause instanceof ElasticsearchException) { - return ((ElasticsearchException) cause).status(); - } else if (cause instanceof IllegalArgumentException) { - return RestStatus.BAD_REQUEST; } else { - return RestStatus.INTERNAL_SERVER_ERROR; + return ExceptionsHelper.status(cause); } } @@ -114,19 +115,6 @@ public Throwable getRootCause() { return rootCause; } - /** - * Retrieve the most specific cause of this exception, that is, - * either the innermost cause (root cause) or this exception itself. - *

Differs from {@link #getRootCause()} in that it falls back - * to the present exception if there is no root cause. - * - * @return the most specific cause (never null) - */ - public Throwable getMostSpecificCause() { - Throwable rootCause = getRootCause(); - return (rootCause != null ? rootCause : this); - } - /** * Check whether this exception contains an exception of the given type: * either it is of the given class itself or it contains a nested cause @@ -175,21 +163,6 @@ public WithRestHeaders(String msg, Tuple... headers) { this.headers = headers(headers); } - public WithRestHeaders(String msg, @Nullable ImmutableMap> headers) { - super(msg); - this.headers = headers != null ? headers : ImmutableMap.>of(); - } - - public WithRestHeaders(String msg, Throwable cause, Tuple... headers) { - super(msg, cause); - this.headers = headers(headers); - } - - public WithRestHeaders(String msg, Throwable cause, @Nullable ImmutableMap> headers) { - super(msg, cause); - this.headers = headers != null ? headers : ImmutableMap.>of(); - } - @Override public ImmutableMap> getHeaders() { return headers; @@ -215,4 +188,97 @@ private static ImmutableMap> headers(TupleElasticsearch prefixes from exception names. + */ + public static String getExceptionName(Throwable ex) { + String simpleName = ex.getClass().getSimpleName(); + if (simpleName.startsWith("Elasticsearch")) { + simpleName = simpleName.substring("Elasticsearch".length()); + } + return Strings.toUnderscoreCase(simpleName); + } + + @Override + public String toString() { + return ExceptionsHelper.detailedMessage(this).trim(); + } + + } diff --git a/src/main/java/org/elasticsearch/ExceptionsHelper.java b/src/main/java/org/elasticsearch/ExceptionsHelper.java index 552d339301e88..9c29a4dc0aaaa 100644 --- a/src/main/java/org/elasticsearch/ExceptionsHelper.java +++ b/src/main/java/org/elasticsearch/ExceptionsHelper.java @@ -54,8 +54,12 @@ public static ElasticsearchException convertToElastic(Throwable t) { } public static RestStatus status(Throwable t) { - if (t instanceof ElasticsearchException) { - return ((ElasticsearchException) t).status(); + if (t != null) { + if (t instanceof ElasticsearchException) { + return ((ElasticsearchException) t).status(); + } else if (t instanceof IllegalArgumentException) { + return RestStatus.BAD_REQUEST; + } } return RestStatus.INTERNAL_SERVER_ERROR; } diff --git a/src/main/java/org/elasticsearch/action/ActionWriteResponse.java b/src/main/java/org/elasticsearch/action/ActionWriteResponse.java index 63b1f06a9f94b..5ddefaf99b2ea 100644 --- a/src/main/java/org/elasticsearch/action/ActionWriteResponse.java +++ b/src/main/java/org/elasticsearch/action/ActionWriteResponse.java @@ -19,6 +19,9 @@ package org.elasticsearch.action; +import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.ExceptionsHelper; +import org.elasticsearch.bootstrap.Elasticsearch; import org.elasticsearch.common.Nullable; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; @@ -164,15 +167,15 @@ public static class Failure implements ShardOperationFailedException, ToXContent private String index; private int shardId; private String nodeId; - private String reason; + private Throwable cause; private RestStatus status; private boolean primary; - public Failure(String index, int shardId, @Nullable String nodeId, String reason, RestStatus status, boolean primary) { + public Failure(String index, int shardId, @Nullable String nodeId, Throwable cause, RestStatus status, boolean primary) { this.index = index; this.shardId = shardId; this.nodeId = nodeId; - this.reason = reason; + this.cause = cause; this.status = status; this.primary = primary; } @@ -209,7 +212,7 @@ public String nodeId() { */ @Override public String reason() { - return reason; + return ExceptionsHelper.detailedMessage(cause); } /** @@ -233,7 +236,7 @@ public void readFrom(StreamInput in) throws IOException { index = in.readString(); shardId = in.readVInt(); nodeId = in.readOptionalString(); - reason = in.readString(); + cause = in.readThrowable(); status = RestStatus.readFrom(in); primary = in.readBoolean(); } @@ -243,7 +246,7 @@ public void writeTo(StreamOutput out) throws IOException { out.writeString(index); out.writeVInt(shardId); out.writeOptionalString(nodeId); - out.writeString(reason); + out.writeThrowable(cause); RestStatus.writeTo(out, status); out.writeBoolean(primary); } @@ -254,7 +257,10 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws builder.field(Fields._INDEX, index); builder.field(Fields._SHARD, shardId); builder.field(Fields._NODE, nodeId); - builder.field(Fields.REASON, reason); + builder.field(Fields.REASON); + builder.startObject(); + ElasticsearchException.toXContent(builder, params, cause); + builder.endObject(); builder.field(Fields.STATUS, status); builder.field(Fields.PRIMARY, primary); builder.endObject(); diff --git a/src/main/java/org/elasticsearch/action/bulk/BulkItemResponse.java b/src/main/java/org/elasticsearch/action/bulk/BulkItemResponse.java index 3ffa1ddcb62fb..c32f02f00227c 100644 --- a/src/main/java/org/elasticsearch/action/bulk/BulkItemResponse.java +++ b/src/main/java/org/elasticsearch/action/bulk/BulkItemResponse.java @@ -51,7 +51,7 @@ public Failure(String index, String type, String id, Throwable t) { this.index = index; this.type = type; this.id = id; - this.message = ExceptionsHelper.detailedMessage(t); + this.message = t.toString(); this.status = ExceptionsHelper.status(t); } diff --git a/src/main/java/org/elasticsearch/action/bulk/TransportShardBulkAction.java b/src/main/java/org/elasticsearch/action/bulk/TransportShardBulkAction.java index 9e354e8283691..4a29cfae58a26 100644 --- a/src/main/java/org/elasticsearch/action/bulk/TransportShardBulkAction.java +++ b/src/main/java/org/elasticsearch/action/bulk/TransportShardBulkAction.java @@ -157,7 +157,7 @@ protected Tuple shardOperationOnPrimary(Clu } throw (ElasticsearchException) e; } - if (e instanceof ElasticsearchException && ((ElasticsearchException) e).status() == RestStatus.CONFLICT) { + if (ExceptionsHelper.status(e) == RestStatus.CONFLICT) { logger.trace("{} failed to execute bulk item (index) {}", e, shardRequest.shardId, indexRequest); } else { logger.debug("{} failed to execute bulk item (index) {}", e, shardRequest.shardId, indexRequest); @@ -190,7 +190,7 @@ protected Tuple shardOperationOnPrimary(Clu } throw (ElasticsearchException) e; } - if (e instanceof ElasticsearchException && ((ElasticsearchException) e).status() == RestStatus.CONFLICT) { + if (ExceptionsHelper.status(e) == RestStatus.CONFLICT) { logger.trace("{} failed to execute bulk item (delete) {}", e, shardRequest.shardId, deleteRequest); } else { logger.debug("{} failed to execute bulk item (delete) {}", e, shardRequest.shardId, deleteRequest); @@ -279,7 +279,7 @@ protected Tuple shardOperationOnPrimary(Clu case UPSERT: case INDEX: IndexRequest indexRequest = updateResult.request(); - if (t instanceof ElasticsearchException && ((ElasticsearchException) t).status() == RestStatus.CONFLICT) { + if (ExceptionsHelper.status(t) == RestStatus.CONFLICT) { logger.trace("{} failed to execute bulk item (index) {}", t, shardRequest.shardId, indexRequest); } else { logger.debug("{} failed to execute bulk item (index) {}", t, shardRequest.shardId, indexRequest); @@ -289,7 +289,7 @@ protected Tuple shardOperationOnPrimary(Clu break; case DELETE: DeleteRequest deleteRequest = updateResult.request(); - if (t instanceof ElasticsearchException && ((ElasticsearchException) t).status() == RestStatus.CONFLICT) { + if (ExceptionsHelper.status(t) == RestStatus.CONFLICT) { logger.trace("{} failed to execute bulk item (delete) {}", t, shardRequest.shardId, deleteRequest); } else { logger.debug("{} failed to execute bulk item (delete) {}", t, shardRequest.shardId, deleteRequest); diff --git a/src/main/java/org/elasticsearch/action/search/SearchPhaseExecutionException.java b/src/main/java/org/elasticsearch/action/search/SearchPhaseExecutionException.java index 9e3de989bbf0e..d0202ba219d98 100644 --- a/src/main/java/org/elasticsearch/action/search/SearchPhaseExecutionException.java +++ b/src/main/java/org/elasticsearch/action/search/SearchPhaseExecutionException.java @@ -20,25 +20,30 @@ package org.elasticsearch.action.search; import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.index.Index; +import org.elasticsearch.index.IndexException; import org.elasticsearch.rest.RestStatus; +import java.io.IOException; +import java.util.*; + /** * */ public class SearchPhaseExecutionException extends ElasticsearchException { - private final String phaseName; private ShardSearchFailure[] shardFailures; public SearchPhaseExecutionException(String phaseName, String msg, ShardSearchFailure[] shardFailures) { - super(buildMessage(phaseName, msg, shardFailures)); + super(msg); this.phaseName = phaseName; this.shardFailures = shardFailures; } public SearchPhaseExecutionException(String phaseName, String msg, Throwable cause, ShardSearchFailure[] shardFailures) { - super(buildMessage(phaseName, msg, shardFailures), cause); + super(msg, cause); this.phaseName = phaseName; this.shardFailures = shardFailures; } @@ -60,10 +65,6 @@ public RestStatus status() { return status; } - public String phaseName() { - return phaseName; - } - public ShardSearchFailure[] shardFailures() { return shardFailures; } @@ -83,4 +84,90 @@ private static String buildMessage(String phaseName, String msg, ShardSearchFail } return sb.toString(); } + + @Override + protected void innerToXContent(XContentBuilder builder, Params params) throws IOException { + builder.field("phase", phaseName); + final boolean group = params.paramAsBoolean("group_shard_failures", true); // we group by default + builder.field("grouped", group); // notify that it's grouped + builder.field("failed_shards"); + builder.startArray(); + ShardSearchFailure[] failures = params.paramAsBoolean("group_shard_failures", true) ? groupBy(shardFailures) : shardFailures; + for (ShardSearchFailure failure : failures) { + builder.startObject(); + failure.toXContent(builder, params); + builder.endObject(); + } + builder.endArray(); + super.innerToXContent(builder, params); + + } + + private ShardSearchFailure[] groupBy(ShardSearchFailure[] failures) { + List uniqueFailures = new ArrayList<>(); + Set reasons = new HashSet<>(); + for (ShardSearchFailure failure : failures) { + GroupBy reason = new GroupBy(failure.getCause()); + if (reasons.contains(reason) == false) { + reasons.add(reason); + uniqueFailures.add(failure); + } + } + return uniqueFailures.toArray(new ShardSearchFailure[0]); + + } + + @Override + public ElasticsearchException[] guessRootCauses() { + ShardSearchFailure[] failures = groupBy(shardFailures); + List rootCauses = new ArrayList<>(failures.length); + for (ShardSearchFailure failure : failures) { + ElasticsearchException[] guessRootCauses = ElasticsearchException.guessRootCauses(failure.getCause()); + rootCauses.addAll(Arrays.asList(guessRootCauses)); + } + return rootCauses.toArray(new ElasticsearchException[0]); + } + + @Override + public String toString() { + return buildMessage(phaseName, getMessage(), shardFailures); + } + + static class GroupBy { + final String reason; + final Index index; + final Class causeType; + + public GroupBy(Throwable t) { + if (t instanceof IndexException) { + index = ((IndexException) t).index(); + } else { + index = null; + } + reason = t.getMessage(); + causeType = t.getClass(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + GroupBy groupBy = (GroupBy) o; + + if (!causeType.equals(groupBy.causeType)) return false; + if (index != null ? !index.equals(groupBy.index) : groupBy.index != null) return false; + if (reason != null ? !reason.equals(groupBy.reason) : groupBy.reason != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = reason != null ? reason.hashCode() : 0; + result = 31 * result + (index != null ? index.hashCode() : 0); + result = 31 * result + causeType.hashCode(); + return result; + } + } } diff --git a/src/main/java/org/elasticsearch/action/search/ShardSearchFailure.java b/src/main/java/org/elasticsearch/action/search/ShardSearchFailure.java index 38bf5693c08d2..4a6e073e2880e 100644 --- a/src/main/java/org/elasticsearch/action/search/ShardSearchFailure.java +++ b/src/main/java/org/elasticsearch/action/search/ShardSearchFailure.java @@ -25,24 +25,29 @@ import org.elasticsearch.common.Nullable; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.xcontent.ToXContent; +import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.rest.RestStatus; import org.elasticsearch.search.SearchException; import org.elasticsearch.search.SearchShardTarget; import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import static org.elasticsearch.search.SearchShardTarget.readSearchShardTarget; /** * Represents a failure to search on a specific shard. */ -public class ShardSearchFailure implements ShardOperationFailedException { +public class ShardSearchFailure implements ShardOperationFailedException, ToXContent { public static final ShardSearchFailure[] EMPTY_ARRAY = new ShardSearchFailure[0]; private SearchShardTarget shardTarget; private String reason; private RestStatus status; + private Throwable cause; private ShardSearchFailure() { @@ -59,12 +64,9 @@ public ShardSearchFailure(Throwable t, @Nullable SearchShardTarget shardTarget) } else if (shardTarget != null) { this.shardTarget = shardTarget; } - if (actual != null && actual instanceof ElasticsearchException) { - status = ((ElasticsearchException) actual).status(); - } else { - status = RestStatus.INTERNAL_SERVER_ERROR; - } + status = ExceptionsHelper.status(actual); this.reason = ExceptionsHelper.detailedMessage(t); + this.cause = actual; } public ShardSearchFailure(String reason, SearchShardTarget shardTarget) { @@ -138,6 +140,7 @@ public void readFrom(StreamInput in) throws IOException { } reason = in.readString(); status = RestStatus.readFrom(in); + cause = in.readThrowable(); } @Override @@ -150,5 +153,26 @@ public void writeTo(StreamOutput out) throws IOException { } out.writeString(reason); RestStatus.writeTo(out, status); + out.writeThrowable(cause); + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.field("shard", shardId()); + builder.field("index", index()); + if (shardTarget != null) { + builder.field("node", shardTarget.nodeId()); + } + if (cause != null) { + builder.field("reason"); + builder.startObject(); + ElasticsearchException.toXContent(builder, params, cause); + builder.endObject(); + } + return builder; + } + + public Throwable getCause() { + return cause; } } diff --git a/src/main/java/org/elasticsearch/action/support/DefaultShardOperationFailedException.java b/src/main/java/org/elasticsearch/action/support/DefaultShardOperationFailedException.java index 3a7e90096c1af..3be7b7d2aee17 100644 --- a/src/main/java/org/elasticsearch/action/support/DefaultShardOperationFailedException.java +++ b/src/main/java/org/elasticsearch/action/support/DefaultShardOperationFailedException.java @@ -20,6 +20,7 @@ package org.elasticsearch.action.support; import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.ExceptionsHelper; import org.elasticsearch.action.ShardOperationFailedException; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; @@ -39,30 +40,25 @@ public class DefaultShardOperationFailedException implements ShardOperationFaile private int shardId; - private String reason; + private Throwable reason; private RestStatus status; private DefaultShardOperationFailedException() { - } public DefaultShardOperationFailedException(IndexShardException e) { this.index = e.shardId().index().name(); this.shardId = e.shardId().id(); - this.reason = detailedMessage(e); + this.reason = e; this.status = e.status(); } public DefaultShardOperationFailedException(String index, int shardId, Throwable t) { this.index = index; this.shardId = shardId; - this.reason = detailedMessage(t); - if (t != null && t instanceof ElasticsearchException) { - status = ((ElasticsearchException) t).status(); - } else { - status = RestStatus.INTERNAL_SERVER_ERROR; - } + this.reason = t; + status = ExceptionsHelper.status(t); } @Override @@ -77,7 +73,7 @@ public int shardId() { @Override public String reason() { - return this.reason; + return detailedMessage(reason); } @Override @@ -97,7 +93,7 @@ public void readFrom(StreamInput in) throws IOException { index = in.readString(); } shardId = in.readVInt(); - reason = in.readString(); + reason = in.readThrowable(); status = RestStatus.readFrom(in); } @@ -110,12 +106,12 @@ public void writeTo(StreamOutput out) throws IOException { out.writeString(index); } out.writeVInt(shardId); - out.writeString(reason); + out.writeThrowable(reason); RestStatus.writeTo(out, status); } @Override public String toString() { - return "[" + index + "][" + shardId + "] failed, reason [" + reason + "]"; + return "[" + index + "][" + shardId + "] failed, reason [" + reason() + "]"; } } diff --git a/src/main/java/org/elasticsearch/action/support/replication/TransportIndexReplicationOperationAction.java b/src/main/java/org/elasticsearch/action/support/replication/TransportIndexReplicationOperationAction.java index 53c4984bfc86f..5d0cba209d0da 100644 --- a/src/main/java/org/elasticsearch/action/support/replication/TransportIndexReplicationOperationAction.java +++ b/src/main/java/org/elasticsearch/action/support/replication/TransportIndexReplicationOperationAction.java @@ -103,14 +103,8 @@ public void onFailure(Throwable e) { failureCounter.getAndIncrement(); int index = indexCounter.getAndIncrement(); // this is a failure for an entire shard group, constructs shard info accordingly - final RestStatus status; - if (e != null && e instanceof ElasticsearchException) { - status = ((ElasticsearchException) e).status(); - } else { - status = RestStatus.INTERNAL_SERVER_ERROR; - } - Failure failure = new Failure(request.index(), shardIt.shardId().id(), null, - "Failed to execute on all shard copies [" + ExceptionsHelper.detailedMessage(e) + "]", status, true); + final RestStatus status = ExceptionsHelper.status(e); + Failure failure = new Failure(request.index(), shardIt.shardId().id(), null, e, status, true); shardsResponses.set(index, new ShardActionResult(new ActionWriteResponse.ShardInfo(shardIt.size(), 0, failure))); returnIfNeeded(); } diff --git a/src/main/java/org/elasticsearch/action/support/replication/TransportShardReplicationOperationAction.java b/src/main/java/org/elasticsearch/action/support/replication/TransportShardReplicationOperationAction.java index c5a0fc95efe6d..6b9e4ca14d872 100644 --- a/src/main/java/org/elasticsearch/action/support/replication/TransportShardReplicationOperationAction.java +++ b/src/main/java/org/elasticsearch/action/support/replication/TransportShardReplicationOperationAction.java @@ -495,7 +495,7 @@ void performOnPrimary(int primaryShardId, final ShardRouting shard) { retry(e); return; } - if (e instanceof ElasticsearchException && ((ElasticsearchException) e).status() == RestStatus.CONFLICT) { + if (ExceptionsHelper.status(e) == RestStatus.CONFLICT) { if (logger.isTraceEnabled()) { logger.trace(shard.shortSummary() + ": Failed to execute [" + internalRequest.request() + "]", e); } @@ -822,10 +822,9 @@ private void doFinish() { int slot = 0; failuresArray = new ActionWriteResponse.ShardInfo.Failure[shardReplicaFailures.size()]; for (Map.Entry entry : shardReplicaFailures.entrySet()) { - String reason = ExceptionsHelper.detailedMessage(entry.getValue()); RestStatus restStatus = ExceptionsHelper.status(entry.getValue()); failuresArray[slot++] = new ActionWriteResponse.ShardInfo.Failure( - shardId.getIndex(), shardId.getId(), entry.getKey(), reason, restStatus, false + shardId.getIndex(), shardId.getId(), entry.getKey(), entry.getValue(), restStatus, false ); } } else { diff --git a/src/main/java/org/elasticsearch/common/io/stream/BytesStreamOutput.java b/src/main/java/org/elasticsearch/common/io/stream/BytesStreamOutput.java index 4235d38a21d47..2107a9958dae6 100644 --- a/src/main/java/org/elasticsearch/common/io/stream/BytesStreamOutput.java +++ b/src/main/java/org/elasticsearch/common/io/stream/BytesStreamOutput.java @@ -60,11 +60,6 @@ protected BytesStreamOutput(int expectedSize, BigArrays bigarrays) { this.bytes = bigarrays.newByteArray(expectedSize); } - @Override - public boolean seekPositionSupported() { - return true; - } - @Override public long position() throws IOException { return count; diff --git a/src/main/java/org/elasticsearch/common/io/stream/StreamInput.java b/src/main/java/org/elasticsearch/common/io/stream/StreamInput.java index b05d463c58d87..fea34cd94c32e 100644 --- a/src/main/java/org/elasticsearch/common/io/stream/StreamInput.java +++ b/src/main/java/org/elasticsearch/common/io/stream/StreamInput.java @@ -21,6 +21,7 @@ import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.CharsRefBuilder; +import org.elasticsearch.ElasticsearchException; import org.elasticsearch.Version; import org.elasticsearch.common.Nullable; import org.elasticsearch.common.Strings; @@ -32,6 +33,7 @@ import java.io.IOException; import java.io.InputStream; +import java.io.ObjectInputStream; import java.util.*; /** @@ -463,4 +465,13 @@ public T readOptionalStreamable(T streamable) throws IOEx return null; } } + + public T readThrowable() throws IOException { + try { + ObjectInputStream oin = new ObjectInputStream(this); + return (T) oin.readObject(); + } catch (ClassNotFoundException e) { + throw new IOException("failed to deserialize exception", e); + } + } } diff --git a/src/main/java/org/elasticsearch/common/io/stream/StreamOutput.java b/src/main/java/org/elasticsearch/common/io/stream/StreamOutput.java index 208b98ea8a752..754e38ceadb18 100644 --- a/src/main/java/org/elasticsearch/common/io/stream/StreamOutput.java +++ b/src/main/java/org/elasticsearch/common/io/stream/StreamOutput.java @@ -28,6 +28,7 @@ import org.joda.time.ReadableInstant; import java.io.IOException; +import java.io.ObjectOutputStream; import java.io.OutputStream; import java.util.Date; import java.util.LinkedHashMap; @@ -50,10 +51,6 @@ public StreamOutput setVersion(Version version) { return this; } - public boolean seekPositionSupported() { - return false; - } - public long position() throws IOException { throw new UnsupportedOperationException(); } @@ -432,4 +429,10 @@ public void writeOptionalStreamable(@Nullable Streamable streamable) throws IOEx writeBoolean(false); } } + + public void writeThrowable(Throwable throwable) throws IOException { + ObjectOutputStream out = new ObjectOutputStream(this); + out.writeObject(throwable); + out.flush(); + } } diff --git a/src/main/java/org/elasticsearch/index/IndexException.java b/src/main/java/org/elasticsearch/index/IndexException.java index a3d18cfd86e9d..0f100dcd4f014 100644 --- a/src/main/java/org/elasticsearch/index/IndexException.java +++ b/src/main/java/org/elasticsearch/index/IndexException.java @@ -20,6 +20,9 @@ package org.elasticsearch.index; import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.common.xcontent.XContentBuilder; + +import java.io.IOException; /** * @@ -32,16 +35,25 @@ public IndexException(Index index, String msg) { this(index, msg, null); } - public IndexException(Index index, String msg, Throwable cause) { - this(index, true, msg, cause); - } - - protected IndexException(Index index, boolean withSpace, String msg, Throwable cause) { - super("[" + (index == null ? "_na" : index.name()) + "]" + (withSpace ? " " : "") + msg, cause); + protected IndexException(Index index, String msg, Throwable cause) { + super(msg, cause); this.index = index; } public Index index() { return index; } + + @Override + protected void innerToXContent(XContentBuilder builder, Params params) throws IOException { + if (index != null) { + builder.field("index", index.getName()); + } + super.innerToXContent(builder, params); + } + + @Override + public String toString() { + return "[" + (index == null ? "_na" : index.name()) + "] " + getMessage(); + } } diff --git a/src/main/java/org/elasticsearch/index/percolator/PercolatorException.java b/src/main/java/org/elasticsearch/index/percolator/PercolatorException.java index 462b9104d0379..6e0f1d1827cfd 100644 --- a/src/main/java/org/elasticsearch/index/percolator/PercolatorException.java +++ b/src/main/java/org/elasticsearch/index/percolator/PercolatorException.java @@ -26,10 +26,6 @@ */ public class PercolatorException extends IndexException { - public PercolatorException(Index index, String msg) { - super(index, msg); - } - public PercolatorException(Index index, String msg, Throwable cause) { super(index, msg, cause); } diff --git a/src/main/java/org/elasticsearch/index/query/QueryParsingException.java b/src/main/java/org/elasticsearch/index/query/QueryParsingException.java index 8c3a0fbccbeff..5bf1407a107f5 100644 --- a/src/main/java/org/elasticsearch/index/query/QueryParsingException.java +++ b/src/main/java/org/elasticsearch/index/query/QueryParsingException.java @@ -40,4 +40,5 @@ public QueryParsingException(Index index, String msg, Throwable cause) { public RestStatus status() { return RestStatus.BAD_REQUEST; } + } diff --git a/src/main/java/org/elasticsearch/index/shard/IndexShardException.java b/src/main/java/org/elasticsearch/index/shard/IndexShardException.java index e9217fda4cbc1..019b4d13bb4f2 100644 --- a/src/main/java/org/elasticsearch/index/shard/IndexShardException.java +++ b/src/main/java/org/elasticsearch/index/shard/IndexShardException.java @@ -19,8 +19,11 @@ package org.elasticsearch.index.shard; +import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.index.IndexException; +import java.io.IOException; + /** * */ @@ -33,11 +36,24 @@ public IndexShardException(ShardId shardId, String msg) { } public IndexShardException(ShardId shardId, String msg, Throwable cause) { - super(shardId == null ? null : shardId.index(), false, "[" + (shardId == null ? "_na" : shardId.id()) + "] " + msg, cause); + super(shardId == null ? null : shardId.index(), msg, cause); this.shardId = shardId; } public ShardId shardId() { return shardId; } + + @Override + public String toString() { + return (shardId == null ? "_na" : shardId) + getMessage(); + } + + @Override + protected void innerToXContent(XContentBuilder builder, Params params) throws IOException { + if (shardId != null) { + builder.field("shard", shardId.getId()); + } + super.innerToXContent(builder, params); + } } diff --git a/src/main/java/org/elasticsearch/indices/AliasFilterParsingException.java b/src/main/java/org/elasticsearch/indices/AliasFilterParsingException.java index aa7b559bb309f..95d1c0f4d6dc6 100644 --- a/src/main/java/org/elasticsearch/indices/AliasFilterParsingException.java +++ b/src/main/java/org/elasticsearch/indices/AliasFilterParsingException.java @@ -27,10 +27,6 @@ */ public class AliasFilterParsingException extends IndexException { - public AliasFilterParsingException(Index index, String name, String desc) { - super(index, "[" + name + "], " + desc); - } - public AliasFilterParsingException(Index index, String name, String desc, Throwable ex) { super(index, "[" + name + "], " + desc, ex); } diff --git a/src/main/java/org/elasticsearch/indices/IndexMissingException.java b/src/main/java/org/elasticsearch/indices/IndexMissingException.java index dbadef5a07617..1bec1585a7ca6 100644 --- a/src/main/java/org/elasticsearch/indices/IndexMissingException.java +++ b/src/main/java/org/elasticsearch/indices/IndexMissingException.java @@ -29,7 +29,7 @@ public class IndexMissingException extends IndexException { public IndexMissingException(Index index) { - super(index, "missing"); + super(index, "no such index"); } @Override diff --git a/src/main/java/org/elasticsearch/indices/TypeMissingException.java b/src/main/java/org/elasticsearch/indices/TypeMissingException.java index ae2830b957595..eb80c057a455c 100644 --- a/src/main/java/org/elasticsearch/indices/TypeMissingException.java +++ b/src/main/java/org/elasticsearch/indices/TypeMissingException.java @@ -34,11 +34,6 @@ public TypeMissingException(Index index, String... types) { super(index, "type[" + Arrays.toString(types) + "] missing"); } - public TypeMissingException(Index index, String[] types, String message) { - super(index, "type[" + Arrays.toString(types) + "] missing: " + message); - } - - @Override public RestStatus status() { return RestStatus.NOT_FOUND; diff --git a/src/main/java/org/elasticsearch/rest/BytesRestResponse.java b/src/main/java/org/elasticsearch/rest/BytesRestResponse.java index b72008cf63e76..693188307e341 100644 --- a/src/main/java/org/elasticsearch/rest/BytesRestResponse.java +++ b/src/main/java/org/elasticsearch/rest/BytesRestResponse.java @@ -20,13 +20,16 @@ package org.elasticsearch.rest; import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.ExceptionsHelper; 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.XContentBuilder; import java.io.IOException; +import java.util.Collections; -import static org.elasticsearch.ExceptionsHelper.detailedMessage; public class BytesRestResponse extends RestResponse { @@ -78,7 +81,7 @@ public BytesRestResponse(RestStatus status, String contentType, BytesReference c } public BytesRestResponse(RestChannel channel, Throwable t) throws IOException { - this(channel, ((t instanceof ElasticsearchException) ? ((ElasticsearchException) t).status() : RestStatus.INTERNAL_SERVER_ERROR), t); + this(channel, ExceptionsHelper.status(t), t); } public BytesRestResponse(RestChannel channel, RestStatus status, Throwable t) throws IOException { @@ -114,9 +117,22 @@ public RestStatus status() { private static XContentBuilder convert(RestChannel channel, RestStatus status, Throwable t) throws IOException { XContentBuilder builder = channel.newBuilder().startObject(); if (t == null) { - builder.field("error", "Unknown"); + builder.field("error", "unknown"); } else if (channel.detailedErrorsEnabled()) { - builder.field("error", detailedMessage(t)); + builder.field("error"); + builder.startObject(); + final ElasticsearchException[] rootCauses = ElasticsearchException.guessRootCauses(t); + builder.field("root_cause"); + builder.startArray(); + for (ElasticsearchException rootCause : rootCauses){ + builder.startObject(); + rootCause.toXContent(builder, new ToXContent.DelegatingMapParams(Collections.singletonMap(ElasticsearchException.REST_EXCEPTION_SKIP_CAUSE, "true"), channel.request())); + builder.endObject(); + } + builder.endArray(); + + ElasticsearchException.toXContent(builder, channel.request(), t); + builder.endObject(); if (channel.request().paramAsBoolean("error_trace", false)) { buildErrorTrace(t, builder); } @@ -128,6 +144,7 @@ private static XContentBuilder convert(RestChannel channel, RestStatus status, T return builder; } + private static void buildErrorTrace(Throwable t, XContentBuilder builder) throws IOException { builder.startObject("error_trace"); boolean first = true; diff --git a/src/main/java/org/elasticsearch/search/SearchContextException.java b/src/main/java/org/elasticsearch/search/SearchContextException.java index 39bea64188fec..599515830e1b3 100644 --- a/src/main/java/org/elasticsearch/search/SearchContextException.java +++ b/src/main/java/org/elasticsearch/search/SearchContextException.java @@ -35,19 +35,6 @@ public SearchContextException(SearchContext context, String msg, Throwable t) { } private static String buildMessage(SearchContext context, String msg) { - StringBuilder sb = new StringBuilder(); - sb.append('[').append(context.shardTarget().index()).append("][").append(context.shardTarget().shardId()).append("]: "); - if (context.parsedQuery() != null) { - try { - sb.append("query[").append(context.parsedQuery().query()).append("],"); - } catch (Exception e) { - sb.append("query[_failed_to_string_],"); - } - } - sb.append("from[").append(context.from()).append("],size[").append(context.size()).append("]"); - if (context.sort() != null) { - sb.append(",sort[").append(context.sort()).append("]"); - } - return sb.append(": ").append(msg).toString(); + return msg; } } diff --git a/src/main/java/org/elasticsearch/search/SearchParseException.java b/src/main/java/org/elasticsearch/search/SearchParseException.java index 5f528f2d57a75..923532373a579 100644 --- a/src/main/java/org/elasticsearch/search/SearchParseException.java +++ b/src/main/java/org/elasticsearch/search/SearchParseException.java @@ -28,11 +28,11 @@ public class SearchParseException extends SearchContextException { public SearchParseException(SearchContext context, String msg) { - super(context, "Parse Failure [" + msg + "]"); + super(context, msg); } public SearchParseException(SearchContext context, String msg, Throwable cause) { - super(context, "Parse Failure [" + msg + "]", cause); + super(context, msg, cause); } @Override diff --git a/src/test/java/org/elasticsearch/ElasticsearchExceptionTests.java b/src/test/java/org/elasticsearch/ElasticsearchExceptionTests.java index 2c605f889aab1..26447471c2c22 100644 --- a/src/test/java/org/elasticsearch/ElasticsearchExceptionTests.java +++ b/src/test/java/org/elasticsearch/ElasticsearchExceptionTests.java @@ -19,13 +19,27 @@ package org.elasticsearch; +import org.elasticsearch.action.search.SearchPhaseExecutionException; +import org.elasticsearch.action.search.ShardSearchFailure; +import org.elasticsearch.common.io.BytesStream; +import org.elasticsearch.common.io.stream.BytesStreamInput; +import org.elasticsearch.common.io.stream.BytesStreamOutput; +import org.elasticsearch.common.xcontent.ToXContent; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.index.Index; +import org.elasticsearch.index.query.QueryParsingException; import org.elasticsearch.indices.IndexMissingException; import org.elasticsearch.rest.RestStatus; +import org.elasticsearch.search.SearchShardTarget; import org.elasticsearch.test.ElasticsearchTestCase; import org.elasticsearch.transport.RemoteTransportException; import org.junit.Test; +import java.io.EOFException; +import java.io.FileNotFoundException; +import java.io.IOException; + import static org.hamcrest.Matchers.equalTo; public class ElasticsearchExceptionTests extends ElasticsearchTestCase { @@ -43,5 +57,203 @@ public void testStatus() { exception = new RemoteTransportException("test", new IndexMissingException(new Index("test"))); assertThat(exception.status(), equalTo(RestStatus.NOT_FOUND)); + + exception = new RemoteTransportException("test", new IllegalArgumentException("foobar")); + assertThat(exception.status(), equalTo(RestStatus.BAD_REQUEST)); + + exception = new RemoteTransportException("test", new IllegalStateException("foobar")); + assertThat(exception.status(), equalTo(RestStatus.INTERNAL_SERVER_ERROR)); + } + + public void testGuessRootCause() { + { + ElasticsearchException exception = new ElasticsearchException("foo", new ElasticsearchException("bar", new ElasticsearchIllegalArgumentException("index is closed", new RuntimeException("foobar")))); + ElasticsearchException[] rootCauses = exception.guessRootCauses(); + assertEquals(rootCauses.length, 1); + assertEquals(ElasticsearchException.getExceptionName(rootCauses[0]), "illegal_argument_exception"); + assertEquals(rootCauses[0].getMessage(), "index is closed"); + ShardSearchFailure failure = new ShardSearchFailure(new QueryParsingException(new Index("foo"), "foobar"), new SearchShardTarget("node_1", "foo", 1)); + ShardSearchFailure failure1 = new ShardSearchFailure(new QueryParsingException(new Index("foo"), "foobar"), new SearchShardTarget("node_1", "foo", 2)); + SearchPhaseExecutionException ex = new SearchPhaseExecutionException("search", "all shards failed", new ShardSearchFailure[]{failure, failure1}); + if (randomBoolean()) { + rootCauses = (randomBoolean() ? new RemoteTransportException("remoteboom", ex) : ex).guessRootCauses(); + } else { + rootCauses = ElasticsearchException.guessRootCauses(randomBoolean() ? new RemoteTransportException("remoteboom", ex) : ex); + } + assertEquals(ElasticsearchException.getExceptionName(rootCauses[0]), "query_parsing_exception"); + assertEquals(rootCauses[0].getMessage(), "foobar"); + + ElasticsearchException oneLevel = new ElasticsearchException("foo", new RuntimeException("foobar")); + rootCauses = oneLevel.guessRootCauses(); + assertEquals(ElasticsearchException.getExceptionName(rootCauses[0]), "exception"); + assertEquals(rootCauses[0].getMessage(), "foo"); + } + { + ShardSearchFailure failure = new ShardSearchFailure(new QueryParsingException(new Index("foo"), "foobar"), new SearchShardTarget("node_1", "foo", 1)); + ShardSearchFailure failure1 = new ShardSearchFailure(new QueryParsingException(new Index("foo1"), "foobar"), new SearchShardTarget("node_1", "foo1", 1)); + ShardSearchFailure failure2 = new ShardSearchFailure(new QueryParsingException(new Index("foo1"), "foobar"), new SearchShardTarget("node_1", "foo1", 2)); + SearchPhaseExecutionException ex = new SearchPhaseExecutionException("search", "all shards failed", new ShardSearchFailure[]{failure, failure1, failure2}); + final ElasticsearchException[] rootCauses = ex.guessRootCauses(); + assertEquals(rootCauses.length, 2); + assertEquals(ElasticsearchException.getExceptionName(rootCauses[0]), "query_parsing_exception"); + assertEquals(rootCauses[0].getMessage(), "foobar"); + assertEquals(((QueryParsingException)rootCauses[0]).index().name(), "foo"); + assertEquals(ElasticsearchException.getExceptionName(rootCauses[1]), "query_parsing_exception"); + assertEquals(rootCauses[1].getMessage(), "foobar"); + assertEquals(((QueryParsingException)rootCauses[1]).index().name(), "foo1"); + + } + + } + + public void testDeduplicate() throws IOException { + { + ShardSearchFailure failure = new ShardSearchFailure(new QueryParsingException(new Index("foo"), "foobar"), new SearchShardTarget("node_1", "foo", 1)); + ShardSearchFailure failure1 = new ShardSearchFailure(new QueryParsingException(new Index("foo"), "foobar"), new SearchShardTarget("node_1", "foo", 2)); + SearchPhaseExecutionException ex = new SearchPhaseExecutionException("search", "all shards failed", new ShardSearchFailure[]{failure, failure1}); + XContentBuilder builder = XContentFactory.jsonBuilder().prettyPrint(); + builder.startObject(); + ex.toXContent(builder, ToXContent.EMPTY_PARAMS); + builder.endObject(); + String expected = "{\n" + + " \"type\" : \"search_phase_execution_exception\",\n" + + " \"reason\" : \"all shards failed\",\n" + + " \"phase\" : \"search\",\n" + + " \"grouped\" : true,\n" + + " \"failed_shards\" : [ {\n" + + " \"shard\" : 1,\n" + + " \"index\" : \"foo\",\n" + + " \"node\" : \"node_1\",\n" + + " \"reason\" : {\n" + + " \"type\" : \"query_parsing_exception\",\n" + + " \"reason\" : \"foobar\",\n" + + " \"index\" : \"foo\"\n" + + " }\n" + + " } ]\n" + + "}"; + assertEquals(expected, builder.string()); + } + { + ShardSearchFailure failure = new ShardSearchFailure(new QueryParsingException(new Index("foo"), "foobar"), new SearchShardTarget("node_1", "foo", 1)); + ShardSearchFailure failure1 = new ShardSearchFailure(new QueryParsingException(new Index("foo1"), "foobar"), new SearchShardTarget("node_1", "foo1", 1)); + ShardSearchFailure failure2 = new ShardSearchFailure(new QueryParsingException(new Index("foo1"), "foobar"), new SearchShardTarget("node_1", "foo1", 2)); + SearchPhaseExecutionException ex = new SearchPhaseExecutionException("search", "all shards failed", new ShardSearchFailure[]{failure, failure1, failure2}); + XContentBuilder builder = XContentFactory.jsonBuilder().prettyPrint(); + builder.startObject(); + ex.toXContent(builder, ToXContent.EMPTY_PARAMS); + builder.endObject(); + String expected = "{\n" + + " \"type\" : \"search_phase_execution_exception\",\n" + + " \"reason\" : \"all shards failed\",\n" + + " \"phase\" : \"search\",\n" + + " \"grouped\" : true,\n" + + " \"failed_shards\" : [ {\n" + + " \"shard\" : 1,\n" + + " \"index\" : \"foo\",\n" + + " \"node\" : \"node_1\",\n" + + " \"reason\" : {\n" + + " \"type\" : \"query_parsing_exception\",\n" + + " \"reason\" : \"foobar\",\n" + + " \"index\" : \"foo\"\n" + + " }\n" + + " }, {\n" + + " \"shard\" : 1,\n" + + " \"index\" : \"foo1\",\n" + + " \"node\" : \"node_1\",\n" + + " \"reason\" : {\n" + + " \"type\" : \"query_parsing_exception\",\n" + + " \"reason\" : \"foobar\",\n" + + " \"index\" : \"foo1\"\n" + + " }\n" + + " } ]\n" + + "}"; + assertEquals(expected, builder.string()); + } } + + public void testGetRootCause() { + Exception root = new RuntimeException("foobar"); + ElasticsearchException exception = new ElasticsearchException("foo", new ElasticsearchException("bar", new ElasticsearchIllegalArgumentException("index is closed", root))); + assertEquals(root, exception.getRootCause()); + assertTrue(exception.contains(RuntimeException.class)); + assertFalse(exception.contains(EOFException.class)); + } + + public void testToString() { + ElasticsearchException exception = new ElasticsearchException("foo", new ElasticsearchException("bar", new ElasticsearchIllegalArgumentException("index is closed", new RuntimeException("foobar")))); + assertEquals("ElasticsearchException[foo]; nested: ElasticsearchException[bar]; nested: ElasticsearchIllegalArgumentException[index is closed]; nested: RuntimeException[foobar];", exception.toString()); + } + + public void testToXContent() throws IOException { + { + ElasticsearchException ex = new ElasticsearchException("foo", new ElasticsearchException("bar", new ElasticsearchIllegalArgumentException("index is closed", new RuntimeException("foobar")))); + XContentBuilder builder = XContentFactory.jsonBuilder().prettyPrint(); + builder.startObject(); + ex.toXContent(builder, ToXContent.EMPTY_PARAMS); + builder.endObject(); + + String expected = "{\n" + + " \"type\" : \"exception\",\n" + + " \"reason\" : \"foo\",\n" + + " \"caused_by\" : {\n" + + " \"type\" : \"exception\",\n" + + " \"reason\" : \"bar\",\n" + + " \"caused_by\" : {\n" + + " \"type\" : \"illegal_argument_exception\",\n" + + " \"reason\" : \"index is closed\",\n" + + " \"caused_by\" : {\n" + + " \"type\" : \"runtime_exception\",\n" + + " \"reason\" : \"foobar\"\n" + + " }\n" + + " }\n" + + " }\n" + + "}"; + assertEquals(expected, builder.string()); + } + + { + Exception ex = new FileNotFoundException("foo not found"); + if (randomBoolean()) { + // just a wrapper which is omitted + ex = new RemoteTransportException("foobar", ex); + } + XContentBuilder builder = XContentFactory.jsonBuilder().prettyPrint(); + builder.startObject(); + ElasticsearchException.toXContent(builder, ToXContent.EMPTY_PARAMS, ex); + builder.endObject(); + + String expected = "{\n" + + " \"type\" : \"file_not_found_exception\",\n" + + " \"reason\" : \"foo not found\"\n" + + "}"; + assertEquals(expected, builder.string()); + } + + { // test equivalence + ElasticsearchException ex = new RemoteTransportException("foobar", new FileNotFoundException("foo not found")); + XContentBuilder builder = XContentFactory.jsonBuilder().prettyPrint(); + builder.startObject(); + ElasticsearchException.toXContent(builder, ToXContent.EMPTY_PARAMS, ex); + builder.endObject(); + + XContentBuilder otherBuilder = XContentFactory.jsonBuilder().prettyPrint(); + + otherBuilder.startObject(); + ex.toXContent(otherBuilder, ToXContent.EMPTY_PARAMS); + otherBuilder.endObject(); + assertEquals(otherBuilder.string(), builder.string()); + } + } + + public void testSerializeElasticsearchException() throws IOException { + BytesStreamOutput out = new BytesStreamOutput(); + QueryParsingException ex = new QueryParsingException(new Index("foo"), "foobar"); + out.writeThrowable(ex); + + BytesStreamInput in = new BytesStreamInput(out.bytes()); + QueryParsingException e = in.readThrowable(); + assertEquals(ex.index(), e.index()); + assertEquals(ex.getMessage(), e.getMessage()); + } + } \ No newline at end of file diff --git a/src/test/java/org/elasticsearch/action/bulk/BulkProcessorClusterSettingsTests.java b/src/test/java/org/elasticsearch/action/bulk/BulkProcessorClusterSettingsTests.java index 6b9379fe0527f..5140df378ddfd 100644 --- a/src/test/java/org/elasticsearch/action/bulk/BulkProcessorClusterSettingsTests.java +++ b/src/test/java/org/elasticsearch/action/bulk/BulkProcessorClusterSettingsTests.java @@ -48,7 +48,7 @@ public void testBulkProcessorAutoCreateRestrictions() throws Exception { assertEquals(3, responses.length); assertFalse("Operation on existing index should succeed", responses[0].isFailed()); assertTrue("Missing index should have been flagged", responses[1].isFailed()); - assertEquals("IndexMissingException[[wontwork] missing]", responses[1].getFailureMessage()); + assertEquals("[wontwork] no such index", responses[1].getFailureMessage()); assertFalse("Operation on existing index should succeed", responses[2].isFailed()); } } diff --git a/src/test/java/org/elasticsearch/cluster/metadata/MetaDataTests.java b/src/test/java/org/elasticsearch/cluster/metadata/MetaDataTests.java index e63927c7933b7..3349b33ed60ef 100644 --- a/src/test/java/org/elasticsearch/cluster/metadata/MetaDataTests.java +++ b/src/test/java/org/elasticsearch/cluster/metadata/MetaDataTests.java @@ -441,7 +441,8 @@ public void testIndexOptions_singleIndexNoExpandWildcards() { md.concreteIndices(IndicesOptions.strictSingleIndexNoExpandForbidClosed(), "foofoo-closed", "foofoobar"); fail(); } catch(IndexClosedException e) { - assertThat(e.getMessage(), containsString("[foofoo-closed] closed")); + assertThat(e.getMessage(), equalTo("closed")); + assertEquals(e.index().getName(), "foofoo-closed"); } String[] results = md.concreteIndices(IndicesOptions.strictSingleIndexNoExpandForbidClosed(), "foo", "barbaz"); diff --git a/src/test/java/org/elasticsearch/deleteByQuery/DeleteByQueryTests.java b/src/test/java/org/elasticsearch/deleteByQuery/DeleteByQueryTests.java index ffc8db1d36b61..877714681c69c 100644 --- a/src/test/java/org/elasticsearch/deleteByQuery/DeleteByQueryTests.java +++ b/src/test/java/org/elasticsearch/deleteByQuery/DeleteByQueryTests.java @@ -120,7 +120,7 @@ public void testFailure() throws Exception { assertThat(response.getIndices().size(), equalTo(1)); assertThat(response.getIndices().get("test").getShardInfo().getFailures().length, equalTo(twitter.numPrimaries)); for (ActionWriteResponse.ShardInfo.Failure failure : response.getIndices().get("test").getShardInfo().getFailures()) { - assertThat(failure.reason(), containsString("[test] [has_child] query and filter unsupported in delete_by_query api")); + assertThat(failure.reason(), containsString("[has_child] query and filter unsupported in delete_by_query api")); assertThat(failure.status(), equalTo(RestStatus.BAD_REQUEST)); assertThat(failure.shardId(), greaterThan(-1)); } diff --git a/src/test/java/org/elasticsearch/document/BulkTests.java b/src/test/java/org/elasticsearch/document/BulkTests.java index f49914606dd6b..380828372bb0b 100644 --- a/src/test/java/org/elasticsearch/document/BulkTests.java +++ b/src/test/java/org/elasticsearch/document/BulkTests.java @@ -133,7 +133,7 @@ public void testBulkUpdate_simple() throws Exception { assertThat(bulkResponse.getItems()[1].getResponse(), nullValue()); assertThat(bulkResponse.getItems()[1].getFailure().getIndex(), equalTo("test")); assertThat(bulkResponse.getItems()[1].getFailure().getId(), equalTo("7")); - assertThat(bulkResponse.getItems()[1].getFailure().getMessage(), containsString("DocumentMissingException")); + assertThat(bulkResponse.getItems()[1].getFailure().getMessage(), containsString("document missing")); assertThat(((UpdateResponse) bulkResponse.getItems()[2].getResponse()).getId(), equalTo("2")); assertThat(((UpdateResponse) bulkResponse.getItems()[2].getResponse()).getIndex(), equalTo("test")); assertThat(((UpdateResponse) bulkResponse.getItems()[2].getResponse()).getVersion(), equalTo(3l)); @@ -173,7 +173,7 @@ public void testBulkVersioning() throws Exception { .add(client().prepareUpdate("test", "type", "2").setDoc("field", "2")) .add(client().prepareUpdate("test", "type", "1").setVersion(2l).setDoc("field", "3")).get(); - assertThat(bulkResponse.getItems()[0].getFailureMessage(), containsString("Version")); + assertThat(bulkResponse.getItems()[0].getFailureMessage(), containsString("version conflict")); assertThat(((UpdateResponse) bulkResponse.getItems()[1].getResponse()).getVersion(), equalTo(2l)); assertThat(((UpdateResponse) bulkResponse.getItems()[2].getResponse()).getVersion(), equalTo(3l)); @@ -194,7 +194,7 @@ public void testBulkVersioning() throws Exception { .add(client().prepareUpdate("test", "type", "e1").setDoc("field", "3").setVersion(20).setVersionType(VersionType.FORCE)) .add(client().prepareUpdate("test", "type", "e1").setDoc("field", "3").setVersion(20).setVersionType(VersionType.INTERNAL)).get(); - assertThat(bulkResponse.getItems()[0].getFailureMessage(), containsString("Version")); + assertThat(bulkResponse.getItems()[0].getFailureMessage(), containsString("version conflict")); assertThat(((UpdateResponse) bulkResponse.getItems()[1].getResponse()).getVersion(), equalTo(20l)); assertThat(((UpdateResponse) bulkResponse.getItems()[2].getResponse()).getVersion(), equalTo(21l)); } @@ -325,7 +325,7 @@ public void testBulkUpdate_largerVolume() throws Exception { int id = i + (numDocs / 2); if (i >= (numDocs / 2)) { assertThat(response.getItems()[i].getFailure().getId(), equalTo(Integer.toString(id))); - assertThat(response.getItems()[i].getFailure().getMessage(), containsString("DocumentMissingException")); + assertThat(response.getItems()[i].getFailure().getMessage(), containsString("document missing")); } else { assertThat(response.getItems()[i].getId(), equalTo(Integer.toString(id))); assertThat(response.getItems()[i].getVersion(), equalTo(3l)); diff --git a/src/test/java/org/elasticsearch/index/query/SimpleIndexQueryParserTests.java b/src/test/java/org/elasticsearch/index/query/SimpleIndexQueryParserTests.java index 6e928ca4f814e..b258420a24543 100644 --- a/src/test/java/org/elasticsearch/index/query/SimpleIndexQueryParserTests.java +++ b/src/test/java/org/elasticsearch/index/query/SimpleIndexQueryParserTests.java @@ -1191,7 +1191,7 @@ public void testTermsQueryWithMultipleFields() throws IOException { queryParser.parse(query).query(); fail(); } catch (QueryParsingException ex) { - assertThat(ex.getMessage(), equalTo("[test] [terms] query does not support multiple fields")); + assertThat(ex.getMessage(), equalTo("[terms] query does not support multiple fields")); } } @@ -1207,7 +1207,7 @@ public void testTermsFilterWithMultipleFields() throws IOException { queryParser.parse(query).query(); fail(); } catch (QueryParsingException ex) { - assertThat(ex.getMessage(), equalTo("[test] [terms] filter does not support multiple fields")); + assertThat(ex.getMessage(), equalTo("[terms] filter does not support multiple fields")); } } diff --git a/src/test/java/org/elasticsearch/indices/memory/breaker/CircuitBreakerServiceTests.java b/src/test/java/org/elasticsearch/indices/memory/breaker/CircuitBreakerServiceTests.java index 311449aaece55..f09562f690e50 100644 --- a/src/test/java/org/elasticsearch/indices/memory/breaker/CircuitBreakerServiceTests.java +++ b/src/test/java/org/elasticsearch/indices/memory/breaker/CircuitBreakerServiceTests.java @@ -241,8 +241,8 @@ public void testParentChecking() throws Exception { fail("should have thrown an exception"); } catch (Exception e) { String errMsg = "[fielddata] Data too large, data for [test] would be larger than limit of [10/10b]"; - assertThat("Exception: " + ExceptionsHelper.unwrapCause(e) + " should contain a CircuitBreakingException", - ExceptionsHelper.unwrapCause(e).getMessage().contains(errMsg), equalTo(true)); + assertThat("Exception: " + e.toString() + " should contain a CircuitBreakingException", + e.toString().contains(errMsg), equalTo(true)); } assertFailures(client.prepareSearch("cb-test").setQuery(matchAllQuery()).addSort("test", SortOrder.DESC), @@ -263,8 +263,8 @@ public void testParentChecking() throws Exception { fail("should have thrown an exception"); } catch (Exception e) { String errMsg = "[parent] Data too large, data for [test] would be larger than limit of [15/15b]"; - assertThat("Exception: " + ExceptionsHelper.unwrapCause(e) + " should contain a CircuitBreakingException", - ExceptionsHelper.unwrapCause(e).getMessage().contains(errMsg), equalTo(true)); + assertThat("Exception: " +e.toString() + " should contain a CircuitBreakingException", + e.toString().contains(errMsg), equalTo(true)); } } @@ -297,8 +297,8 @@ public void testRequestBreaker() throws Exception { fail("aggregation should have tripped the breaker"); } catch (Exception e) { String errMsg = "CircuitBreakingException[[request] Data too large, data for [] would be larger than limit of [10/10b]]"; - assertThat("Exception: " + ExceptionsHelper.unwrapCause(e) + " should contain a CircuitBreakingException", - ExceptionsHelper.unwrapCause(e).getMessage().contains(errMsg), equalTo(true)); + assertThat("Exception: " + e.toString() + " should contain a CircuitBreakingException", + e.toString().contains(errMsg), equalTo(true)); } } diff --git a/src/test/java/org/elasticsearch/indices/template/SimpleIndexTemplateTests.java b/src/test/java/org/elasticsearch/indices/template/SimpleIndexTemplateTests.java index 39a54516e9bf0..e02c2bef8b40e 100644 --- a/src/test/java/org/elasticsearch/indices/template/SimpleIndexTemplateTests.java +++ b/src/test/java/org/elasticsearch/indices/template/SimpleIndexTemplateTests.java @@ -495,7 +495,7 @@ public void testAliasInvalidFilterValidJson() throws Exception { } catch(ElasticsearchIllegalArgumentException e) { assertThat(e.getMessage(), equalTo("failed to parse filter for alias [invalid_alias]")); assertThat(e.getCause(), instanceOf(QueryParsingException.class)); - assertThat(e.getCause().getMessage(), equalTo("[test] No filter registered for [invalid]")); + assertThat(e.getCause().getMessage(), equalTo("No filter registered for [invalid]")); } } @@ -530,7 +530,7 @@ public void testAliasNameExistingIndex() throws Exception { createIndex("test"); fail("index creation should have failed due to alias with existing index name in mathching index template"); } catch(InvalidAliasNameException e) { - assertThat(e.getMessage(), equalTo("[test] Invalid alias name [index], an index exists with the same name as the alias")); + assertThat(e.getMessage(), equalTo("Invalid alias name [index], an index exists with the same name as the alias")); } } diff --git a/src/test/java/org/elasticsearch/nested/SimpleNestedTests.java b/src/test/java/org/elasticsearch/nested/SimpleNestedTests.java index 9ee0ecba47f35..fc95131d250b4 100644 --- a/src/test/java/org/elasticsearch/nested/SimpleNestedTests.java +++ b/src/test/java/org/elasticsearch/nested/SimpleNestedTests.java @@ -707,7 +707,7 @@ public void testSimpleNestedSorting() throws Exception { .execute().actionGet(); Assert.fail("SearchPhaseExecutionException should have been thrown"); } catch (SearchPhaseExecutionException e) { - assertThat(e.getMessage(), containsString("type [string] doesn't support mode [SUM]")); + assertThat(e.toString(), containsString("type [string] doesn't support mode [SUM]")); } } diff --git a/src/test/java/org/elasticsearch/rest/BytesRestResponseTests.java b/src/test/java/org/elasticsearch/rest/BytesRestResponseTests.java index 989ea7194fc88..784015e9db041 100644 --- a/src/test/java/org/elasticsearch/rest/BytesRestResponseTests.java +++ b/src/test/java/org/elasticsearch/rest/BytesRestResponseTests.java @@ -20,11 +20,18 @@ package org.elasticsearch.rest; import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.action.search.SearchPhaseExecutionException; +import org.elasticsearch.action.search.ShardSearchFailure; +import org.elasticsearch.index.Index; +import org.elasticsearch.index.query.QueryParsingException; +import org.elasticsearch.search.SearchShardTarget; import org.elasticsearch.test.ElasticsearchTestCase; import org.elasticsearch.test.rest.FakeRestRequest; +import org.elasticsearch.transport.RemoteTransportException; import org.junit.Test; import java.io.FileNotFoundException; +import java.io.IOException; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.containsString; @@ -70,8 +77,8 @@ public void testDetailedExceptionMessage() throws Exception { Throwable t = new ElasticsearchException("an error occurred reading data", new FileNotFoundException("/foo/bar")); BytesRestResponse response = new BytesRestResponse(channel, t); String text = response.content().toUtf8(); - assertThat(text, containsString("ElasticsearchException[an error occurred reading data]")); - assertThat(text, containsString("FileNotFoundException[/foo/bar]")); + assertThat(text, containsString("{\"type\":\"exception\",\"reason\":\"an error occurred reading data\"}")); + assertThat(text, containsString("{\"type\":\"file_not_found_exception\",\"reason\":\"/foo/bar\"}")); } @Test @@ -97,11 +104,21 @@ public void testErrorTrace() throws Exception { Throwable t = new Throwable("an error occurred reading data", new FileNotFoundException("/foo/bar")); BytesRestResponse response = new BytesRestResponse(channel, t); String text = response.content().toUtf8(); - assertThat(text, containsString("\"error\":\"Throwable[an error occurred reading data]")); - assertThat(text, containsString("FileNotFoundException[/foo/bar]")); + assertThat(text, containsString("\"type\":\"throwable\",\"reason\":\"an error occurred reading data\"")); + assertThat(text, containsString("{\"type\":\"file_not_found_exception\",\"reason\":\"/foo/bar\"}")); assertThat(text, containsString("\"error_trace\":{\"message\":\"an error occurred reading data\"")); } + public void testGuessRootCause() throws IOException { + RestRequest request = new FakeRestRequest(); + RestChannel channel = new DetailedExceptionRestChannel(request); + + Throwable t = new ElasticsearchException("an error occurred reading data", new FileNotFoundException("/foo/bar")); + BytesRestResponse response = new BytesRestResponse(channel, t); + String text = response.content().toUtf8(); + assertThat(text, containsString("{\"root_cause\":[{\"type\":\"exception\",\"reason\":\"an error occurred reading data\"}]")); + } + @Test public void testNullThrowable() throws Exception { RestRequest request = new FakeRestRequest(); @@ -109,10 +126,47 @@ public void testNullThrowable() throws Exception { BytesRestResponse response = new BytesRestResponse(channel, null); String text = response.content().toUtf8(); - assertThat(text, containsString("\"error\":\"Unknown\"")); + assertThat(text, containsString("\"error\":\"unknown\"")); assertThat(text, not(containsString("error_trace"))); } + @Test + public void testConvert() throws IOException { + RestRequest request = new FakeRestRequest(); + request.params().put("pretty", "true"); + RestChannel channel = new DetailedExceptionRestChannel(request); + ShardSearchFailure failure = new ShardSearchFailure(new QueryParsingException(new Index("foo"), "foobar"), new SearchShardTarget("node_1", "foo", 1)); + ShardSearchFailure failure1 = new ShardSearchFailure(new QueryParsingException(new Index("foo"), "foobar"), new SearchShardTarget("node_1", "foo", 2)); + SearchPhaseExecutionException ex = new SearchPhaseExecutionException("search", "all shards failed", new ShardSearchFailure[] {failure, failure1}); + BytesRestResponse response = new BytesRestResponse(channel, new RemoteTransportException("foo", ex)); + String text = response.content().toUtf8(); + String expected = "{\n" + + " \"error\" : {\n" + + " \"root_cause\" : [ {\n" + + " \"type\" : \"query_parsing_exception\",\n" + + " \"reason\" : \"foobar\",\n" + + " \"index\" : \"foo\"\n" + + " } ],\n" + + " \"type\" : \"search_phase_execution_exception\",\n" + + " \"reason\" : \"all shards failed\",\n" + + " \"phase\" : \"search\",\n" + + " \"grouped\" : true,\n" + + " \"failed_shards\" : [ {\n" + + " \"shard\" : 1,\n" + + " \"index\" : \"foo\",\n" + + " \"node\" : \"node_1\",\n" + + " \"reason\" : {\n" + + " \"type\" : \"query_parsing_exception\",\n" + + " \"reason\" : \"foobar\",\n" + + " \"index\" : \"foo\"\n" + + " }\n" + + " } ]\n" + + " },\n" + + " \"status\" : 400\n" + + "}"; + assertEquals(expected.trim(), text.trim()); + } + private static class ExceptionWithHeaders extends ElasticsearchException.WithRestHeaders { ExceptionWithHeaders() { diff --git a/src/test/java/org/elasticsearch/script/GroovySandboxScriptTests.java b/src/test/java/org/elasticsearch/script/GroovySandboxScriptTests.java index 8e521a6f39280..c575d9152a1d7 100644 --- a/src/test/java/org/elasticsearch/script/GroovySandboxScriptTests.java +++ b/src/test/java/org/elasticsearch/script/GroovySandboxScriptTests.java @@ -153,8 +153,7 @@ public void testFailure(String script, String failMessage) { "; doc['foo'].value + 2\", \"type\": \"number\", \"lang\": \"groovy\"}}}").get(); fail("script: " + script + " failed to be caught be the sandbox!"); } catch (SearchPhaseExecutionException e) { - String msg = ExceptionsHelper.detailedMessage(ExceptionsHelper.unwrapCause(e)); - assertThat("script failed, but with incorrect message: " + msg, msg.contains(failMessage), equalTo(true)); + assertThat("script failed, but with incorrect message: " + e.toString(), e.toString().contains(failMessage), equalTo(true)); } } } diff --git a/src/test/java/org/elasticsearch/script/GroovyScriptTests.java b/src/test/java/org/elasticsearch/script/GroovyScriptTests.java index 801f4b36e40c4..657d2bc361ebd 100644 --- a/src/test/java/org/elasticsearch/script/GroovyScriptTests.java +++ b/src/test/java/org/elasticsearch/script/GroovyScriptTests.java @@ -76,12 +76,12 @@ public void testGroovyExceptionSerialization() throws Exception { client().prepareSearch("test").setQuery(constantScoreQuery(scriptFilter("1 == not_found").lang(GroovyScriptEngineService.NAME))).get(); fail("should have thrown an exception"); } catch (SearchPhaseExecutionException e) { - assertThat(ExceptionsHelper.detailedMessage(e) + "should not contained NotSerializableTransportException", - ExceptionsHelper.detailedMessage(e).contains("NotSerializableTransportException"), equalTo(false)); - assertThat(ExceptionsHelper.detailedMessage(e) + "should have contained GroovyScriptExecutionException", - ExceptionsHelper.detailedMessage(e).contains("GroovyScriptExecutionException"), equalTo(true)); - assertThat(ExceptionsHelper.detailedMessage(e) + "should have contained not_found", - ExceptionsHelper.detailedMessage(e).contains("No such property: not_found"), equalTo(true)); + assertThat(e.toString()+ "should not contained NotSerializableTransportException", + e.toString().contains("NotSerializableTransportException"), equalTo(false)); + assertThat(e.toString()+ "should have contained GroovyScriptExecutionException", + e.toString().contains("GroovyScriptExecutionException"), equalTo(true)); + assertThat(e.toString()+ "should have contained not_found", + e.toString().contains("No such property: not_found"), equalTo(true)); } try { @@ -89,12 +89,12 @@ public void testGroovyExceptionSerialization() throws Exception { scriptFilter("assert false").lang("groovy"))).get(); fail("should have thrown an exception"); } catch (SearchPhaseExecutionException e) { - assertThat(ExceptionsHelper.detailedMessage(e) + "should not contained NotSerializableTransportException", - ExceptionsHelper.detailedMessage(e).contains("NotSerializableTransportException"), equalTo(false)); - assertThat(ExceptionsHelper.detailedMessage(e) + "should have contained GroovyScriptExecutionException", - ExceptionsHelper.detailedMessage(e).contains("GroovyScriptExecutionException"), equalTo(true)); - assertThat(ExceptionsHelper.detailedMessage(e) + "should have contained an assert error", - ExceptionsHelper.detailedMessage(e).contains("PowerAssertionError[assert false"), equalTo(true)); + assertThat(e.toString()+ "should not contained NotSerializableTransportException", + e.toString().contains("NotSerializableTransportException"), equalTo(false)); + assertThat(e.toString()+ "should have contained GroovyScriptExecutionException", + e.toString().contains("GroovyScriptExecutionException"), equalTo(true)); + assertThat(e.toString()+ "should have contained an assert error", + e.toString().contains("PowerAssertionError[assert false"), equalTo(true)); } } diff --git a/src/test/java/org/elasticsearch/script/IndexLookupTests.java b/src/test/java/org/elasticsearch/script/IndexLookupTests.java index 85940106a35d5..a9a61555b3a93 100644 --- a/src/test/java/org/elasticsearch/script/IndexLookupTests.java +++ b/src/test/java/org/elasticsearch/script/IndexLookupTests.java @@ -178,8 +178,8 @@ public void testCallWithDifferentFlagsFails() throws Exception { client().prepareSearch("test").setQuery(QueryBuilders.matchAllQuery()).addScriptField("tvtest", script).execute().actionGet(); } catch (SearchPhaseExecutionException e) { assertThat( - "got: " + e.getDetailedMessage(), - e.getDetailedMessage() + "got: " + e.toString(), + e.toString() .indexOf( "You must call get with all required flags! Instead of _index['int_payload_field'].get('b', _FREQUENCIES) and _index['int_payload_field'].get('b', _POSITIONS) call _index['int_payload_field'].get('b', _FREQUENCIES | _POSITIONS) once]"), Matchers.greaterThan(-1)); diff --git a/src/test/java/org/elasticsearch/script/IndexedScriptTests.java b/src/test/java/org/elasticsearch/script/IndexedScriptTests.java index ac44e4d6dbc73..1064bf464c729 100644 --- a/src/test/java/org/elasticsearch/script/IndexedScriptTests.java +++ b/src/test/java/org/elasticsearch/script/IndexedScriptTests.java @@ -158,20 +158,20 @@ public void testAllOpsDisabledIndexedScripts() throws IOException { fail("update script should have been rejected"); } catch(Exception e) { assertThat(e.getMessage(), containsString("failed to execute script")); - assertThat(ExceptionsHelper.detailedMessage(e), containsString("scripts of type [indexed], operation [update] and lang [expression] are disabled")); + assertThat(e.toString(), containsString("scripts of type [indexed], operation [update] and lang [expression] are disabled")); } try { String query = "{ \"script_fields\" : { \"test1\" : { \"script_id\" : \"script1\", \"lang\":\"expression\" }}}"; client().prepareSearch().setSource(query).setIndices("test").setTypes("scriptTest").get(); fail("search script should have been rejected"); } catch(Exception e) { - assertThat(e.getMessage(), containsString("scripts of type [indexed], operation [search] and lang [expression] are disabled")); + assertThat(e.toString(), containsString("scripts of type [indexed], operation [search] and lang [expression] are disabled")); } try { String source = "{\"aggs\": {\"test\": { \"terms\" : { \"script_id\":\"script1\", \"script_lang\":\"expression\" } } } }"; client().prepareSearch("test").setSource(source).get(); } catch(Exception e) { - assertThat(e.getMessage(), containsString("scripts of type [indexed], operation [aggs] and lang [expression] are disabled")); + assertThat(e.toString(), containsString("scripts of type [indexed], operation [aggs] and lang [expression] are disabled")); } } } diff --git a/src/test/java/org/elasticsearch/script/OnDiskScriptTests.java b/src/test/java/org/elasticsearch/script/OnDiskScriptTests.java index 78a28520d4adc..88471f712b4ec 100644 --- a/src/test/java/org/elasticsearch/script/OnDiskScriptTests.java +++ b/src/test/java/org/elasticsearch/script/OnDiskScriptTests.java @@ -107,7 +107,7 @@ public void testPartiallyDisabledOnDiskScripts() throws ExecutionException, Inte client().prepareSearch("test").setSource(source).get(); fail("aggs script should have been rejected"); } catch(Exception e) { - assertThat(ExceptionsHelper.detailedMessage(e), containsString("scripts of type [file], operation [aggs] and lang [expression] are disabled")); + assertThat(e.toString(), containsString("scripts of type [file], operation [aggs] and lang [expression] are disabled")); } String query = "{ \"query\" : { \"match_all\": {}} , \"script_fields\" : { \"test1\" : { \"script_file\" : \"script1\", \"lang\":\"expression\" }}, size:1}"; @@ -128,21 +128,21 @@ public void testAllOpsDisabledOnDiskScripts() { client().prepareSearch("test").setSource(source).get(); fail("aggs script should have been rejected"); } catch(Exception e) { - assertThat(ExceptionsHelper.detailedMessage(e), containsString("scripts of type [file], operation [aggs] and lang [mustache] are disabled")); + assertThat(e.toString(), containsString("scripts of type [file], operation [aggs] and lang [mustache] are disabled")); } String query = "{ \"query\" : { \"match_all\": {}} , \"script_fields\" : { \"test1\" : { \"script_file\" : \"script1\", \"lang\":\"mustache\" }}, size:1}"; try { client().prepareSearch().setSource(query).setIndices("test").setTypes("scriptTest").get(); fail("search script should have been rejected"); } catch(Exception e) { - assertThat(ExceptionsHelper.detailedMessage(e), containsString("scripts of type [file], operation [search] and lang [mustache] are disabled")); + assertThat(e.toString(), containsString("scripts of type [file], operation [search] and lang [mustache] are disabled")); } try { client().prepareUpdate("test", "scriptTest", "1").setScript("script1", ScriptService.ScriptType.FILE).setScriptLang(MustacheScriptEngineService.NAME).get(); fail("update script should have been rejected"); } catch(Exception e) { assertThat(e.getMessage(), containsString("failed to execute script")); - assertThat(ExceptionsHelper.detailedMessage(e), containsString("scripts of type [file], operation [update] and lang [mustache] are disabled")); + assertThat(e.getCause().toString(), containsString("scripts of type [file], operation [update] and lang [mustache] are disabled")); } } } diff --git a/src/test/java/org/elasticsearch/script/SandboxDisabledTests.java b/src/test/java/org/elasticsearch/script/SandboxDisabledTests.java index 0a759c07b9887..0799fa0ddbdde 100644 --- a/src/test/java/org/elasticsearch/script/SandboxDisabledTests.java +++ b/src/test/java/org/elasticsearch/script/SandboxDisabledTests.java @@ -51,7 +51,7 @@ public void testScriptingDisabledWhileSandboxDisabled() { "\"sort\":{\"_script\": {\"script\": \"doc['foo'].value + 2\", \"type\": \"number\", \"lang\": \"groovy\"}}}").get(); fail("shards should fail because the sandbox and dynamic scripting are disabled"); } catch (Exception e) { - assertThat(ExceptionsHelper.detailedMessage(e), containsString("scripts of type [inline], operation [search] and lang [groovy] are disabled")); + assertThat(e.toString(), containsString("scripts of type [inline], operation [search] and lang [groovy] are disabled")); } } } diff --git a/src/test/java/org/elasticsearch/script/expression/ExpressionScriptTests.java b/src/test/java/org/elasticsearch/script/expression/ExpressionScriptTests.java index 9ef64d8247729..8ee8d1dcbf1e9 100644 --- a/src/test/java/org/elasticsearch/script/expression/ExpressionScriptTests.java +++ b/src/test/java/org/elasticsearch/script/expression/ExpressionScriptTests.java @@ -111,10 +111,10 @@ public void testMissingField() throws Exception { buildRequest("doc['bogus'].value").get(); fail("Expected missing field to cause failure"); } catch (SearchPhaseExecutionException e) { - assertThat(ExceptionsHelper.detailedMessage(e) + "should have contained ExpressionScriptCompilationException", - ExceptionsHelper.detailedMessage(e).contains("ExpressionScriptCompilationException"), equalTo(true)); - assertThat(ExceptionsHelper.detailedMessage(e) + "should have contained missing field error", - ExceptionsHelper.detailedMessage(e).contains("does not exist in mappings"), equalTo(true)); + assertThat(e.toString() + "should have contained ExpressionScriptCompilationException", + e.toString().contains("ExpressionScriptCompilationException"), equalTo(true)); + assertThat(e.toString() + "should have contained missing field error", + e.toString().contains("does not exist in mappings"), equalTo(true)); } } @@ -141,10 +141,10 @@ public void testCompileFailure() { buildRequest("garbage%@#%@").get(); fail("Expected expression compilation failure"); } catch (SearchPhaseExecutionException e) { - assertThat(ExceptionsHelper.detailedMessage(e) + "should have contained ExpressionScriptCompilationException", - ExceptionsHelper.detailedMessage(e).contains("ExpressionScriptCompilationException"), equalTo(true)); - assertThat(ExceptionsHelper.detailedMessage(e) + "should have contained compilation failure", - ExceptionsHelper.detailedMessage(e).contains("Failed to parse expression"), equalTo(true)); + assertThat(e.toString() + "should have contained ExpressionScriptCompilationException", + e.toString().contains("ExpressionScriptCompilationException"), equalTo(true)); + assertThat(e.toString() + "should have contained compilation failure", + e.toString().contains("Failed to parse expression"), equalTo(true)); } } @@ -154,10 +154,10 @@ public void testNonNumericParam() { buildRequest("a", "a", "astring").get(); fail("Expected string parameter to cause failure"); } catch (SearchPhaseExecutionException e) { - assertThat(ExceptionsHelper.detailedMessage(e) + "should have contained ExpressionScriptCompilationException", - ExceptionsHelper.detailedMessage(e).contains("ExpressionScriptCompilationException"), equalTo(true)); - assertThat(ExceptionsHelper.detailedMessage(e) + "should have contained non-numeric parameter error", - ExceptionsHelper.detailedMessage(e).contains("must be a numeric type"), equalTo(true)); + assertThat(e.toString() + "should have contained ExpressionScriptCompilationException", + e.toString().contains("ExpressionScriptCompilationException"), equalTo(true)); + assertThat(e.toString() + "should have contained non-numeric parameter error", + e.toString().contains("must be a numeric type"), equalTo(true)); } } @@ -167,10 +167,10 @@ public void testNonNumericField() { buildRequest("doc['text'].value").get(); fail("Expected text field to cause execution failure"); } catch (SearchPhaseExecutionException e) { - assertThat(ExceptionsHelper.detailedMessage(e) + "should have contained ExpressionScriptCompilationException", - ExceptionsHelper.detailedMessage(e).contains("ExpressionScriptCompilationException"), equalTo(true)); - assertThat(ExceptionsHelper.detailedMessage(e) + "should have contained non-numeric field error", - ExceptionsHelper.detailedMessage(e).contains("must be numeric"), equalTo(true)); + assertThat(e.toString() + "should have contained ExpressionScriptCompilationException", + e.toString().contains("ExpressionScriptCompilationException"), equalTo(true)); + assertThat(e.toString() + "should have contained non-numeric field error", + e.toString().contains("must be numeric"), equalTo(true)); } } @@ -180,10 +180,10 @@ public void testInvalidGlobalVariable() { buildRequest("bogus").get(); fail("Expected bogus variable to cause execution failure"); } catch (SearchPhaseExecutionException e) { - assertThat(ExceptionsHelper.detailedMessage(e) + "should have contained ExpressionScriptCompilationException", - ExceptionsHelper.detailedMessage(e).contains("ExpressionScriptCompilationException"), equalTo(true)); - assertThat(ExceptionsHelper.detailedMessage(e) + "should have contained unknown variable error", - ExceptionsHelper.detailedMessage(e).contains("Unknown variable"), equalTo(true)); + assertThat(e.toString() + "should have contained ExpressionScriptCompilationException", + e.toString().contains("ExpressionScriptCompilationException"), equalTo(true)); + assertThat(e.toString() + "should have contained unknown variable error", + e.toString().contains("Unknown variable"), equalTo(true)); } } @@ -193,10 +193,10 @@ public void testDocWithoutField() { buildRequest("doc").get(); fail("Expected doc variable without field to cause execution failure"); } catch (SearchPhaseExecutionException e) { - assertThat(ExceptionsHelper.detailedMessage(e) + "should have contained ExpressionScriptCompilationException", - ExceptionsHelper.detailedMessage(e).contains("ExpressionScriptCompilationException"), equalTo(true)); - assertThat(ExceptionsHelper.detailedMessage(e) + "should have contained a missing specific field error", - ExceptionsHelper.detailedMessage(e).contains("must be used with a specific field"), equalTo(true)); + assertThat(e.toString() + "should have contained ExpressionScriptCompilationException", + e.toString().contains("ExpressionScriptCompilationException"), equalTo(true)); + assertThat(e.toString() + "should have contained a missing specific field error", + e.toString().contains("must be used with a specific field"), equalTo(true)); } } @@ -206,10 +206,10 @@ public void testInvalidFieldMember() { buildRequest("doc['foo'].bogus").get(); fail("Expected bogus field member to cause execution failure"); } catch (SearchPhaseExecutionException e) { - assertThat(ExceptionsHelper.detailedMessage(e) + "should have contained ExpressionScriptCompilationException", - ExceptionsHelper.detailedMessage(e).contains("ExpressionScriptCompilationException"), equalTo(true)); - assertThat(ExceptionsHelper.detailedMessage(e) + "should have contained field member error", - ExceptionsHelper.detailedMessage(e).contains("Invalid member for field"), equalTo(true)); + assertThat(e.toString() + "should have contained ExpressionScriptCompilationException", + e.toString().contains("ExpressionScriptCompilationException"), equalTo(true)); + assertThat(e.toString() + "should have contained field member error", + e.toString().contains("Invalid member for field"), equalTo(true)); } } @@ -260,7 +260,7 @@ public void testStringSpecialValueVariable() throws Exception { assertThat(rsp.getShardFailures().length, greaterThan(0)); // at least the shards containing the docs should have failed message = rsp.getShardFailures()[0].reason(); } catch (SearchPhaseExecutionException e) { - message = ExceptionsHelper.detailedMessage(e); + message = e.toString(); } assertThat(message + "should have contained ExpressionScriptExecutionException", message.contains("ExpressionScriptExecutionException"), equalTo(true)); diff --git a/src/test/java/org/elasticsearch/search/aggregations/AggregationsIntegrationTests.java b/src/test/java/org/elasticsearch/search/aggregations/AggregationsIntegrationTests.java index e7b1d8fbc593b..640ac7ffb81fe 100644 --- a/src/test/java/org/elasticsearch/search/aggregations/AggregationsIntegrationTests.java +++ b/src/test/java/org/elasticsearch/search/aggregations/AggregationsIntegrationTests.java @@ -57,7 +57,7 @@ public void testScan() { client().prepareSearch("index").setSearchType(SearchType.SCAN).setScroll(new TimeValue(500)).addAggregation(terms("f").field("f")).get(); fail(); } catch (SearchPhaseExecutionException e) { - assertTrue(e.getMessage(), e.getMessage().contains("aggregations are not supported with search_type=scan")); + assertTrue(e.toString(), e.toString().contains("aggregations are not supported with search_type=scan")); } } diff --git a/src/test/java/org/elasticsearch/search/aggregations/bucket/DateHistogramTests.java b/src/test/java/org/elasticsearch/search/aggregations/bucket/DateHistogramTests.java index b34d09bfc1a04..b9f7e3e511d99 100644 --- a/src/test/java/org/elasticsearch/search/aggregations/bucket/DateHistogramTests.java +++ b/src/test/java/org/elasticsearch/search/aggregations/bucket/DateHistogramTests.java @@ -1314,7 +1314,7 @@ public void testExeptionOnNegativerInterval() { .actionGet(); fail(); } catch (SearchPhaseExecutionException e) { - assertThat(e.getMessage(), containsString("IllegalArgumentException")); + assertThat(e.toString(), containsString("IllegalArgumentException")); } } } diff --git a/src/test/java/org/elasticsearch/search/aggregations/bucket/HistogramTests.java b/src/test/java/org/elasticsearch/search/aggregations/bucket/HistogramTests.java index 58a50e8938ae2..9a6c7c0f9f14b 100644 --- a/src/test/java/org/elasticsearch/search/aggregations/bucket/HistogramTests.java +++ b/src/test/java/org/elasticsearch/search/aggregations/bucket/HistogramTests.java @@ -1017,7 +1017,7 @@ public void testExeptionOnNegativerInterval() { .addAggregation(histogram("histo").field(SINGLE_VALUED_FIELD_NAME).interval(-1).minDocCount(0)).execute().actionGet(); fail(); } catch (SearchPhaseExecutionException e) { - assertThat(e.getMessage(), containsString("Missing required field [interval]")); + assertThat(e.toString(), containsString("Missing required field [interval]")); } } diff --git a/src/test/java/org/elasticsearch/search/aggregations/bucket/NestedTests.java b/src/test/java/org/elasticsearch/search/aggregations/bucket/NestedTests.java index ac28cd4c8e4ca..d437eb34915bb 100644 --- a/src/test/java/org/elasticsearch/search/aggregations/bucket/NestedTests.java +++ b/src/test/java/org/elasticsearch/search/aggregations/bucket/NestedTests.java @@ -365,7 +365,7 @@ public void nestedOnObjectField() throws Exception { .execute().actionGet(); fail(); } catch (SearchPhaseExecutionException e) { - assertThat(e.getMessage(), containsString("[nested] nested path [incorrect] is not nested")); + assertThat(e.toString(), containsString("[nested] nested path [incorrect] is not nested")); } } diff --git a/src/test/java/org/elasticsearch/search/aggregations/bucket/TopHitsTests.java b/src/test/java/org/elasticsearch/search/aggregations/bucket/TopHitsTests.java index 0322b6cc8a7bb..70bedbdb40ff1 100644 --- a/src/test/java/org/elasticsearch/search/aggregations/bucket/TopHitsTests.java +++ b/src/test/java/org/elasticsearch/search/aggregations/bucket/TopHitsTests.java @@ -520,7 +520,7 @@ public void testInvalidSortField() throws Exception { ).get(); fail(); } catch (SearchPhaseExecutionException e) { - assertThat(e.getMessage(), containsString("No mapping found for [xyz] in order to sort on")); + assertThat(e.toString(), containsString("No mapping found for [xyz] in order to sort on")); } } @@ -553,7 +553,7 @@ public void testFailWithSubAgg() throws Exception { .get(); fail(); } catch (SearchPhaseExecutionException e) { - assertThat(e.getMessage(), containsString("Aggregator [top_tags_hits] of type [top_hits] cannot accept sub-aggregations")); + assertThat(e.toString(), containsString("Aggregator [top_tags_hits] of type [top_hits] cannot accept sub-aggregations")); } } diff --git a/src/test/java/org/elasticsearch/search/child/SimpleChildQuerySearchTests.java b/src/test/java/org/elasticsearch/search/child/SimpleChildQuerySearchTests.java index 00aad548d6466..a536f64260ddb 100644 --- a/src/test/java/org/elasticsearch/search/child/SimpleChildQuerySearchTests.java +++ b/src/test/java/org/elasticsearch/search/child/SimpleChildQuerySearchTests.java @@ -108,14 +108,7 @@ import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchHit; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchHits; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.hasId; -import static org.hamcrest.Matchers.anyOf; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.greaterThan; -import static org.hamcrest.Matchers.greaterThanOrEqualTo; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.Matchers.startsWith; +import static org.hamcrest.Matchers.*; /** * @@ -1612,13 +1605,13 @@ public void indexChildDocWithNoParentMapping() throws ElasticsearchException, IO client().prepareIndex("test", "child1", "c1").setParent("p1").setSource("c_field", "blue").get(); fail(); } catch (ElasticsearchIllegalArgumentException e) { - assertThat(e.getMessage(), equalTo("Can't specify parent if no parent field has been configured")); + assertThat(e.toString(), containsString("Can't specify parent if no parent field has been configured")); } try { client().prepareIndex("test", "child2", "c2").setParent("p1").setSource("c_field", "blue").get(); fail(); } catch (ElasticsearchIllegalArgumentException e) { - assertThat(e.getMessage(), equalTo("Can't specify parent if no parent field has been configured")); + assertThat(e.toString(), containsString("Can't specify parent if no parent field has been configured")); } refresh(); @@ -1645,7 +1638,7 @@ public void testAddingParentToExistingMapping() throws ElasticsearchException, I .endObject().endObject()).get(); fail(); } catch (MergeMappingException e) { - assertThat(e.getMessage(), equalTo("Merge failed with failures {[The _parent field's type option can't be changed: [null]->[parent]]}")); + assertThat(e.toString(), containsString("Merge failed with failures {[The _parent field's type option can't be changed: [null]->[parent]]}")); } } @@ -2332,7 +2325,7 @@ public void testMinMaxChildren() throws Exception { response = minMaxQuery("none", 3, 2, cutoff); fail(); } catch (SearchPhaseExecutionException e) { - assertThat(e.getMessage(), containsString("[has_child] 'max_children' is less than 'min_children'")); + assertThat(e.toString(), containsString("[has_child] 'max_children' is less than 'min_children'")); } // Score mode = SUM @@ -2412,7 +2405,7 @@ public void testMinMaxChildren() throws Exception { response = minMaxQuery("sum", 3, 2, cutoff); fail(); } catch (SearchPhaseExecutionException e) { - assertThat(e.getMessage(), containsString("[has_child] 'max_children' is less than 'min_children'")); + assertThat(e.toString(), containsString("[has_child] 'max_children' is less than 'min_children'")); } // Score mode = MAX @@ -2492,7 +2485,7 @@ public void testMinMaxChildren() throws Exception { response = minMaxQuery("max", 3, 2, cutoff); fail(); } catch (SearchPhaseExecutionException e) { - assertThat(e.getMessage(), containsString("[has_child] 'max_children' is less than 'min_children'")); + assertThat(e.toString(), containsString("[has_child] 'max_children' is less than 'min_children'")); } // Score mode = AVG @@ -2572,7 +2565,7 @@ public void testMinMaxChildren() throws Exception { response = minMaxQuery("avg", 3, 2, cutoff); fail(); } catch (SearchPhaseExecutionException e) { - assertThat(e.getMessage(), containsString("[has_child] 'max_children' is less than 'min_children'")); + assertThat(e.toString(), containsString("[has_child] 'max_children' is less than 'min_children'")); } // HasChildFilter @@ -2652,7 +2645,7 @@ public void testMinMaxChildren() throws Exception { response = minMaxFilter(3, 2, cutoff); fail(); } catch (SearchPhaseExecutionException e) { - assertThat(e.getMessage(), containsString("[has_child] 'max_children' is less than 'min_children'")); + assertThat(e.toString(), containsString("[has_child] 'max_children' is less than 'min_children'")); } } diff --git a/src/test/java/org/elasticsearch/search/functionscore/DecayFunctionScoreTests.java b/src/test/java/org/elasticsearch/search/functionscore/DecayFunctionScoreTests.java index 59ff93d27d820..315442a00227e 100644 --- a/src/test/java/org/elasticsearch/search/functionscore/DecayFunctionScoreTests.java +++ b/src/test/java/org/elasticsearch/search/functionscore/DecayFunctionScoreTests.java @@ -874,8 +874,8 @@ public void testMissingFunctionThrowsElasticsearchParseException() throws IOExce searchSource().query(query))).actionGet(); fail("Should fail with SearchPhaseExecutionException"); } catch (SearchPhaseExecutionException failure) { - assertTrue(failure.getMessage().contains("SearchParseException")); - assertFalse(failure.getMessage().contains("NullPointerException")); + assertTrue(failure.toString().contains("SearchParseException")); + assertFalse(failure.toString().contains("NullPointerException")); } query = "{\n" + @@ -908,26 +908,26 @@ public void testMissingFunctionThrowsElasticsearchParseException() throws IOExce searchSource().query(query))).actionGet(); fail("Should fail with SearchPhaseExecutionException"); } catch (SearchPhaseExecutionException failure) { - assertTrue(failure.getMessage().contains("SearchParseException")); - assertFalse(failure.getMessage().contains("NullPointerException")); - assertTrue(failure.getMessage().contains("One entry in functions list is missing a function")); + assertTrue(failure.toString().contains("SearchParseException")); + assertFalse(failure.toString().contains("NullPointerException")); + assertTrue(failure.toString().contains("One entry in functions list is missing a function")); } // next test java client try { client().prepareSearch("t").setQuery(QueryBuilders.functionScoreQuery(FilterBuilders.matchAllFilter(), null)).get(); } catch (ElasticsearchIllegalArgumentException failure) { - assertTrue(failure.getMessage().contains("function must not be null")); + assertTrue(failure.toString().contains("function must not be null")); } try { client().prepareSearch("t").setQuery(QueryBuilders.functionScoreQuery().add(FilterBuilders.matchAllFilter(), null)).get(); } catch (ElasticsearchIllegalArgumentException failure) { - assertTrue(failure.getMessage().contains("function must not be null")); + assertTrue(failure.toString().contains("function must not be null")); } try { client().prepareSearch("t").setQuery(QueryBuilders.functionScoreQuery().add(null)).get(); } catch (ElasticsearchIllegalArgumentException failure) { - assertTrue(failure.getMessage().contains("function must not be null")); + assertTrue(failure.toString().contains("function must not be null")); } } diff --git a/src/test/java/org/elasticsearch/search/query/SearchQueryTests.java b/src/test/java/org/elasticsearch/search/query/SearchQueryTests.java index d0a5a6b357b82..9d3b887fd196d 100644 --- a/src/test/java/org/elasticsearch/search/query/SearchQueryTests.java +++ b/src/test/java/org/elasticsearch/search/query/SearchQueryTests.java @@ -483,7 +483,7 @@ public void testOmitTermFreqsAndPositions() throws Exception { client().prepareSearch().setQuery(matchQuery("field1", "quick brown").type(MatchQueryBuilder.Type.PHRASE).slop(0)).get(); fail("SearchPhaseExecutionException should have been thrown"); } catch (SearchPhaseExecutionException e) { - assertTrue(e.getMessage().contains("IllegalStateException[field \"field1\" was indexed without position data; cannot run PhraseQuery")); + assertTrue(e.toString().contains("IllegalStateException[field \"field1\" was indexed without position data; cannot run PhraseQuery")); } cluster().wipeIndices("test"); } catch (MapperParsingException ex) { @@ -563,7 +563,7 @@ public void testDateRangeInQueryString() { fail("expected SearchPhaseExecutionException (total failure)"); } catch (SearchPhaseExecutionException e) { assertThat(e.status(), equalTo(RestStatus.BAD_REQUEST)); - assertThat(e.getMessage(), containsString("unit [D] not supported for date math")); + assertThat(e.toString(), containsString("unit [D] not supported for date math")); } } @@ -2493,8 +2493,8 @@ public void testIdsQueryWithInvalidValues() throws Exception { .get(); fail("query is invalid and should have produced a parse exception"); } catch (Exception e) { - assertThat("query could not be parsed due to bad format: " + e.getMessage(), - e.getMessage().contains("Illegal value for id, expecting a string or number, got: START_ARRAY"), + assertThat("query could not be parsed due to bad format: " + e.toString(), + e.toString().contains("Illegal value for id, expecting a string or number, got: START_ARRAY"), equalTo(true)); } } diff --git a/src/test/java/org/elasticsearch/search/simple/SimpleSearchTests.java b/src/test/java/org/elasticsearch/search/simple/SimpleSearchTests.java index 2e3276107fa3f..f4a2e81df613c 100644 --- a/src/test/java/org/elasticsearch/search/simple/SimpleSearchTests.java +++ b/src/test/java/org/elasticsearch/search/simple/SimpleSearchTests.java @@ -234,7 +234,7 @@ public void testInsaneFrom() throws Exception { client().prepareSearch("idx").setFrom(Integer.MAX_VALUE).get(); fail(); } catch (SearchPhaseExecutionException e) { - assertThat(e.getMessage(), containsString("Result window is too large, from + size must be less than or equal to:")); + assertThat(e.toString(), containsString("Result window is too large, from + size must be less than or equal to:")); } } } diff --git a/src/test/java/org/elasticsearch/search/sort/SimpleSortTests.java b/src/test/java/org/elasticsearch/search/sort/SimpleSortTests.java index b40e5547b1a08..7972df64741f6 100644 --- a/src/test/java/org/elasticsearch/search/sort/SimpleSortTests.java +++ b/src/test/java/org/elasticsearch/search/sort/SimpleSortTests.java @@ -1131,7 +1131,7 @@ public void testIgnoreUnmapped() throws Exception { } catch (SearchPhaseExecutionException e) { //we check that it's a parse failure rather than a different shard failure for (ShardSearchFailure shardSearchFailure : e.shardFailures()) { - assertThat(shardSearchFailure.reason(), containsString("Parse Failure [No mapping found for [kkk] in order to sort on]")); + assertThat(shardSearchFailure.toString(), containsString("[No mapping found for [kkk] in order to sort on]")); } } diff --git a/src/test/java/org/elasticsearch/search/suggest/CompletionSuggestSearchTests.java b/src/test/java/org/elasticsearch/search/suggest/CompletionSuggestSearchTests.java index b2528428297a0..f4c7c74933f03 100644 --- a/src/test/java/org/elasticsearch/search/suggest/CompletionSuggestSearchTests.java +++ b/src/test/java/org/elasticsearch/search/suggest/CompletionSuggestSearchTests.java @@ -23,7 +23,6 @@ import com.google.common.collect.Lists; import org.apache.lucene.util.LuceneTestCase.SuppressCodecs; -import org.elasticsearch.ExceptionsHelper; import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse; import org.elasticsearch.action.admin.indices.optimize.OptimizeResponse; import org.elasticsearch.action.admin.indices.segments.IndexShardSegments; @@ -50,7 +49,6 @@ import org.elasticsearch.search.suggest.completion.CompletionSuggestionBuilder; import org.elasticsearch.search.suggest.completion.CompletionSuggestionFuzzyBuilder; import org.elasticsearch.test.ElasticsearchIntegrationTest; -import org.elasticsearch.test.hamcrest.ElasticsearchAssertions; import org.junit.Test; import java.io.IOException; @@ -177,7 +175,7 @@ public void testThatWeightMustBeAnInteger() throws Exception { ).get(); fail("Indexing with a float weight was successful, but should not be"); } catch (MapperParsingException e) { - assertThat(ExceptionsHelper.detailedMessage(e), containsString("2.5")); + assertThat(e.toString(), containsString("2.5")); } } @@ -221,7 +219,7 @@ public void testThatWeightMustNotBeANonNumberString() throws Exception { ).get(); fail("Indexing with a non-number representing string as weight was successful, but should not be"); } catch (MapperParsingException e) { - assertThat(ExceptionsHelper.detailedMessage(e), containsString("thisIsNotValid")); + assertThat(e.toString(), containsString("thisIsNotValid")); } } @@ -239,7 +237,7 @@ public void testThatWeightAsStringMustBeInt() throws Exception { ).get(); fail("Indexing with weight string representing value > Int.MAX_VALUE was successful, but should not be"); } catch (MapperParsingException e) { - assertThat(ExceptionsHelper.detailedMessage(e), containsString(weight)); + assertThat(e.toString(), containsString(weight)); } } @@ -774,7 +772,7 @@ public void testThatSortingOnCompletionFieldReturnsUsefulException() throws Exce fail("Expected an exception due to trying to sort on completion field, but did not happen"); } catch (SearchPhaseExecutionException e) { assertThat(e.status().getStatus(), is(400)); - assertThat(e.getMessage(), containsString("Sorting not supported for field[" + FIELD + "]")); + assertThat(e.toString(), containsString("Sorting not supported for field[" + FIELD + "]")); } } @@ -1096,7 +1094,7 @@ public void testIssue5930() throws IOException { // Exception must be thrown assertFalse(true); } catch (SearchPhaseExecutionException e) { - assertTrue(e.getDetailedMessage().contains("found no fielddata type for field [" + FIELD + "]")); + assertTrue(e.toString().contains("found no fielddata type for field [" + FIELD + "]")); } } diff --git a/src/test/java/org/elasticsearch/test/hamcrest/ElasticsearchAssertions.java b/src/test/java/org/elasticsearch/test/hamcrest/ElasticsearchAssertions.java index c691f3c5834c2..0a52c36ce32a1 100644 --- a/src/test/java/org/elasticsearch/test/hamcrest/ElasticsearchAssertions.java +++ b/src/test/java/org/elasticsearch/test/hamcrest/ElasticsearchAssertions.java @@ -310,7 +310,7 @@ public static void assertFailures(SearchRequestBuilder searchRequestBuilder, Res assertVersionSerializable(searchResponse); } catch (SearchPhaseExecutionException e) { assertThat(e.status(), equalTo(restStatus)); - assertThat(e.getMessage(), reasonMatcher); + assertThat(e.toString(), reasonMatcher); for (ShardSearchFailure shardSearchFailure : e.shardFailures()) { assertThat(shardSearchFailure.status(), equalTo(restStatus)); assertThat(shardSearchFailure.reason(), reasonMatcher);