[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
This commit is contained in:
Simon Willnauer 2015-04-24 09:36:10 +02:00
parent c9d72431a3
commit 15d58d91f1
66 changed files with 737 additions and 275 deletions

View File

@ -14,7 +14,7 @@
wait_for_status: yellow wait_for_status: yellow
- do: - do:
catch: /RoutingMissingException/ catch: /routing_missing_exception/
create: create:
index: test_1 index: test_1
type: test type: test

View File

@ -89,7 +89,7 @@
type: test type: test
id: 1 id: 1
- do: - do:
catch: /AlreadyExpiredException/ catch: /already_expired_exception/
create: create:
index: test_1 index: test_1
type: test type: test

View File

@ -21,7 +21,7 @@
body: { foo: bar } body: { foo: bar }
- do: - do:
catch: /RoutingMissingException/ catch: /routing_missing_exception/
delete: delete:
index: test_1 index: test_1
type: test type: test

View File

@ -13,7 +13,7 @@
wait_for_status: yellow wait_for_status: yellow
- do: - do:
catch: /RoutingMissingException/ catch: /routing_missing_exception/
index: index:
index: test_1 index: test_1
type: test type: test

View File

@ -74,7 +74,7 @@
# with timestamp # with timestamp
- do: - do:
catch: /AlreadyExpiredException/ catch: /already_expired_exception/
index: index:
index: test_1 index: test_1
type: test type: test

View File

@ -13,27 +13,27 @@
wait_for_status: yellow wait_for_status: yellow
- do: - do:
catch: /ActionRequestValidationException.+ id is missing/ catch: /action_request_validation_exception.+ id is missing/
mget: mget:
body: body:
docs: docs:
- { _index: test_1, _type: test} - { _index: test_1, _type: test}
- do: - do:
catch: /ActionRequestValidationException.+ index is missing/ catch: /action_request_validation_exception.+ index is missing/
mget: mget:
body: body:
docs: docs:
- { _type: test, _id: 1} - { _type: test, _id: 1}
- do: - do:
catch: /ActionRequestValidationException.+ no documents to get/ catch: /action_request_validation_exception.+ no documents to get/
mget: mget:
body: body:
docs: [] docs: []
- do: - do:
catch: /ActionRequestValidationException.+ no documents to get/ catch: /action_request_validation_exception.+ no documents to get/
mget: mget:
body: {} body: {}

View File

@ -59,14 +59,14 @@
- do: - do:
catch: /ActionRequestValidationException.+ no documents to get/ catch: /action_request_validation_exception.+ no documents to get/
mget: mget:
index: test_1 index: test_1
body: body:
ids: [] ids: []
- do: - do:
catch: /ActionRequestValidationException.+ no documents to get/ catch: /action_request_validation_exception.+ no documents to get/
mget: mget:
index: test_1 index: test_1
body: {} body: {}

View File

@ -37,5 +37,5 @@
foo: bar foo: bar
- match: { responses.0.total: 1 } - 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 } - match: { responses.2.total: 1 }

View File

@ -39,7 +39,7 @@
match: {foo: bar} match: {foo: bar}
- match: { responses.0.hits.total: 3 } - 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 } - match: { responses.2.hits.total: 1 }

View File

@ -60,7 +60,7 @@
- do: - do:
catch: /ElasticsearchIllegalArgumentException.Unable.to.parse.*/ catch: /Unable.to.parse.*/
put_script: put_script:
id: "1" id: "1"
lang: "groovy" lang: "groovy"
@ -74,7 +74,7 @@
body: { "script" : "_score * doc[\"myParent.weight\"].value" } body: { "script" : "_score * doc[\"myParent.weight\"].value" }
- do: - do:
catch: /ElasticsearchIllegalArgumentException.script_lang.not.supported/ catch: /script_lang.not.supported/
put_script: put_script:
id: "1" id: "1"
lang: "foobar" lang: "foobar"

View File

@ -50,7 +50,7 @@
body: { "template": { "query": { "match{{}}_all": {}}, "size": "{{my_size}}" } } body: { "template": { "query": { "match{{}}_all": {}}, "size": "{{my_size}}" } }
- do: - do:
catch: /ElasticsearchIllegalArgumentException\SUnable\sto\sparse.*/ catch: /Unable\sto\sparse.*/
put_template: put_template:
id: "1" id: "1"
body: { "template": { "query": { "match{{}}_all": {}}, "size": "{{my_size}}" } } body: { "template": { "query": { "match{{}}_all": {}}, "size": "{{my_size}}" } }

View File

@ -37,7 +37,7 @@
- match: { hits.total: 1 } - match: { hits.total: 1 }
- do: - do:
catch: /ElasticsearchIllegalArgumentException.Unable.to.find.on.disk.script.simple1/ catch: /Unable.to.find.on.disk.script.simple1/
search_template: search_template:
body: { "template" : "simple1" } body: { "template" : "simple1" }

View File

@ -15,7 +15,7 @@ setup:
"Parent": "Parent":
- do: - do:
catch: /RoutingMissingException/ catch: /routing_missing_exception/
update: update:
index: test_1 index: test_1
type: test type: test

View File

@ -81,7 +81,7 @@
# with timestamp # with timestamp
- do: - do:
catch: /AlreadyExpiredException/ catch: /already_expired_exception/
index: index:
index: test_1 index: test_1
type: test type: test

View File

@ -22,18 +22,23 @@ package org.elasticsearch;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps; 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.collect.Tuple;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.rest.HasRestHeaders; import org.elasticsearch.rest.HasRestHeaders;
import org.elasticsearch.rest.RestStatus; import org.elasticsearch.rest.RestStatus;
import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
* A base class for all elasticsearch exceptions. * 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 <code>ElasticsearchException</code> with the specified detail message. * Construct a <code>ElasticsearchException</code> with the specified detail message.
@ -62,12 +67,8 @@ public class ElasticsearchException extends RuntimeException {
Throwable cause = unwrapCause(); Throwable cause = unwrapCause();
if (cause == this) { if (cause == this) {
return RestStatus.INTERNAL_SERVER_ERROR; return RestStatus.INTERNAL_SERVER_ERROR;
} else if (cause instanceof ElasticsearchException) {
return ((ElasticsearchException) cause).status();
} else if (cause instanceof IllegalArgumentException) {
return RestStatus.BAD_REQUEST;
} else { } else {
return RestStatus.INTERNAL_SERVER_ERROR; return ExceptionsHelper.status(cause);
} }
} }
@ -114,19 +115,6 @@ public class ElasticsearchException extends RuntimeException {
return rootCause; return rootCause;
} }
/**
* Retrieve the most specific cause of this exception, that is,
* either the innermost cause (root cause) or this exception itself.
* <p>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 <code>null</code>)
*/
public Throwable getMostSpecificCause() {
Throwable rootCause = getRootCause();
return (rootCause != null ? rootCause : this);
}
/** /**
* Check whether this exception contains an exception of the given type: * 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 * either it is of the given class itself or it contains a nested cause
@ -175,21 +163,6 @@ public class ElasticsearchException extends RuntimeException {
this.headers = headers(headers); this.headers = headers(headers);
} }
public WithRestHeaders(String msg, @Nullable ImmutableMap<String, List<String>> headers) {
super(msg);
this.headers = headers != null ? headers : ImmutableMap.<String, List<String>>of();
}
public WithRestHeaders(String msg, Throwable cause, Tuple<String, String[]>... headers) {
super(msg, cause);
this.headers = headers(headers);
}
public WithRestHeaders(String msg, Throwable cause, @Nullable ImmutableMap<String, List<String>> headers) {
super(msg, cause);
this.headers = headers != null ? headers : ImmutableMap.<String, List<String>>of();
}
@Override @Override
public ImmutableMap<String, List<String>> getHeaders() { public ImmutableMap<String, List<String>> getHeaders() {
return headers; return headers;
@ -215,4 +188,97 @@ public class ElasticsearchException extends RuntimeException {
return ImmutableMap.copyOf(map); return ImmutableMap.copyOf(map);
} }
} }
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
if (this instanceof ElasticsearchWrapperException) {
toXContent(builder, params, this);
} else {
builder.field("type", getExceptionName(this));
builder.field("reason", getMessage());
innerToXContent(builder, params);
}
return builder;
}
/**
* Renders additional per exception information into the xcontent
*/
protected void innerToXContent(XContentBuilder builder, Params params) throws IOException {
causeToXContent(builder, params);
}
/**
* Renders a cause exception as xcontent
*/
protected final void causeToXContent(XContentBuilder builder, Params params) throws IOException {
final Throwable cause = getCause();
if (cause != null && params.paramAsBoolean(REST_EXCEPTION_SKIP_CAUSE, false) == false) {
builder.field("caused_by");
builder.startObject();
toXContent(builder, params, cause);
builder.endObject();
}
}
/**
* Statis toXContent helper method that also renders non {@link org.elasticsearch.ElasticsearchException} instances as XContent.
*/
public static void toXContent(XContentBuilder builder, Params params, Throwable ex) throws IOException {
ex = ExceptionsHelper.unwrapCause(ex);
if (ex instanceof ElasticsearchException) {
((ElasticsearchException) ex).toXContent(builder, params);
} else {
builder.field("type", getExceptionName(ex));
builder.field("reason", ex.getMessage());
if (ex.getCause() != null) {
builder.field("caused_by");
builder.startObject();
toXContent(builder, params, ex.getCause());
builder.endObject();
}
}
}
/**
* Returns the root cause of this exception or mupltiple if different shards caused different exceptions
*/
public ElasticsearchException[] guessRootCauses() {
final Throwable cause = getCause();
if (cause != null && cause instanceof ElasticsearchException) {
return ((ElasticsearchException) cause).guessRootCauses();
}
return new ElasticsearchException[] {this};
}
/**
* Returns the root cause of this exception or mupltiple if different shards caused different exceptions.
* If the given exception is not an instance of {@link org.elasticsearch.ElasticsearchException} an empty array
* is returned.
*/
public static ElasticsearchException[] guessRootCauses(Throwable t) {
Throwable ex = ExceptionsHelper.unwrapCause(t);
if (ex instanceof ElasticsearchException) {
return ((ElasticsearchException) ex).guessRootCauses();
}
return new ElasticsearchException[0];
}
/**
* Returns a underscore case name for the given exception. This method strips <tt>Elasticsearch</tt> 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();
}
} }

View File

@ -54,8 +54,12 @@ public final class ExceptionsHelper {
} }
public static RestStatus status(Throwable t) { public static RestStatus status(Throwable t) {
if (t != null) {
if (t instanceof ElasticsearchException) { if (t instanceof ElasticsearchException) {
return ((ElasticsearchException) t).status(); return ((ElasticsearchException) t).status();
} else if (t instanceof IllegalArgumentException) {
return RestStatus.BAD_REQUEST;
}
} }
return RestStatus.INTERNAL_SERVER_ERROR; return RestStatus.INTERNAL_SERVER_ERROR;
} }

View File

@ -19,6 +19,9 @@
package org.elasticsearch.action; 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.Nullable;
import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.StreamOutput;
@ -164,15 +167,15 @@ public abstract class ActionWriteResponse extends ActionResponse {
private String index; private String index;
private int shardId; private int shardId;
private String nodeId; private String nodeId;
private String reason; private Throwable cause;
private RestStatus status; private RestStatus status;
private boolean primary; 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.index = index;
this.shardId = shardId; this.shardId = shardId;
this.nodeId = nodeId; this.nodeId = nodeId;
this.reason = reason; this.cause = cause;
this.status = status; this.status = status;
this.primary = primary; this.primary = primary;
} }
@ -209,7 +212,7 @@ public abstract class ActionWriteResponse extends ActionResponse {
*/ */
@Override @Override
public String reason() { public String reason() {
return reason; return ExceptionsHelper.detailedMessage(cause);
} }
/** /**
@ -233,7 +236,7 @@ public abstract class ActionWriteResponse extends ActionResponse {
index = in.readString(); index = in.readString();
shardId = in.readVInt(); shardId = in.readVInt();
nodeId = in.readOptionalString(); nodeId = in.readOptionalString();
reason = in.readString(); cause = in.readThrowable();
status = RestStatus.readFrom(in); status = RestStatus.readFrom(in);
primary = in.readBoolean(); primary = in.readBoolean();
} }
@ -243,7 +246,7 @@ public abstract class ActionWriteResponse extends ActionResponse {
out.writeString(index); out.writeString(index);
out.writeVInt(shardId); out.writeVInt(shardId);
out.writeOptionalString(nodeId); out.writeOptionalString(nodeId);
out.writeString(reason); out.writeThrowable(cause);
RestStatus.writeTo(out, status); RestStatus.writeTo(out, status);
out.writeBoolean(primary); out.writeBoolean(primary);
} }
@ -254,7 +257,10 @@ public abstract class ActionWriteResponse extends ActionResponse {
builder.field(Fields._INDEX, index); builder.field(Fields._INDEX, index);
builder.field(Fields._SHARD, shardId); builder.field(Fields._SHARD, shardId);
builder.field(Fields._NODE, nodeId); 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.STATUS, status);
builder.field(Fields.PRIMARY, primary); builder.field(Fields.PRIMARY, primary);
builder.endObject(); builder.endObject();

View File

@ -51,7 +51,7 @@ public class BulkItemResponse implements Streamable {
this.index = index; this.index = index;
this.type = type; this.type = type;
this.id = id; this.id = id;
this.message = ExceptionsHelper.detailedMessage(t); this.message = t.toString();
this.status = ExceptionsHelper.status(t); this.status = ExceptionsHelper.status(t);
} }

View File

@ -157,7 +157,7 @@ public class TransportShardBulkAction extends TransportShardReplicationOperation
} }
throw (ElasticsearchException) e; 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); logger.trace("{} failed to execute bulk item (index) {}", e, shardRequest.shardId, indexRequest);
} else { } else {
logger.debug("{} failed to execute bulk item (index) {}", e, shardRequest.shardId, indexRequest); logger.debug("{} failed to execute bulk item (index) {}", e, shardRequest.shardId, indexRequest);
@ -190,7 +190,7 @@ public class TransportShardBulkAction extends TransportShardReplicationOperation
} }
throw (ElasticsearchException) e; 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); logger.trace("{} failed to execute bulk item (delete) {}", e, shardRequest.shardId, deleteRequest);
} else { } else {
logger.debug("{} failed to execute bulk item (delete) {}", e, shardRequest.shardId, deleteRequest); logger.debug("{} failed to execute bulk item (delete) {}", e, shardRequest.shardId, deleteRequest);
@ -279,7 +279,7 @@ public class TransportShardBulkAction extends TransportShardReplicationOperation
case UPSERT: case UPSERT:
case INDEX: case INDEX:
IndexRequest indexRequest = updateResult.request(); 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); logger.trace("{} failed to execute bulk item (index) {}", t, shardRequest.shardId, indexRequest);
} else { } else {
logger.debug("{} failed to execute bulk item (index) {}", t, shardRequest.shardId, indexRequest); logger.debug("{} failed to execute bulk item (index) {}", t, shardRequest.shardId, indexRequest);
@ -289,7 +289,7 @@ public class TransportShardBulkAction extends TransportShardReplicationOperation
break; break;
case DELETE: case DELETE:
DeleteRequest deleteRequest = updateResult.request(); 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); logger.trace("{} failed to execute bulk item (delete) {}", t, shardRequest.shardId, deleteRequest);
} else { } else {
logger.debug("{} failed to execute bulk item (delete) {}", t, shardRequest.shardId, deleteRequest); logger.debug("{} failed to execute bulk item (delete) {}", t, shardRequest.shardId, deleteRequest);

View File

@ -20,25 +20,30 @@
package org.elasticsearch.action.search; package org.elasticsearch.action.search;
import org.elasticsearch.ElasticsearchException; 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 org.elasticsearch.rest.RestStatus;
import java.io.IOException;
import java.util.*;
/** /**
* *
*/ */
public class SearchPhaseExecutionException extends ElasticsearchException { public class SearchPhaseExecutionException extends ElasticsearchException {
private final String phaseName; private final String phaseName;
private ShardSearchFailure[] shardFailures; private ShardSearchFailure[] shardFailures;
public SearchPhaseExecutionException(String phaseName, String msg, ShardSearchFailure[] shardFailures) { public SearchPhaseExecutionException(String phaseName, String msg, ShardSearchFailure[] shardFailures) {
super(buildMessage(phaseName, msg, shardFailures)); super(msg);
this.phaseName = phaseName; this.phaseName = phaseName;
this.shardFailures = shardFailures; this.shardFailures = shardFailures;
} }
public SearchPhaseExecutionException(String phaseName, String msg, Throwable cause, ShardSearchFailure[] shardFailures) { public SearchPhaseExecutionException(String phaseName, String msg, Throwable cause, ShardSearchFailure[] shardFailures) {
super(buildMessage(phaseName, msg, shardFailures), cause); super(msg, cause);
this.phaseName = phaseName; this.phaseName = phaseName;
this.shardFailures = shardFailures; this.shardFailures = shardFailures;
} }
@ -60,10 +65,6 @@ public class SearchPhaseExecutionException extends ElasticsearchException {
return status; return status;
} }
public String phaseName() {
return phaseName;
}
public ShardSearchFailure[] shardFailures() { public ShardSearchFailure[] shardFailures() {
return shardFailures; return shardFailures;
} }
@ -83,4 +84,90 @@ public class SearchPhaseExecutionException extends ElasticsearchException {
} }
return sb.toString(); 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<ShardSearchFailure> uniqueFailures = new ArrayList<>();
Set<GroupBy> 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<ElasticsearchException> 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<? extends Throwable> 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;
}
}
} }

View File

@ -25,24 +25,29 @@ import org.elasticsearch.action.ShardOperationFailedException;
import org.elasticsearch.common.Nullable; import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput; 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.rest.RestStatus;
import org.elasticsearch.search.SearchException; import org.elasticsearch.search.SearchException;
import org.elasticsearch.search.SearchShardTarget; import org.elasticsearch.search.SearchShardTarget;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import static org.elasticsearch.search.SearchShardTarget.readSearchShardTarget; import static org.elasticsearch.search.SearchShardTarget.readSearchShardTarget;
/** /**
* Represents a failure to search on a specific shard. * 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]; public static final ShardSearchFailure[] EMPTY_ARRAY = new ShardSearchFailure[0];
private SearchShardTarget shardTarget; private SearchShardTarget shardTarget;
private String reason; private String reason;
private RestStatus status; private RestStatus status;
private Throwable cause;
private ShardSearchFailure() { private ShardSearchFailure() {
@ -59,12 +64,9 @@ public class ShardSearchFailure implements ShardOperationFailedException {
} else if (shardTarget != null) { } else if (shardTarget != null) {
this.shardTarget = shardTarget; this.shardTarget = shardTarget;
} }
if (actual != null && actual instanceof ElasticsearchException) { status = ExceptionsHelper.status(actual);
status = ((ElasticsearchException) actual).status();
} else {
status = RestStatus.INTERNAL_SERVER_ERROR;
}
this.reason = ExceptionsHelper.detailedMessage(t); this.reason = ExceptionsHelper.detailedMessage(t);
this.cause = actual;
} }
public ShardSearchFailure(String reason, SearchShardTarget shardTarget) { public ShardSearchFailure(String reason, SearchShardTarget shardTarget) {
@ -138,6 +140,7 @@ public class ShardSearchFailure implements ShardOperationFailedException {
} }
reason = in.readString(); reason = in.readString();
status = RestStatus.readFrom(in); status = RestStatus.readFrom(in);
cause = in.readThrowable();
} }
@Override @Override
@ -150,5 +153,26 @@ public class ShardSearchFailure implements ShardOperationFailedException {
} }
out.writeString(reason); out.writeString(reason);
RestStatus.writeTo(out, status); 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;
} }
} }

View File

@ -20,6 +20,7 @@
package org.elasticsearch.action.support; package org.elasticsearch.action.support;
import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.ExceptionsHelper;
import org.elasticsearch.action.ShardOperationFailedException; import org.elasticsearch.action.ShardOperationFailedException;
import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.StreamOutput;
@ -39,30 +40,25 @@ public class DefaultShardOperationFailedException implements ShardOperationFaile
private int shardId; private int shardId;
private String reason; private Throwable reason;
private RestStatus status; private RestStatus status;
private DefaultShardOperationFailedException() { private DefaultShardOperationFailedException() {
} }
public DefaultShardOperationFailedException(IndexShardException e) { public DefaultShardOperationFailedException(IndexShardException e) {
this.index = e.shardId().index().name(); this.index = e.shardId().index().name();
this.shardId = e.shardId().id(); this.shardId = e.shardId().id();
this.reason = detailedMessage(e); this.reason = e;
this.status = e.status(); this.status = e.status();
} }
public DefaultShardOperationFailedException(String index, int shardId, Throwable t) { public DefaultShardOperationFailedException(String index, int shardId, Throwable t) {
this.index = index; this.index = index;
this.shardId = shardId; this.shardId = shardId;
this.reason = detailedMessage(t); this.reason = t;
if (t != null && t instanceof ElasticsearchException) { status = ExceptionsHelper.status(t);
status = ((ElasticsearchException) t).status();
} else {
status = RestStatus.INTERNAL_SERVER_ERROR;
}
} }
@Override @Override
@ -77,7 +73,7 @@ public class DefaultShardOperationFailedException implements ShardOperationFaile
@Override @Override
public String reason() { public String reason() {
return this.reason; return detailedMessage(reason);
} }
@Override @Override
@ -97,7 +93,7 @@ public class DefaultShardOperationFailedException implements ShardOperationFaile
index = in.readString(); index = in.readString();
} }
shardId = in.readVInt(); shardId = in.readVInt();
reason = in.readString(); reason = in.readThrowable();
status = RestStatus.readFrom(in); status = RestStatus.readFrom(in);
} }
@ -110,12 +106,12 @@ public class DefaultShardOperationFailedException implements ShardOperationFaile
out.writeString(index); out.writeString(index);
} }
out.writeVInt(shardId); out.writeVInt(shardId);
out.writeString(reason); out.writeThrowable(reason);
RestStatus.writeTo(out, status); RestStatus.writeTo(out, status);
} }
@Override @Override
public String toString() { public String toString() {
return "[" + index + "][" + shardId + "] failed, reason [" + reason + "]"; return "[" + index + "][" + shardId + "] failed, reason [" + reason() + "]";
} }
} }

View File

@ -103,14 +103,8 @@ public abstract class TransportIndexReplicationOperationAction<Request extends I
failureCounter.getAndIncrement(); failureCounter.getAndIncrement();
int index = indexCounter.getAndIncrement(); int index = indexCounter.getAndIncrement();
// this is a failure for an entire shard group, constructs shard info accordingly // this is a failure for an entire shard group, constructs shard info accordingly
final RestStatus status; final RestStatus status = ExceptionsHelper.status(e);
if (e != null && e instanceof ElasticsearchException) { Failure failure = new Failure(request.index(), shardIt.shardId().id(), null, e, status, true);
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);
shardsResponses.set(index, new ShardActionResult(new ActionWriteResponse.ShardInfo(shardIt.size(), 0, failure))); shardsResponses.set(index, new ShardActionResult(new ActionWriteResponse.ShardInfo(shardIt.size(), 0, failure)));
returnIfNeeded(); returnIfNeeded();
} }

View File

@ -495,7 +495,7 @@ public abstract class TransportShardReplicationOperationAction<Request extends S
retry(e); retry(e);
return; return;
} }
if (e instanceof ElasticsearchException && ((ElasticsearchException) e).status() == RestStatus.CONFLICT) { if (ExceptionsHelper.status(e) == RestStatus.CONFLICT) {
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
logger.trace(shard.shortSummary() + ": Failed to execute [" + internalRequest.request() + "]", e); logger.trace(shard.shortSummary() + ": Failed to execute [" + internalRequest.request() + "]", e);
} }
@ -822,10 +822,9 @@ public abstract class TransportShardReplicationOperationAction<Request extends S
int slot = 0; int slot = 0;
failuresArray = new ActionWriteResponse.ShardInfo.Failure[shardReplicaFailures.size()]; failuresArray = new ActionWriteResponse.ShardInfo.Failure[shardReplicaFailures.size()];
for (Map.Entry<String, Throwable> entry : shardReplicaFailures.entrySet()) { for (Map.Entry<String, Throwable> entry : shardReplicaFailures.entrySet()) {
String reason = ExceptionsHelper.detailedMessage(entry.getValue());
RestStatus restStatus = ExceptionsHelper.status(entry.getValue()); RestStatus restStatus = ExceptionsHelper.status(entry.getValue());
failuresArray[slot++] = new ActionWriteResponse.ShardInfo.Failure( 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 { } else {

View File

@ -60,11 +60,6 @@ public class BytesStreamOutput extends StreamOutput implements BytesStream {
this.bytes = bigarrays.newByteArray(expectedSize); this.bytes = bigarrays.newByteArray(expectedSize);
} }
@Override
public boolean seekPositionSupported() {
return true;
}
@Override @Override
public long position() throws IOException { public long position() throws IOException {
return count; return count;

View File

@ -21,6 +21,7 @@ package org.elasticsearch.common.io.stream;
import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.CharsRefBuilder; import org.apache.lucene.util.CharsRefBuilder;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.Version; import org.elasticsearch.Version;
import org.elasticsearch.common.Nullable; import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.Strings; import org.elasticsearch.common.Strings;
@ -32,6 +33,7 @@ import org.joda.time.DateTime;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.ObjectInputStream;
import java.util.*; import java.util.*;
/** /**
@ -463,4 +465,13 @@ public abstract class StreamInput extends InputStream {
return null; return null;
} }
} }
public <T extends Throwable> 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);
}
}
} }

View File

@ -28,6 +28,7 @@ import org.elasticsearch.common.text.Text;
import org.joda.time.ReadableInstant; import org.joda.time.ReadableInstant;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.Date; import java.util.Date;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
@ -50,10 +51,6 @@ public abstract class StreamOutput extends OutputStream {
return this; return this;
} }
public boolean seekPositionSupported() {
return false;
}
public long position() throws IOException { public long position() throws IOException {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@ -432,4 +429,10 @@ public abstract class StreamOutput extends OutputStream {
writeBoolean(false); writeBoolean(false);
} }
} }
public void writeThrowable(Throwable throwable) throws IOException {
ObjectOutputStream out = new ObjectOutputStream(this);
out.writeObject(throwable);
out.flush();
}
} }

View File

@ -20,6 +20,9 @@
package org.elasticsearch.index; package org.elasticsearch.index;
import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.xcontent.XContentBuilder;
import java.io.IOException;
/** /**
* *
@ -32,16 +35,25 @@ public class IndexException extends ElasticsearchException {
this(index, msg, null); this(index, msg, null);
} }
public IndexException(Index index, String msg, Throwable cause) { protected IndexException(Index index, String msg, Throwable cause) {
this(index, true, msg, cause); super(msg, cause);
}
protected IndexException(Index index, boolean withSpace, String msg, Throwable cause) {
super("[" + (index == null ? "_na" : index.name()) + "]" + (withSpace ? " " : "") + msg, cause);
this.index = index; this.index = index;
} }
public Index index() { public Index index() {
return 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();
}
} }

View File

@ -26,10 +26,6 @@ import org.elasticsearch.index.IndexException;
*/ */
public class PercolatorException extends IndexException { public class PercolatorException extends IndexException {
public PercolatorException(Index index, String msg) {
super(index, msg);
}
public PercolatorException(Index index, String msg, Throwable cause) { public PercolatorException(Index index, String msg, Throwable cause) {
super(index, msg, cause); super(index, msg, cause);
} }

View File

@ -40,4 +40,5 @@ public class QueryParsingException extends IndexException {
public RestStatus status() { public RestStatus status() {
return RestStatus.BAD_REQUEST; return RestStatus.BAD_REQUEST;
} }
} }

View File

@ -19,8 +19,11 @@
package org.elasticsearch.index.shard; package org.elasticsearch.index.shard;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.IndexException; import org.elasticsearch.index.IndexException;
import java.io.IOException;
/** /**
* *
*/ */
@ -33,11 +36,24 @@ public class IndexShardException extends IndexException {
} }
public IndexShardException(ShardId shardId, String msg, Throwable cause) { 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; this.shardId = shardId;
} }
public ShardId shardId() { public ShardId shardId() {
return 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);
}
} }

View File

@ -27,10 +27,6 @@ import org.elasticsearch.index.IndexException;
*/ */
public class AliasFilterParsingException extends IndexException { 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) { public AliasFilterParsingException(Index index, String name, String desc, Throwable ex) {
super(index, "[" + name + "], " + desc, ex); super(index, "[" + name + "], " + desc, ex);
} }

View File

@ -29,7 +29,7 @@ import org.elasticsearch.rest.RestStatus;
public class IndexMissingException extends IndexException { public class IndexMissingException extends IndexException {
public IndexMissingException(Index index) { public IndexMissingException(Index index) {
super(index, "missing"); super(index, "no such index");
} }
@Override @Override

View File

@ -34,11 +34,6 @@ public class TypeMissingException extends IndexException {
super(index, "type[" + Arrays.toString(types) + "] missing"); super(index, "type[" + Arrays.toString(types) + "] missing");
} }
public TypeMissingException(Index index, String[] types, String message) {
super(index, "type[" + Arrays.toString(types) + "] missing: " + message);
}
@Override @Override
public RestStatus status() { public RestStatus status() {
return RestStatus.NOT_FOUND; return RestStatus.NOT_FOUND;

View File

@ -20,13 +20,16 @@
package org.elasticsearch.rest; package org.elasticsearch.rest;
import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.ExceptionsHelper;
import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference; 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 org.elasticsearch.common.xcontent.XContentBuilder;
import java.io.IOException; import java.io.IOException;
import java.util.Collections;
import static org.elasticsearch.ExceptionsHelper.detailedMessage;
public class BytesRestResponse extends RestResponse { public class BytesRestResponse extends RestResponse {
@ -78,7 +81,7 @@ public class BytesRestResponse extends RestResponse {
} }
public BytesRestResponse(RestChannel channel, Throwable t) throws IOException { 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 { public BytesRestResponse(RestChannel channel, RestStatus status, Throwable t) throws IOException {
@ -114,9 +117,22 @@ public class BytesRestResponse extends RestResponse {
private static XContentBuilder convert(RestChannel channel, RestStatus status, Throwable t) throws IOException { private static XContentBuilder convert(RestChannel channel, RestStatus status, Throwable t) throws IOException {
XContentBuilder builder = channel.newBuilder().startObject(); XContentBuilder builder = channel.newBuilder().startObject();
if (t == null) { if (t == null) {
builder.field("error", "Unknown"); builder.field("error", "unknown");
} else if (channel.detailedErrorsEnabled()) { } 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)) { if (channel.request().paramAsBoolean("error_trace", false)) {
buildErrorTrace(t, builder); buildErrorTrace(t, builder);
} }
@ -128,6 +144,7 @@ public class BytesRestResponse extends RestResponse {
return builder; return builder;
} }
private static void buildErrorTrace(Throwable t, XContentBuilder builder) throws IOException { private static void buildErrorTrace(Throwable t, XContentBuilder builder) throws IOException {
builder.startObject("error_trace"); builder.startObject("error_trace");
boolean first = true; boolean first = true;

View File

@ -35,19 +35,6 @@ public class SearchContextException extends SearchException {
} }
private static String buildMessage(SearchContext context, String msg) { private static String buildMessage(SearchContext context, String msg) {
StringBuilder sb = new StringBuilder(); return msg;
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();
} }
} }

View File

@ -28,11 +28,11 @@ import org.elasticsearch.search.internal.SearchContext;
public class SearchParseException extends SearchContextException { public class SearchParseException extends SearchContextException {
public SearchParseException(SearchContext context, String msg) { public SearchParseException(SearchContext context, String msg) {
super(context, "Parse Failure [" + msg + "]"); super(context, msg);
} }
public SearchParseException(SearchContext context, String msg, Throwable cause) { public SearchParseException(SearchContext context, String msg, Throwable cause) {
super(context, "Parse Failure [" + msg + "]", cause); super(context, msg, cause);
} }
@Override @Override

View File

@ -19,13 +19,27 @@
package org.elasticsearch; 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.Index;
import org.elasticsearch.index.query.QueryParsingException;
import org.elasticsearch.indices.IndexMissingException; import org.elasticsearch.indices.IndexMissingException;
import org.elasticsearch.rest.RestStatus; import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchShardTarget;
import org.elasticsearch.test.ElasticsearchTestCase; import org.elasticsearch.test.ElasticsearchTestCase;
import org.elasticsearch.transport.RemoteTransportException; import org.elasticsearch.transport.RemoteTransportException;
import org.junit.Test; import org.junit.Test;
import java.io.EOFException;
import java.io.FileNotFoundException;
import java.io.IOException;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
public class ElasticsearchExceptionTests extends ElasticsearchTestCase { public class ElasticsearchExceptionTests extends ElasticsearchTestCase {
@ -43,5 +57,203 @@ public class ElasticsearchExceptionTests extends ElasticsearchTestCase {
exception = new RemoteTransportException("test", new IndexMissingException(new Index("test"))); exception = new RemoteTransportException("test", new IndexMissingException(new Index("test")));
assertThat(exception.status(), equalTo(RestStatus.NOT_FOUND)); 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());
}
}

View File

@ -48,7 +48,7 @@ public class BulkProcessorClusterSettingsTests extends ElasticsearchIntegrationT
assertEquals(3, responses.length); assertEquals(3, responses.length);
assertFalse("Operation on existing index should succeed", responses[0].isFailed()); assertFalse("Operation on existing index should succeed", responses[0].isFailed());
assertTrue("Missing index should have been flagged", responses[1].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()); assertFalse("Operation on existing index should succeed", responses[2].isFailed());
} }
} }

View File

@ -441,7 +441,8 @@ public class MetaDataTests extends ElasticsearchTestCase {
md.concreteIndices(IndicesOptions.strictSingleIndexNoExpandForbidClosed(), "foofoo-closed", "foofoobar"); md.concreteIndices(IndicesOptions.strictSingleIndexNoExpandForbidClosed(), "foofoo-closed", "foofoobar");
fail(); fail();
} catch(IndexClosedException e) { } 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"); String[] results = md.concreteIndices(IndicesOptions.strictSingleIndexNoExpandForbidClosed(), "foo", "barbaz");

View File

@ -120,7 +120,7 @@ public class DeleteByQueryTests extends ElasticsearchIntegrationTest {
assertThat(response.getIndices().size(), equalTo(1)); assertThat(response.getIndices().size(), equalTo(1));
assertThat(response.getIndices().get("test").getShardInfo().getFailures().length, equalTo(twitter.numPrimaries)); assertThat(response.getIndices().get("test").getShardInfo().getFailures().length, equalTo(twitter.numPrimaries));
for (ActionWriteResponse.ShardInfo.Failure failure : response.getIndices().get("test").getShardInfo().getFailures()) { 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.status(), equalTo(RestStatus.BAD_REQUEST));
assertThat(failure.shardId(), greaterThan(-1)); assertThat(failure.shardId(), greaterThan(-1));
} }

View File

@ -133,7 +133,7 @@ public class BulkTests extends ElasticsearchIntegrationTest {
assertThat(bulkResponse.getItems()[1].getResponse(), nullValue()); assertThat(bulkResponse.getItems()[1].getResponse(), nullValue());
assertThat(bulkResponse.getItems()[1].getFailure().getIndex(), equalTo("test")); assertThat(bulkResponse.getItems()[1].getFailure().getIndex(), equalTo("test"));
assertThat(bulkResponse.getItems()[1].getFailure().getId(), equalTo("7")); 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()).getId(), equalTo("2"));
assertThat(((UpdateResponse) bulkResponse.getItems()[2].getResponse()).getIndex(), equalTo("test")); assertThat(((UpdateResponse) bulkResponse.getItems()[2].getResponse()).getIndex(), equalTo("test"));
assertThat(((UpdateResponse) bulkResponse.getItems()[2].getResponse()).getVersion(), equalTo(3l)); assertThat(((UpdateResponse) bulkResponse.getItems()[2].getResponse()).getVersion(), equalTo(3l));
@ -173,7 +173,7 @@ public class BulkTests extends ElasticsearchIntegrationTest {
.add(client().prepareUpdate("test", "type", "2").setDoc("field", "2")) .add(client().prepareUpdate("test", "type", "2").setDoc("field", "2"))
.add(client().prepareUpdate("test", "type", "1").setVersion(2l).setDoc("field", "3")).get(); .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()[1].getResponse()).getVersion(), equalTo(2l));
assertThat(((UpdateResponse) bulkResponse.getItems()[2].getResponse()).getVersion(), equalTo(3l)); assertThat(((UpdateResponse) bulkResponse.getItems()[2].getResponse()).getVersion(), equalTo(3l));
@ -194,7 +194,7 @@ public class BulkTests extends ElasticsearchIntegrationTest {
.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.FORCE))
.add(client().prepareUpdate("test", "type", "e1").setDoc("field", "3").setVersion(20).setVersionType(VersionType.INTERNAL)).get(); .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()[1].getResponse()).getVersion(), equalTo(20l));
assertThat(((UpdateResponse) bulkResponse.getItems()[2].getResponse()).getVersion(), equalTo(21l)); assertThat(((UpdateResponse) bulkResponse.getItems()[2].getResponse()).getVersion(), equalTo(21l));
} }
@ -325,7 +325,7 @@ public class BulkTests extends ElasticsearchIntegrationTest {
int id = i + (numDocs / 2); int id = i + (numDocs / 2);
if (i >= (numDocs / 2)) { if (i >= (numDocs / 2)) {
assertThat(response.getItems()[i].getFailure().getId(), equalTo(Integer.toString(id))); 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 { } else {
assertThat(response.getItems()[i].getId(), equalTo(Integer.toString(id))); assertThat(response.getItems()[i].getId(), equalTo(Integer.toString(id)));
assertThat(response.getItems()[i].getVersion(), equalTo(3l)); assertThat(response.getItems()[i].getVersion(), equalTo(3l));

View File

@ -1191,7 +1191,7 @@ public class SimpleIndexQueryParserTests extends ElasticsearchSingleNodeTest {
queryParser.parse(query).query(); queryParser.parse(query).query();
fail(); fail();
} catch (QueryParsingException ex) { } 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 class SimpleIndexQueryParserTests extends ElasticsearchSingleNodeTest {
queryParser.parse(query).query(); queryParser.parse(query).query();
fail(); fail();
} catch (QueryParsingException ex) { } 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"));
} }
} }

View File

@ -241,8 +241,8 @@ public class CircuitBreakerServiceTests extends ElasticsearchIntegrationTest {
fail("should have thrown an exception"); fail("should have thrown an exception");
} catch (Exception e) { } catch (Exception e) {
String errMsg = "[fielddata] Data too large, data for [test] would be larger than limit of [10/10b]"; 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", assertThat("Exception: " + e.toString() + " should contain a CircuitBreakingException",
ExceptionsHelper.unwrapCause(e).getMessage().contains(errMsg), equalTo(true)); e.toString().contains(errMsg), equalTo(true));
} }
assertFailures(client.prepareSearch("cb-test").setQuery(matchAllQuery()).addSort("test", SortOrder.DESC), assertFailures(client.prepareSearch("cb-test").setQuery(matchAllQuery()).addSort("test", SortOrder.DESC),
@ -263,8 +263,8 @@ public class CircuitBreakerServiceTests extends ElasticsearchIntegrationTest {
fail("should have thrown an exception"); fail("should have thrown an exception");
} catch (Exception e) { } catch (Exception e) {
String errMsg = "[parent] Data too large, data for [test] would be larger than limit of [15/15b]"; 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", assertThat("Exception: " +e.toString() + " should contain a CircuitBreakingException",
ExceptionsHelper.unwrapCause(e).getMessage().contains(errMsg), equalTo(true)); e.toString().contains(errMsg), equalTo(true));
} }
} }
@ -297,8 +297,8 @@ public class CircuitBreakerServiceTests extends ElasticsearchIntegrationTest {
fail("aggregation should have tripped the breaker"); fail("aggregation should have tripped the breaker");
} catch (Exception e) { } catch (Exception e) {
String errMsg = "CircuitBreakingException[[request] Data too large, data for [<reused_arrays>] would be larger than limit of [10/10b]]"; String errMsg = "CircuitBreakingException[[request] Data too large, data for [<reused_arrays>] would be larger than limit of [10/10b]]";
assertThat("Exception: " + ExceptionsHelper.unwrapCause(e) + " should contain a CircuitBreakingException", assertThat("Exception: " + e.toString() + " should contain a CircuitBreakingException",
ExceptionsHelper.unwrapCause(e).getMessage().contains(errMsg), equalTo(true)); e.toString().contains(errMsg), equalTo(true));
} }
} }

View File

@ -495,7 +495,7 @@ public class SimpleIndexTemplateTests extends ElasticsearchIntegrationTest {
} catch(ElasticsearchIllegalArgumentException e) { } catch(ElasticsearchIllegalArgumentException e) {
assertThat(e.getMessage(), equalTo("failed to parse filter for alias [invalid_alias]")); assertThat(e.getMessage(), equalTo("failed to parse filter for alias [invalid_alias]"));
assertThat(e.getCause(), instanceOf(QueryParsingException.class)); 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 class SimpleIndexTemplateTests extends ElasticsearchIntegrationTest {
createIndex("test"); createIndex("test");
fail("index creation should have failed due to alias with existing index name in mathching index template"); fail("index creation should have failed due to alias with existing index name in mathching index template");
} catch(InvalidAliasNameException e) { } 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"));
} }
} }

View File

@ -707,7 +707,7 @@ public class SimpleNestedTests extends ElasticsearchIntegrationTest {
.execute().actionGet(); .execute().actionGet();
Assert.fail("SearchPhaseExecutionException should have been thrown"); Assert.fail("SearchPhaseExecutionException should have been thrown");
} catch (SearchPhaseExecutionException e) { } 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]"));
} }
} }

View File

@ -20,11 +20,18 @@
package org.elasticsearch.rest; package org.elasticsearch.rest;
import org.elasticsearch.ElasticsearchException; 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.ElasticsearchTestCase;
import org.elasticsearch.test.rest.FakeRestRequest; import org.elasticsearch.test.rest.FakeRestRequest;
import org.elasticsearch.transport.RemoteTransportException;
import org.junit.Test; import org.junit.Test;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException;
import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
@ -70,8 +77,8 @@ public class BytesRestResponseTests extends ElasticsearchTestCase {
Throwable t = new ElasticsearchException("an error occurred reading data", new FileNotFoundException("/foo/bar")); Throwable t = new ElasticsearchException("an error occurred reading data", new FileNotFoundException("/foo/bar"));
BytesRestResponse response = new BytesRestResponse(channel, t); BytesRestResponse response = new BytesRestResponse(channel, t);
String text = response.content().toUtf8(); String text = response.content().toUtf8();
assertThat(text, containsString("ElasticsearchException[an error occurred reading data]")); assertThat(text, containsString("{\"type\":\"exception\",\"reason\":\"an error occurred reading data\"}"));
assertThat(text, containsString("FileNotFoundException[/foo/bar]")); assertThat(text, containsString("{\"type\":\"file_not_found_exception\",\"reason\":\"/foo/bar\"}"));
} }
@Test @Test
@ -97,11 +104,21 @@ public class BytesRestResponseTests extends ElasticsearchTestCase {
Throwable t = new Throwable("an error occurred reading data", new FileNotFoundException("/foo/bar")); Throwable t = new Throwable("an error occurred reading data", new FileNotFoundException("/foo/bar"));
BytesRestResponse response = new BytesRestResponse(channel, t); BytesRestResponse response = new BytesRestResponse(channel, t);
String text = response.content().toUtf8(); String text = response.content().toUtf8();
assertThat(text, containsString("\"error\":\"Throwable[an error occurred reading data]")); assertThat(text, containsString("\"type\":\"throwable\",\"reason\":\"an error occurred reading data\""));
assertThat(text, containsString("FileNotFoundException[/foo/bar]")); assertThat(text, containsString("{\"type\":\"file_not_found_exception\",\"reason\":\"/foo/bar\"}"));
assertThat(text, containsString("\"error_trace\":{\"message\":\"an error occurred reading data\"")); 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 @Test
public void testNullThrowable() throws Exception { public void testNullThrowable() throws Exception {
RestRequest request = new FakeRestRequest(); RestRequest request = new FakeRestRequest();
@ -109,10 +126,47 @@ public class BytesRestResponseTests extends ElasticsearchTestCase {
BytesRestResponse response = new BytesRestResponse(channel, null); BytesRestResponse response = new BytesRestResponse(channel, null);
String text = response.content().toUtf8(); String text = response.content().toUtf8();
assertThat(text, containsString("\"error\":\"Unknown\"")); assertThat(text, containsString("\"error\":\"unknown\""));
assertThat(text, not(containsString("error_trace"))); 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 { private static class ExceptionWithHeaders extends ElasticsearchException.WithRestHeaders {
ExceptionWithHeaders() { ExceptionWithHeaders() {

View File

@ -153,8 +153,7 @@ public class GroovySandboxScriptTests extends ElasticsearchIntegrationTest {
"; doc['foo'].value + 2\", \"type\": \"number\", \"lang\": \"groovy\"}}}").get(); "; doc['foo'].value + 2\", \"type\": \"number\", \"lang\": \"groovy\"}}}").get();
fail("script: " + script + " failed to be caught be the sandbox!"); fail("script: " + script + " failed to be caught be the sandbox!");
} catch (SearchPhaseExecutionException e) { } catch (SearchPhaseExecutionException e) {
String msg = ExceptionsHelper.detailedMessage(ExceptionsHelper.unwrapCause(e)); assertThat("script failed, but with incorrect message: " + e.toString(), e.toString().contains(failMessage), equalTo(true));
assertThat("script failed, but with incorrect message: " + msg, msg.contains(failMessage), equalTo(true));
} }
} }
} }

View File

@ -76,12 +76,12 @@ public class GroovyScriptTests extends ElasticsearchIntegrationTest {
client().prepareSearch("test").setQuery(constantScoreQuery(scriptFilter("1 == not_found").lang(GroovyScriptEngineService.NAME))).get(); client().prepareSearch("test").setQuery(constantScoreQuery(scriptFilter("1 == not_found").lang(GroovyScriptEngineService.NAME))).get();
fail("should have thrown an exception"); fail("should have thrown an exception");
} catch (SearchPhaseExecutionException e) { } catch (SearchPhaseExecutionException e) {
assertThat(ExceptionsHelper.detailedMessage(e) + "should not contained NotSerializableTransportException", assertThat(e.toString()+ "should not contained NotSerializableTransportException",
ExceptionsHelper.detailedMessage(e).contains("NotSerializableTransportException"), equalTo(false)); e.toString().contains("NotSerializableTransportException"), equalTo(false));
assertThat(ExceptionsHelper.detailedMessage(e) + "should have contained GroovyScriptExecutionException", assertThat(e.toString()+ "should have contained GroovyScriptExecutionException",
ExceptionsHelper.detailedMessage(e).contains("GroovyScriptExecutionException"), equalTo(true)); e.toString().contains("GroovyScriptExecutionException"), equalTo(true));
assertThat(ExceptionsHelper.detailedMessage(e) + "should have contained not_found", assertThat(e.toString()+ "should have contained not_found",
ExceptionsHelper.detailedMessage(e).contains("No such property: not_found"), equalTo(true)); e.toString().contains("No such property: not_found"), equalTo(true));
} }
try { try {
@ -89,12 +89,12 @@ public class GroovyScriptTests extends ElasticsearchIntegrationTest {
scriptFilter("assert false").lang("groovy"))).get(); scriptFilter("assert false").lang("groovy"))).get();
fail("should have thrown an exception"); fail("should have thrown an exception");
} catch (SearchPhaseExecutionException e) { } catch (SearchPhaseExecutionException e) {
assertThat(ExceptionsHelper.detailedMessage(e) + "should not contained NotSerializableTransportException", assertThat(e.toString()+ "should not contained NotSerializableTransportException",
ExceptionsHelper.detailedMessage(e).contains("NotSerializableTransportException"), equalTo(false)); e.toString().contains("NotSerializableTransportException"), equalTo(false));
assertThat(ExceptionsHelper.detailedMessage(e) + "should have contained GroovyScriptExecutionException", assertThat(e.toString()+ "should have contained GroovyScriptExecutionException",
ExceptionsHelper.detailedMessage(e).contains("GroovyScriptExecutionException"), equalTo(true)); e.toString().contains("GroovyScriptExecutionException"), equalTo(true));
assertThat(ExceptionsHelper.detailedMessage(e) + "should have contained an assert error", assertThat(e.toString()+ "should have contained an assert error",
ExceptionsHelper.detailedMessage(e).contains("PowerAssertionError[assert false"), equalTo(true)); e.toString().contains("PowerAssertionError[assert false"), equalTo(true));
} }
} }

View File

@ -178,8 +178,8 @@ public class IndexLookupTests extends ElasticsearchIntegrationTest {
client().prepareSearch("test").setQuery(QueryBuilders.matchAllQuery()).addScriptField("tvtest", script).execute().actionGet(); client().prepareSearch("test").setQuery(QueryBuilders.matchAllQuery()).addScriptField("tvtest", script).execute().actionGet();
} catch (SearchPhaseExecutionException e) { } catch (SearchPhaseExecutionException e) {
assertThat( assertThat(
"got: " + e.getDetailedMessage(), "got: " + e.toString(),
e.getDetailedMessage() e.toString()
.indexOf( .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]"), "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)); Matchers.greaterThan(-1));

View File

@ -158,20 +158,20 @@ public class IndexedScriptTests extends ElasticsearchIntegrationTest {
fail("update script should have been rejected"); fail("update script should have been rejected");
} catch(Exception e) { } catch(Exception e) {
assertThat(e.getMessage(), containsString("failed to execute script")); 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 { try {
String query = "{ \"script_fields\" : { \"test1\" : { \"script_id\" : \"script1\", \"lang\":\"expression\" }}}"; String query = "{ \"script_fields\" : { \"test1\" : { \"script_id\" : \"script1\", \"lang\":\"expression\" }}}";
client().prepareSearch().setSource(query).setIndices("test").setTypes("scriptTest").get(); client().prepareSearch().setSource(query).setIndices("test").setTypes("scriptTest").get();
fail("search script should have been rejected"); fail("search script should have been rejected");
} catch(Exception e) { } 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 { try {
String source = "{\"aggs\": {\"test\": { \"terms\" : { \"script_id\":\"script1\", \"script_lang\":\"expression\" } } } }"; String source = "{\"aggs\": {\"test\": { \"terms\" : { \"script_id\":\"script1\", \"script_lang\":\"expression\" } } } }";
client().prepareSearch("test").setSource(source).get(); client().prepareSearch("test").setSource(source).get();
} catch(Exception e) { } 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"));
} }
} }
} }

View File

@ -107,7 +107,7 @@ public class OnDiskScriptTests extends ElasticsearchIntegrationTest {
client().prepareSearch("test").setSource(source).get(); client().prepareSearch("test").setSource(source).get();
fail("aggs script should have been rejected"); fail("aggs script should have been rejected");
} catch(Exception e) { } 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}"; String query = "{ \"query\" : { \"match_all\": {}} , \"script_fields\" : { \"test1\" : { \"script_file\" : \"script1\", \"lang\":\"expression\" }}, size:1}";
@ -128,21 +128,21 @@ public class OnDiskScriptTests extends ElasticsearchIntegrationTest {
client().prepareSearch("test").setSource(source).get(); client().prepareSearch("test").setSource(source).get();
fail("aggs script should have been rejected"); fail("aggs script should have been rejected");
} catch(Exception e) { } 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}"; String query = "{ \"query\" : { \"match_all\": {}} , \"script_fields\" : { \"test1\" : { \"script_file\" : \"script1\", \"lang\":\"mustache\" }}, size:1}";
try { try {
client().prepareSearch().setSource(query).setIndices("test").setTypes("scriptTest").get(); client().prepareSearch().setSource(query).setIndices("test").setTypes("scriptTest").get();
fail("search script should have been rejected"); fail("search script should have been rejected");
} catch(Exception e) { } 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 { try {
client().prepareUpdate("test", "scriptTest", "1").setScript("script1", ScriptService.ScriptType.FILE).setScriptLang(MustacheScriptEngineService.NAME).get(); client().prepareUpdate("test", "scriptTest", "1").setScript("script1", ScriptService.ScriptType.FILE).setScriptLang(MustacheScriptEngineService.NAME).get();
fail("update script should have been rejected"); fail("update script should have been rejected");
} catch(Exception e) { } catch(Exception e) {
assertThat(e.getMessage(), containsString("failed to execute script")); 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"));
} }
} }
} }

View File

@ -51,7 +51,7 @@ public class SandboxDisabledTests extends ElasticsearchIntegrationTest {
"\"sort\":{\"_script\": {\"script\": \"doc['foo'].value + 2\", \"type\": \"number\", \"lang\": \"groovy\"}}}").get(); "\"sort\":{\"_script\": {\"script\": \"doc['foo'].value + 2\", \"type\": \"number\", \"lang\": \"groovy\"}}}").get();
fail("shards should fail because the sandbox and dynamic scripting are disabled"); fail("shards should fail because the sandbox and dynamic scripting are disabled");
} catch (Exception e) { } 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"));
} }
} }
} }

View File

@ -111,10 +111,10 @@ public class ExpressionScriptTests extends ElasticsearchIntegrationTest {
buildRequest("doc['bogus'].value").get(); buildRequest("doc['bogus'].value").get();
fail("Expected missing field to cause failure"); fail("Expected missing field to cause failure");
} catch (SearchPhaseExecutionException e) { } catch (SearchPhaseExecutionException e) {
assertThat(ExceptionsHelper.detailedMessage(e) + "should have contained ExpressionScriptCompilationException", assertThat(e.toString() + "should have contained ExpressionScriptCompilationException",
ExceptionsHelper.detailedMessage(e).contains("ExpressionScriptCompilationException"), equalTo(true)); e.toString().contains("ExpressionScriptCompilationException"), equalTo(true));
assertThat(ExceptionsHelper.detailedMessage(e) + "should have contained missing field error", assertThat(e.toString() + "should have contained missing field error",
ExceptionsHelper.detailedMessage(e).contains("does not exist in mappings"), equalTo(true)); e.toString().contains("does not exist in mappings"), equalTo(true));
} }
} }
@ -141,10 +141,10 @@ public class ExpressionScriptTests extends ElasticsearchIntegrationTest {
buildRequest("garbage%@#%@").get(); buildRequest("garbage%@#%@").get();
fail("Expected expression compilation failure"); fail("Expected expression compilation failure");
} catch (SearchPhaseExecutionException e) { } catch (SearchPhaseExecutionException e) {
assertThat(ExceptionsHelper.detailedMessage(e) + "should have contained ExpressionScriptCompilationException", assertThat(e.toString() + "should have contained ExpressionScriptCompilationException",
ExceptionsHelper.detailedMessage(e).contains("ExpressionScriptCompilationException"), equalTo(true)); e.toString().contains("ExpressionScriptCompilationException"), equalTo(true));
assertThat(ExceptionsHelper.detailedMessage(e) + "should have contained compilation failure", assertThat(e.toString() + "should have contained compilation failure",
ExceptionsHelper.detailedMessage(e).contains("Failed to parse expression"), equalTo(true)); e.toString().contains("Failed to parse expression"), equalTo(true));
} }
} }
@ -154,10 +154,10 @@ public class ExpressionScriptTests extends ElasticsearchIntegrationTest {
buildRequest("a", "a", "astring").get(); buildRequest("a", "a", "astring").get();
fail("Expected string parameter to cause failure"); fail("Expected string parameter to cause failure");
} catch (SearchPhaseExecutionException e) { } catch (SearchPhaseExecutionException e) {
assertThat(ExceptionsHelper.detailedMessage(e) + "should have contained ExpressionScriptCompilationException", assertThat(e.toString() + "should have contained ExpressionScriptCompilationException",
ExceptionsHelper.detailedMessage(e).contains("ExpressionScriptCompilationException"), equalTo(true)); e.toString().contains("ExpressionScriptCompilationException"), equalTo(true));
assertThat(ExceptionsHelper.detailedMessage(e) + "should have contained non-numeric parameter error", assertThat(e.toString() + "should have contained non-numeric parameter error",
ExceptionsHelper.detailedMessage(e).contains("must be a numeric type"), equalTo(true)); e.toString().contains("must be a numeric type"), equalTo(true));
} }
} }
@ -167,10 +167,10 @@ public class ExpressionScriptTests extends ElasticsearchIntegrationTest {
buildRequest("doc['text'].value").get(); buildRequest("doc['text'].value").get();
fail("Expected text field to cause execution failure"); fail("Expected text field to cause execution failure");
} catch (SearchPhaseExecutionException e) { } catch (SearchPhaseExecutionException e) {
assertThat(ExceptionsHelper.detailedMessage(e) + "should have contained ExpressionScriptCompilationException", assertThat(e.toString() + "should have contained ExpressionScriptCompilationException",
ExceptionsHelper.detailedMessage(e).contains("ExpressionScriptCompilationException"), equalTo(true)); e.toString().contains("ExpressionScriptCompilationException"), equalTo(true));
assertThat(ExceptionsHelper.detailedMessage(e) + "should have contained non-numeric field error", assertThat(e.toString() + "should have contained non-numeric field error",
ExceptionsHelper.detailedMessage(e).contains("must be numeric"), equalTo(true)); e.toString().contains("must be numeric"), equalTo(true));
} }
} }
@ -180,10 +180,10 @@ public class ExpressionScriptTests extends ElasticsearchIntegrationTest {
buildRequest("bogus").get(); buildRequest("bogus").get();
fail("Expected bogus variable to cause execution failure"); fail("Expected bogus variable to cause execution failure");
} catch (SearchPhaseExecutionException e) { } catch (SearchPhaseExecutionException e) {
assertThat(ExceptionsHelper.detailedMessage(e) + "should have contained ExpressionScriptCompilationException", assertThat(e.toString() + "should have contained ExpressionScriptCompilationException",
ExceptionsHelper.detailedMessage(e).contains("ExpressionScriptCompilationException"), equalTo(true)); e.toString().contains("ExpressionScriptCompilationException"), equalTo(true));
assertThat(ExceptionsHelper.detailedMessage(e) + "should have contained unknown variable error", assertThat(e.toString() + "should have contained unknown variable error",
ExceptionsHelper.detailedMessage(e).contains("Unknown variable"), equalTo(true)); e.toString().contains("Unknown variable"), equalTo(true));
} }
} }
@ -193,10 +193,10 @@ public class ExpressionScriptTests extends ElasticsearchIntegrationTest {
buildRequest("doc").get(); buildRequest("doc").get();
fail("Expected doc variable without field to cause execution failure"); fail("Expected doc variable without field to cause execution failure");
} catch (SearchPhaseExecutionException e) { } catch (SearchPhaseExecutionException e) {
assertThat(ExceptionsHelper.detailedMessage(e) + "should have contained ExpressionScriptCompilationException", assertThat(e.toString() + "should have contained ExpressionScriptCompilationException",
ExceptionsHelper.detailedMessage(e).contains("ExpressionScriptCompilationException"), equalTo(true)); e.toString().contains("ExpressionScriptCompilationException"), equalTo(true));
assertThat(ExceptionsHelper.detailedMessage(e) + "should have contained a missing specific field error", assertThat(e.toString() + "should have contained a missing specific field error",
ExceptionsHelper.detailedMessage(e).contains("must be used with a specific field"), equalTo(true)); e.toString().contains("must be used with a specific field"), equalTo(true));
} }
} }
@ -206,10 +206,10 @@ public class ExpressionScriptTests extends ElasticsearchIntegrationTest {
buildRequest("doc['foo'].bogus").get(); buildRequest("doc['foo'].bogus").get();
fail("Expected bogus field member to cause execution failure"); fail("Expected bogus field member to cause execution failure");
} catch (SearchPhaseExecutionException e) { } catch (SearchPhaseExecutionException e) {
assertThat(ExceptionsHelper.detailedMessage(e) + "should have contained ExpressionScriptCompilationException", assertThat(e.toString() + "should have contained ExpressionScriptCompilationException",
ExceptionsHelper.detailedMessage(e).contains("ExpressionScriptCompilationException"), equalTo(true)); e.toString().contains("ExpressionScriptCompilationException"), equalTo(true));
assertThat(ExceptionsHelper.detailedMessage(e) + "should have contained field member error", assertThat(e.toString() + "should have contained field member error",
ExceptionsHelper.detailedMessage(e).contains("Invalid member for field"), equalTo(true)); e.toString().contains("Invalid member for field"), equalTo(true));
} }
} }
@ -260,7 +260,7 @@ public class ExpressionScriptTests extends ElasticsearchIntegrationTest {
assertThat(rsp.getShardFailures().length, greaterThan(0)); // at least the shards containing the docs should have failed assertThat(rsp.getShardFailures().length, greaterThan(0)); // at least the shards containing the docs should have failed
message = rsp.getShardFailures()[0].reason(); message = rsp.getShardFailures()[0].reason();
} catch (SearchPhaseExecutionException e) { } catch (SearchPhaseExecutionException e) {
message = ExceptionsHelper.detailedMessage(e); message = e.toString();
} }
assertThat(message + "should have contained ExpressionScriptExecutionException", assertThat(message + "should have contained ExpressionScriptExecutionException",
message.contains("ExpressionScriptExecutionException"), equalTo(true)); message.contains("ExpressionScriptExecutionException"), equalTo(true));

View File

@ -57,7 +57,7 @@ public class AggregationsIntegrationTests extends ElasticsearchIntegrationTest {
client().prepareSearch("index").setSearchType(SearchType.SCAN).setScroll(new TimeValue(500)).addAggregation(terms("f").field("f")).get(); client().prepareSearch("index").setSearchType(SearchType.SCAN).setScroll(new TimeValue(500)).addAggregation(terms("f").field("f")).get();
fail(); fail();
} catch (SearchPhaseExecutionException e) { } 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"));
} }
} }

View File

@ -1314,7 +1314,7 @@ public class DateHistogramTests extends ElasticsearchIntegrationTest {
.actionGet(); .actionGet();
fail(); fail();
} catch (SearchPhaseExecutionException e) { } catch (SearchPhaseExecutionException e) {
assertThat(e.getMessage(), containsString("IllegalArgumentException")); assertThat(e.toString(), containsString("IllegalArgumentException"));
} }
} }
} }

View File

@ -1017,7 +1017,7 @@ public class HistogramTests extends ElasticsearchIntegrationTest {
.addAggregation(histogram("histo").field(SINGLE_VALUED_FIELD_NAME).interval(-1).minDocCount(0)).execute().actionGet(); .addAggregation(histogram("histo").field(SINGLE_VALUED_FIELD_NAME).interval(-1).minDocCount(0)).execute().actionGet();
fail(); fail();
} catch (SearchPhaseExecutionException e) { } catch (SearchPhaseExecutionException e) {
assertThat(e.getMessage(), containsString("Missing required field [interval]")); assertThat(e.toString(), containsString("Missing required field [interval]"));
} }
} }

View File

@ -365,7 +365,7 @@ public class NestedTests extends ElasticsearchIntegrationTest {
.execute().actionGet(); .execute().actionGet();
fail(); fail();
} catch (SearchPhaseExecutionException e) { } 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"));
} }
} }

View File

@ -520,7 +520,7 @@ public class TopHitsTests extends ElasticsearchIntegrationTest {
).get(); ).get();
fail(); fail();
} catch (SearchPhaseExecutionException e) { } 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 class TopHitsTests extends ElasticsearchIntegrationTest {
.get(); .get();
fail(); fail();
} catch (SearchPhaseExecutionException e) { } 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"));
} }
} }

View File

@ -108,14 +108,7 @@ import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFa
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchHit; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchHit;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchHits; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchHits;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.hasId; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.hasId;
import static org.hamcrest.Matchers.anyOf; import static org.hamcrest.Matchers.*;
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;
/** /**
* *
@ -1612,13 +1605,13 @@ public class SimpleChildQuerySearchTests extends ElasticsearchIntegrationTest {
client().prepareIndex("test", "child1", "c1").setParent("p1").setSource("c_field", "blue").get(); client().prepareIndex("test", "child1", "c1").setParent("p1").setSource("c_field", "blue").get();
fail(); fail();
} catch (ElasticsearchIllegalArgumentException e) { } 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 { try {
client().prepareIndex("test", "child2", "c2").setParent("p1").setSource("c_field", "blue").get(); client().prepareIndex("test", "child2", "c2").setParent("p1").setSource("c_field", "blue").get();
fail(); fail();
} catch (ElasticsearchIllegalArgumentException e) { } 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(); refresh();
@ -1645,7 +1638,7 @@ public class SimpleChildQuerySearchTests extends ElasticsearchIntegrationTest {
.endObject().endObject()).get(); .endObject().endObject()).get();
fail(); fail();
} catch (MergeMappingException e) { } 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 class SimpleChildQuerySearchTests extends ElasticsearchIntegrationTest {
response = minMaxQuery("none", 3, 2, cutoff); response = minMaxQuery("none", 3, 2, cutoff);
fail(); fail();
} catch (SearchPhaseExecutionException e) { } 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 // Score mode = SUM
@ -2412,7 +2405,7 @@ public class SimpleChildQuerySearchTests extends ElasticsearchIntegrationTest {
response = minMaxQuery("sum", 3, 2, cutoff); response = minMaxQuery("sum", 3, 2, cutoff);
fail(); fail();
} catch (SearchPhaseExecutionException e) { } 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 // Score mode = MAX
@ -2492,7 +2485,7 @@ public class SimpleChildQuerySearchTests extends ElasticsearchIntegrationTest {
response = minMaxQuery("max", 3, 2, cutoff); response = minMaxQuery("max", 3, 2, cutoff);
fail(); fail();
} catch (SearchPhaseExecutionException e) { } 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 // Score mode = AVG
@ -2572,7 +2565,7 @@ public class SimpleChildQuerySearchTests extends ElasticsearchIntegrationTest {
response = minMaxQuery("avg", 3, 2, cutoff); response = minMaxQuery("avg", 3, 2, cutoff);
fail(); fail();
} catch (SearchPhaseExecutionException e) { } 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 // HasChildFilter
@ -2652,7 +2645,7 @@ public class SimpleChildQuerySearchTests extends ElasticsearchIntegrationTest {
response = minMaxFilter(3, 2, cutoff); response = minMaxFilter(3, 2, cutoff);
fail(); fail();
} catch (SearchPhaseExecutionException e) { } 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'"));
} }
} }

View File

@ -874,8 +874,8 @@ public class DecayFunctionScoreTests extends ElasticsearchIntegrationTest {
searchSource().query(query))).actionGet(); searchSource().query(query))).actionGet();
fail("Should fail with SearchPhaseExecutionException"); fail("Should fail with SearchPhaseExecutionException");
} catch (SearchPhaseExecutionException failure) { } catch (SearchPhaseExecutionException failure) {
assertTrue(failure.getMessage().contains("SearchParseException")); assertTrue(failure.toString().contains("SearchParseException"));
assertFalse(failure.getMessage().contains("NullPointerException")); assertFalse(failure.toString().contains("NullPointerException"));
} }
query = "{\n" + query = "{\n" +
@ -908,26 +908,26 @@ public class DecayFunctionScoreTests extends ElasticsearchIntegrationTest {
searchSource().query(query))).actionGet(); searchSource().query(query))).actionGet();
fail("Should fail with SearchPhaseExecutionException"); fail("Should fail with SearchPhaseExecutionException");
} catch (SearchPhaseExecutionException failure) { } catch (SearchPhaseExecutionException failure) {
assertTrue(failure.getMessage().contains("SearchParseException")); assertTrue(failure.toString().contains("SearchParseException"));
assertFalse(failure.getMessage().contains("NullPointerException")); assertFalse(failure.toString().contains("NullPointerException"));
assertTrue(failure.getMessage().contains("One entry in functions list is missing a function")); assertTrue(failure.toString().contains("One entry in functions list is missing a function"));
} }
// next test java client // next test java client
try { try {
client().prepareSearch("t").setQuery(QueryBuilders.functionScoreQuery(FilterBuilders.matchAllFilter(), null)).get(); client().prepareSearch("t").setQuery(QueryBuilders.functionScoreQuery(FilterBuilders.matchAllFilter(), null)).get();
} catch (ElasticsearchIllegalArgumentException failure) { } catch (ElasticsearchIllegalArgumentException failure) {
assertTrue(failure.getMessage().contains("function must not be null")); assertTrue(failure.toString().contains("function must not be null"));
} }
try { try {
client().prepareSearch("t").setQuery(QueryBuilders.functionScoreQuery().add(FilterBuilders.matchAllFilter(), null)).get(); client().prepareSearch("t").setQuery(QueryBuilders.functionScoreQuery().add(FilterBuilders.matchAllFilter(), null)).get();
} catch (ElasticsearchIllegalArgumentException failure) { } catch (ElasticsearchIllegalArgumentException failure) {
assertTrue(failure.getMessage().contains("function must not be null")); assertTrue(failure.toString().contains("function must not be null"));
} }
try { try {
client().prepareSearch("t").setQuery(QueryBuilders.functionScoreQuery().add(null)).get(); client().prepareSearch("t").setQuery(QueryBuilders.functionScoreQuery().add(null)).get();
} catch (ElasticsearchIllegalArgumentException failure) { } catch (ElasticsearchIllegalArgumentException failure) {
assertTrue(failure.getMessage().contains("function must not be null")); assertTrue(failure.toString().contains("function must not be null"));
} }
} }

View File

@ -483,7 +483,7 @@ public class SearchQueryTests extends ElasticsearchIntegrationTest {
client().prepareSearch().setQuery(matchQuery("field1", "quick brown").type(MatchQueryBuilder.Type.PHRASE).slop(0)).get(); client().prepareSearch().setQuery(matchQuery("field1", "quick brown").type(MatchQueryBuilder.Type.PHRASE).slop(0)).get();
fail("SearchPhaseExecutionException should have been thrown"); fail("SearchPhaseExecutionException should have been thrown");
} catch (SearchPhaseExecutionException e) { } 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"); cluster().wipeIndices("test");
} catch (MapperParsingException ex) { } catch (MapperParsingException ex) {
@ -563,7 +563,7 @@ public class SearchQueryTests extends ElasticsearchIntegrationTest {
fail("expected SearchPhaseExecutionException (total failure)"); fail("expected SearchPhaseExecutionException (total failure)");
} catch (SearchPhaseExecutionException e) { } catch (SearchPhaseExecutionException e) {
assertThat(e.status(), equalTo(RestStatus.BAD_REQUEST)); 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 class SearchQueryTests extends ElasticsearchIntegrationTest {
.get(); .get();
fail("query is invalid and should have produced a parse exception"); fail("query is invalid and should have produced a parse exception");
} catch (Exception e) { } catch (Exception e) {
assertThat("query could not be parsed due to bad format: " + e.getMessage(), assertThat("query could not be parsed due to bad format: " + e.toString(),
e.getMessage().contains("Illegal value for id, expecting a string or number, got: START_ARRAY"), e.toString().contains("Illegal value for id, expecting a string or number, got: START_ARRAY"),
equalTo(true)); equalTo(true));
} }
} }

View File

@ -234,7 +234,7 @@ public class SimpleSearchTests extends ElasticsearchIntegrationTest {
client().prepareSearch("idx").setFrom(Integer.MAX_VALUE).get(); client().prepareSearch("idx").setFrom(Integer.MAX_VALUE).get();
fail(); fail();
} catch (SearchPhaseExecutionException e) { } 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:"));
} }
} }
} }

View File

@ -1131,7 +1131,7 @@ public class SimpleSortTests extends ElasticsearchIntegrationTest {
} catch (SearchPhaseExecutionException e) { } catch (SearchPhaseExecutionException e) {
//we check that it's a parse failure rather than a different shard failure //we check that it's a parse failure rather than a different shard failure
for (ShardSearchFailure shardSearchFailure : e.shardFailures()) { 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]"));
} }
} }

View File

@ -23,7 +23,6 @@ import com.carrotsearch.randomizedtesting.generators.RandomStrings;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import org.apache.lucene.util.LuceneTestCase.SuppressCodecs; 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.mapping.put.PutMappingResponse;
import org.elasticsearch.action.admin.indices.optimize.OptimizeResponse; import org.elasticsearch.action.admin.indices.optimize.OptimizeResponse;
import org.elasticsearch.action.admin.indices.segments.IndexShardSegments; import org.elasticsearch.action.admin.indices.segments.IndexShardSegments;
@ -50,7 +49,6 @@ import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
import org.elasticsearch.search.suggest.completion.CompletionSuggestionBuilder; import org.elasticsearch.search.suggest.completion.CompletionSuggestionBuilder;
import org.elasticsearch.search.suggest.completion.CompletionSuggestionFuzzyBuilder; import org.elasticsearch.search.suggest.completion.CompletionSuggestionFuzzyBuilder;
import org.elasticsearch.test.ElasticsearchIntegrationTest; import org.elasticsearch.test.ElasticsearchIntegrationTest;
import org.elasticsearch.test.hamcrest.ElasticsearchAssertions;
import org.junit.Test; import org.junit.Test;
import java.io.IOException; import java.io.IOException;
@ -177,7 +175,7 @@ public class CompletionSuggestSearchTests extends ElasticsearchIntegrationTest {
).get(); ).get();
fail("Indexing with a float weight was successful, but should not be"); fail("Indexing with a float weight was successful, but should not be");
} catch (MapperParsingException e) { } catch (MapperParsingException e) {
assertThat(ExceptionsHelper.detailedMessage(e), containsString("2.5")); assertThat(e.toString(), containsString("2.5"));
} }
} }
@ -221,7 +219,7 @@ public class CompletionSuggestSearchTests extends ElasticsearchIntegrationTest {
).get(); ).get();
fail("Indexing with a non-number representing string as weight was successful, but should not be"); fail("Indexing with a non-number representing string as weight was successful, but should not be");
} catch (MapperParsingException e) { } catch (MapperParsingException e) {
assertThat(ExceptionsHelper.detailedMessage(e), containsString("thisIsNotValid")); assertThat(e.toString(), containsString("thisIsNotValid"));
} }
} }
@ -239,7 +237,7 @@ public class CompletionSuggestSearchTests extends ElasticsearchIntegrationTest {
).get(); ).get();
fail("Indexing with weight string representing value > Int.MAX_VALUE was successful, but should not be"); fail("Indexing with weight string representing value > Int.MAX_VALUE was successful, but should not be");
} catch (MapperParsingException e) { } catch (MapperParsingException e) {
assertThat(ExceptionsHelper.detailedMessage(e), containsString(weight)); assertThat(e.toString(), containsString(weight));
} }
} }
@ -774,7 +772,7 @@ public class CompletionSuggestSearchTests extends ElasticsearchIntegrationTest {
fail("Expected an exception due to trying to sort on completion field, but did not happen"); fail("Expected an exception due to trying to sort on completion field, but did not happen");
} catch (SearchPhaseExecutionException e) { } catch (SearchPhaseExecutionException e) {
assertThat(e.status().getStatus(), is(400)); 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 class CompletionSuggestSearchTests extends ElasticsearchIntegrationTest {
// Exception must be thrown // Exception must be thrown
assertFalse(true); assertFalse(true);
} catch (SearchPhaseExecutionException e) { } 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 + "]"));
} }
} }

View File

@ -310,7 +310,7 @@ public class ElasticsearchAssertions {
assertVersionSerializable(searchResponse); assertVersionSerializable(searchResponse);
} catch (SearchPhaseExecutionException e) { } catch (SearchPhaseExecutionException e) {
assertThat(e.status(), equalTo(restStatus)); assertThat(e.status(), equalTo(restStatus));
assertThat(e.getMessage(), reasonMatcher); assertThat(e.toString(), reasonMatcher);
for (ShardSearchFailure shardSearchFailure : e.shardFailures()) { for (ShardSearchFailure shardSearchFailure : e.shardFailures()) {
assertThat(shardSearchFailure.status(), equalTo(restStatus)); assertThat(shardSearchFailure.status(), equalTo(restStatus));
assertThat(shardSearchFailure.reason(), reasonMatcher); assertThat(shardSearchFailure.reason(), reasonMatcher);