Skip to content
Draft
Original file line number Diff line number Diff line change
Expand Up @@ -202,9 +202,9 @@ public void testIndicesDontExist() throws IOException {
indexTimestampData(docsTest1, "test1", "2024-11-26", "id1");

ResponseException e = expectThrows(ResponseException.class, () -> runEsql(timestampFilter("gte", "2020-01-01").query(from("foo"))));
assertEquals(400, e.getResponse().getStatusLine().getStatusCode());
assertThat(e.getMessage(), containsString("verification_exception"));
assertThat(e.getMessage(), anyOf(containsString("Unknown index [foo]"), containsString("Unknown index [remote_cluster:foo]")));
assertEquals(404, e.getResponse().getStatusLine().getStatusCode());
assertThat(e.getMessage(), containsString("index_not_found_exception"));
assertThat(e.getMessage(), anyOf(containsString("no such index [foo]"), containsString("Unknown index [remote_cluster:foo]")));

e = expectThrows(ResponseException.class, () -> runEsql(timestampFilter("gte", "2020-01-01").query(from("foo*"))));
assertEquals(400, e.getResponse().getStatusLine().getStatusCode());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
package org.elasticsearch.xpack.esql.action;

import org.elasticsearch.Build;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse;
Expand Down Expand Up @@ -155,14 +156,10 @@ public void testSearchesAgainstNonMatchingIndicesWithLocalOnly() throws Exceptio

{
String q = "FROM nomatch," + localIndex;
IndexNotFoundException e = expectThrows(IndexNotFoundException.class, () -> runQuery(q, false));
assertThat(e.getDetailedMessage(), containsString("no such index [nomatch]"));

// MP TODO: am I able to fix this from the field-caps call? Yes, if we detect concrete vs. wildcard expressions in user query
// TODO bug - this does not throw; uncomment this test once https://github.com/elastic/elasticsearch/issues/114495 is fixed
// String limit0 = q + " | LIMIT 0";
// VerificationException ve = expectThrows(VerificationException.class, () -> runQuery(limit0, false));
// assertThat(ve.getDetailedMessage(), containsString("No matching indices for [nomatch]"));
expectNotFoundExceptionForQuery(q, "no such index [nomatch]", false);

String limit0 = q + " | LIMIT 0";
expectNotFoundExceptionForQuery(limit0, "no such index [nomatch]", false);
}

{
Expand All @@ -186,8 +183,8 @@ public void testSearchesAgainstNonMatchingIndicesWithLocalOnly() throws Exceptio
}
{
String q = "FROM nomatch";
String expectedError = "Unknown index [nomatch]";
expectVerificationExceptionForQuery(q, expectedError, false);
String expectedError = "no such index [nomatch]";
expectNotFoundExceptionForQuery(q, expectedError, false);
}
{
String q = "FROM nomatch*";
Expand Down Expand Up @@ -273,8 +270,8 @@ public void testSearchesAgainstNonMatchingIndices() throws Exception {
// missing concrete local index is an error
{
String q = "FROM nomatch,cluster-a:" + remote1Index;
String expectedError = "Unknown index [nomatch]";
expectVerificationExceptionForQuery(q, expectedError, requestIncludeMeta);
String expectedError = "no such index [nomatch]";
expectNotFoundExceptionForQuery(q, expectedError, requestIncludeMeta);
}

// missing concrete remote index is fatal
Expand All @@ -300,6 +297,13 @@ public void testSearchesAgainstNonMatchingIndices() throws Exception {
}
}

// missing concrete remote index is fatal
{
String q = "FROM logs*,cluster-a:logs*,cluster-a:nomatch";
String expectedError = "Unknown index [cluster-a:logs*,nomatch]";
expectVerificationExceptionForQuery(q, expectedError, requestIncludeMeta);
}

// No error since local non-matching index has wildcard and the remote cluster index expression matches
{
String remote1IndexName = randomFrom(remote1Index, IDX_ALIAS, FILTERED_IDX_ALIAS);
Expand Down Expand Up @@ -384,8 +388,8 @@ public void testSearchesAgainstNonMatchingIndices() throws Exception {
// an error is thrown if there is a concrete index that does not match
{
String q = "FROM cluster-a:nomatch";
String expectedError = "Unknown index [cluster-a:nomatch]";
expectVerificationExceptionForQuery(q, expectedError, requestIncludeMeta);
String expectedError = "no such index [nomatch]";
expectExceptionForQuery(q, expectedError, requestIncludeMeta, IndexNotFoundException.class);
}

// an error is thrown if there are no matching indices at all - single remote cluster with wildcard index expression
Expand All @@ -398,8 +402,8 @@ public void testSearchesAgainstNonMatchingIndices() throws Exception {
// an error is thrown if there is a concrete index that does not match
{
String q = "FROM nomatch*,cluster-a:nomatch";
String expectedError = "Unknown index [cluster-a:nomatch,nomatch*]";
expectVerificationExceptionForQuery(q, expectedError, requestIncludeMeta);
String expectedError = "no such index [nomatch]";
expectNotFoundExceptionForQuery(q, expectedError, requestIncludeMeta);
}

// an error is thrown if there are no matching indices at all - local with wildcard, remote with wildcard
Expand All @@ -410,13 +414,13 @@ public void testSearchesAgainstNonMatchingIndices() throws Exception {
}
{
String q = "FROM nomatch,cluster-a:nomatch";
String expectedError = "Unknown index [cluster-a:nomatch,nomatch]";
expectVerificationExceptionForQuery(q, expectedError, requestIncludeMeta);
String expectedError = "no such index [nomatch]";
expectNotFoundExceptionForQuery(q, expectedError, requestIncludeMeta);
}
{
String q = "FROM nomatch,cluster-a:nomatch*";
String expectedError = "Unknown index [cluster-a:nomatch*,nomatch]";
expectVerificationExceptionForQuery(q, expectedError, requestIncludeMeta);
String expectedError = "no such index [nomatch]";
expectNotFoundExceptionForQuery(q, expectedError, requestIncludeMeta);
}

// --- test against 3 clusters
Expand Down Expand Up @@ -465,11 +469,32 @@ record ExpectedCluster(String clusterAlias, String indexExpression, EsqlExecutio
* extra processing step to ensure that ESQL coordinator-only operations throw the same VerificationError.
*/
private void expectVerificationExceptionForQuery(String query, String error, Boolean requestIncludeMeta) {
VerificationException e = expectThrows(VerificationException.class, () -> runQuery(query, requestIncludeMeta));
expectExceptionForQuery(query, error, requestIncludeMeta, VerificationException.class);
}

/**
* Runs the provided query, expecting a VerificationError. It then runs the same query with a "| LIMIT 0"
* extra processing step to ensure that ESQL coordinator-only operations throw the same VerificationError.
*/
private void expectNotFoundExceptionForQuery(String query, String error, Boolean requestIncludeMeta) {
expectExceptionForQuery(query, error, requestIncludeMeta, IndexNotFoundException.class);
}

/**
* Runs the provided query, expecting a VerificationError. It then runs the same query with a "| LIMIT 0"
* extra processing step to ensure that ESQL coordinator-only operations throw the same VerificationError.
*/
private <ET extends ElasticsearchException> void expectExceptionForQuery(
String query,
String error,
Boolean requestIncludeMeta,
Class<ET> clazz
) {
ET e = expectThrows(clazz, () -> runQuery(query, requestIncludeMeta));
assertThat(e.getDetailedMessage(), containsString(error));

String limit0 = query + " | LIMIT 0";
e = expectThrows(VerificationException.class, () -> runQuery(limit0, requestIncludeMeta));
e = expectThrows(clazz, () -> runQuery(limit0, requestIncludeMeta));
assertThat(e.getDetailedMessage(), containsString(error));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public class IndexResolver {
public static final String UNMAPPED = "unmapped";

public static final IndicesOptions FIELD_CAPS_INDICES_OPTIONS = IndicesOptions.builder()
.concreteTargetOptions(IndicesOptions.ConcreteTargetOptions.ALLOW_UNAVAILABLE_TARGETS)
.concreteTargetOptions(IndicesOptions.ConcreteTargetOptions.ERROR_WHEN_UNAVAILABLE_TARGETS)
.wildcardOptions(
IndicesOptions.WildcardOptions.builder()
.matchOpen(true)
Expand Down