diff --git a/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/RequestIndexFilteringIT.java b/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/RequestIndexFilteringIT.java index 2e67ad06dc0a3..ccd9ae7b48beb 100644 --- a/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/RequestIndexFilteringIT.java +++ b/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/RequestIndexFilteringIT.java @@ -39,6 +39,7 @@ import static org.hamcrest.Matchers.greaterThanOrEqualTo; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; @ThreadLeakFilters(filters = TestClustersThreadFilter.class) public class RequestIndexFilteringIT extends RequestIndexFilteringTestCase { @@ -97,6 +98,12 @@ protected String from(String... indexName) { @Override public Map runEsql(RestEsqlTestCase.RequestObjectBuilder requestObject) throws IOException { + return runEsql(requestObject, true); + } + + @Override + public Map runEsql(RestEsqlTestCase.RequestObjectBuilder requestObject, boolean checkPartialResults) + throws IOException { if (requestObject.allowPartialResults() != null) { assumeTrue( "require allow_partial_results on local cluster", @@ -104,7 +111,7 @@ public Map runEsql(RestEsqlTestCase.RequestObjectBuilder request ); } requestObject.includeCCSMetadata(true); - return super.runEsql(requestObject); + return super.runEsql(requestObject, checkPartialResults); } @After @@ -160,7 +167,30 @@ public void testIndicesDontExistRemote() throws IOException { indexTimestampData(docsTest1, "test1", "2024-11-26", "id1"); Map result = runEsql( - timestampFilter("gte", "2020-01-01").query("FROM *:foo,*:test1 METADATA _index | SORT id1 | KEEP _index, id*") + timestampFilter("gte", "2020-01-01").query("FROM *:foo,*:test1 METADATA _index | SORT id1 | KEEP _index, id*"), + false + ); + + // `foo` index doesn't exist, so the request will currently be successful, but with partial results + var isPartial = result.get("is_partial"); + assertThat(isPartial, is(true)); + assertThat( + result, + matchesMap().entry( + "_clusters", + matchesMap().entry( + "details", + matchesMap().entry( + "remote_cluster", + matchesMap().entry( + "failures", + matchesList().item( + matchesMap().entry("reason", matchesMap().entry("reason", "no such index [foo]").extraOk()).extraOk() + ) + ).extraOk() + ).extraOk() + ).extraOk() + ).extraOk() ); @SuppressWarnings("unchecked") var columns = (List>) result.get("columns"); diff --git a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/EsqlSpecTestCase.java b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/EsqlSpecTestCase.java index 58015f3ca410a..1f00bdf18774e 100644 --- a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/EsqlSpecTestCase.java +++ b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/EsqlSpecTestCase.java @@ -268,9 +268,7 @@ protected final void doTest() throws Throwable { Map answer = runEsql(builder.query(testCase.query), testCase.assertWarnings(deduplicateExactWarnings())); - var clusters = answer.get("_clusters"); - var reason = "unexpected partial results" + (clusters != null ? ": _clusters=" + clusters : ""); - assertThat(reason, answer.get("is_partial"), anyOf(nullValue(), is(false))); + assertNotPartial(answer); var expectedColumnsWithValues = loadCsvSpecValues(testCase.expectedResults); @@ -288,6 +286,14 @@ protected final void doTest() throws Throwable { assertResults(expectedColumnsWithValues, actualColumns, actualValues, testCase.ignoreOrder, logger); } + static Map assertNotPartial(Map answer) { + var clusters = answer.get("_clusters"); + var reason = "unexpected partial results" + (clusters != null ? ": _clusters=" + clusters : ""); + assertThat(reason, answer.get("is_partial"), anyOf(nullValue(), is(false))); + + return answer; + } + /** * Should warnings be de-duplicated before checking for exact matches. Defaults * to {@code false}, but in some environments we emit duplicate warnings. We'd prefer diff --git a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RequestIndexFilteringTestCase.java b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RequestIndexFilteringTestCase.java index 1cb2a6a526191..1ba4365ea3e92 100644 --- a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RequestIndexFilteringTestCase.java +++ b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RequestIndexFilteringTestCase.java @@ -249,6 +249,11 @@ public Map runEsql(RestEsqlTestCase.RequestObjectBuilder request return RestEsqlTestCase.runEsql(requestObject, new AssertWarnings.NoWarnings(), RestEsqlTestCase.Mode.SYNC); } + public Map runEsql(RestEsqlTestCase.RequestObjectBuilder requestObject, boolean checkPartialResults) + throws IOException { + return RestEsqlTestCase.runEsql(requestObject, new AssertWarnings.NoWarnings(), RestEsqlTestCase.Mode.SYNC, checkPartialResults); + } + protected void indexTimestampData(int docs, String indexName, String date, String differentiatorFieldName) throws IOException { indexTimestampDataForClient(client(), docs, indexName, date, differentiatorFieldName); } diff --git a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RestEsqlTestCase.java b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RestEsqlTestCase.java index 39a7f6f25f80e..ba7d4f2c53ae7 100644 --- a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RestEsqlTestCase.java +++ b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RestEsqlTestCase.java @@ -62,6 +62,7 @@ import static org.elasticsearch.test.MapMatcher.assertMap; import static org.elasticsearch.test.MapMatcher.matchesMap; import static org.elasticsearch.xpack.esql.EsqlTestUtils.as; +import static org.elasticsearch.xpack.esql.qa.rest.EsqlSpecTestCase.assertNotPartial; import static org.elasticsearch.xpack.esql.qa.rest.RestEsqlTestCase.Mode.ASYNC; import static org.elasticsearch.xpack.esql.qa.rest.RestEsqlTestCase.Mode.SYNC; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.dateTimeToString; @@ -1242,13 +1243,21 @@ public static Map runEsqlAsync(RequestObjectBuilder requestObjec return runEsqlAsync(requestObject, randomBoolean(), new AssertWarnings.NoWarnings()); } + public static Map runEsql( + RequestObjectBuilder requestObject, + AssertWarnings assertWarnings, + Mode mode, + boolean checkPartialResults + ) throws IOException { + var results = mode == ASYNC + ? runEsqlAsync(requestObject, randomBoolean(), assertWarnings) + : runEsqlSync(requestObject, assertWarnings); + return checkPartialResults ? assertNotPartial(results) : results; + } + public static Map runEsql(RequestObjectBuilder requestObject, AssertWarnings assertWarnings, Mode mode) throws IOException { - if (mode == ASYNC) { - return runEsqlAsync(requestObject, randomBoolean(), assertWarnings); - } else { - return runEsqlSync(requestObject, assertWarnings); - } + return runEsql(requestObject, assertWarnings, mode, true); } public static Map runEsqlSync(RequestObjectBuilder requestObject, AssertWarnings assertWarnings) throws IOException {