88package org .elasticsearch .xpack .esql .action ;
99
1010import org .elasticsearch .Build ;
11+ import org .elasticsearch .ElasticsearchException ;
1112import org .elasticsearch .action .ActionListener ;
1213import org .elasticsearch .action .admin .cluster .health .ClusterHealthResponse ;
1314import org .elasticsearch .action .admin .indices .alias .IndicesAliasesResponse ;
@@ -156,14 +157,10 @@ public void testSearchesAgainstNonMatchingIndicesWithLocalOnly() throws Exceptio
156157
157158 {
158159 String q = "FROM nomatch," + localIndex ;
159- IndexNotFoundException e = expectThrows (IndexNotFoundException .class , () -> runQuery (q , false ));
160- assertThat (e .getDetailedMessage (), containsString ("no such index [nomatch]" ));
160+ expectNotFoundExceptionForQuery (q , "no such index [nomatch]" , false );
161161
162- // MP TODO: am I able to fix this from the field-caps call? Yes, if we detect concrete vs. wildcard expressions in user query
163- // TODO bug - this does not throw; uncomment this test once https://github.com/elastic/elasticsearch/issues/114495 is fixed
164- // String limit0 = q + " | LIMIT 0";
165- // VerificationException ve = expectThrows(VerificationException.class, () -> runQuery(limit0, false));
166- // assertThat(ve.getDetailedMessage(), containsString("No matching indices for [nomatch]"));
162+ String limit0 = q + " | LIMIT 0" ;
163+ expectNotFoundExceptionForQuery (limit0 , "no such index [nomatch]" , false );
167164 }
168165
169166 {
@@ -187,8 +184,8 @@ public void testSearchesAgainstNonMatchingIndicesWithLocalOnly() throws Exceptio
187184 }
188185 {
189186 String q = "FROM nomatch" ;
190- String expectedError = "Unknown index [nomatch]" ;
191- expectVerificationExceptionForQuery (q , expectedError , false );
187+ String expectedError = "no such index [nomatch]" ;
188+ expectNotFoundExceptionForQuery (q , expectedError , false );
192189 }
193190 {
194191 String q = "FROM nomatch*" ;
@@ -273,8 +270,8 @@ public void testSearchesAgainstNonMatchingIndices() throws Exception {
273270 // missing concrete local index is an error
274271 {
275272 String q = "FROM nomatch,cluster-a:" + remote1Index ;
276- String expectedError = "Unknown index [nomatch]" ;
277- expectVerificationExceptionForQuery (q , expectedError , requestIncludeMeta );
273+ String expectedError = "no such index [nomatch]" ;
274+ expectNotFoundExceptionForQuery (q , expectedError , requestIncludeMeta );
278275 }
279276
280277 // missing concrete remote index is fatal
@@ -284,6 +281,13 @@ public void testSearchesAgainstNonMatchingIndices() throws Exception {
284281 expectVerificationExceptionForQuery (q , expectedError , requestIncludeMeta );
285282 }
286283
284+ // missing concrete remote index is fatal
285+ {
286+ String q = "FROM logs*,cluster-a:logs*,cluster-a:nomatch" ;
287+ String expectedError = "Unknown index [cluster-a:logs*,nomatch]" ;
288+ expectVerificationExceptionForQuery (q , expectedError , requestIncludeMeta );
289+ }
290+
287291 // No error since local non-matching index has wildcard and the remote cluster index expression matches
288292 {
289293 String remote1IndexName = randomFrom (remote1Index , IDX_ALIAS , FILTERED_IDX_ALIAS );
@@ -368,8 +372,8 @@ public void testSearchesAgainstNonMatchingIndices() throws Exception {
368372 // an error is thrown if there is a concrete index that does not match
369373 {
370374 String q = "FROM cluster-a:nomatch" ;
371- String expectedError = "Unknown index [cluster-a: nomatch]" ;
372- expectVerificationExceptionForQuery (q , expectedError , requestIncludeMeta );
375+ String expectedError = "no such index [nomatch]" ;
376+ expectExceptionForQuery (q , expectedError , requestIncludeMeta , IndexNotFoundException . class );
373377 }
374378
375379 // an error is thrown if there are no matching indices at all - single remote cluster with wildcard index expression
@@ -382,8 +386,8 @@ public void testSearchesAgainstNonMatchingIndices() throws Exception {
382386 // an error is thrown if there is a concrete index that does not match
383387 {
384388 String q = "FROM nomatch*,cluster-a:nomatch" ;
385- String expectedError = "Unknown index [cluster-a: nomatch,nomatch* ]" ;
386- expectVerificationExceptionForQuery (q , expectedError , requestIncludeMeta );
389+ String expectedError = "no such index [nomatch]" ;
390+ expectNotFoundExceptionForQuery (q , expectedError , requestIncludeMeta );
387391 }
388392
389393 // an error is thrown if there are no matching indices at all - local with wildcard, remote with wildcard
@@ -394,13 +398,13 @@ public void testSearchesAgainstNonMatchingIndices() throws Exception {
394398 }
395399 {
396400 String q = "FROM nomatch,cluster-a:nomatch" ;
397- String expectedError = "Unknown index [cluster-a:nomatch, nomatch]" ;
398- expectVerificationExceptionForQuery (q , expectedError , requestIncludeMeta );
401+ String expectedError = "no such index [nomatch]" ;
402+ expectNotFoundExceptionForQuery (q , expectedError , requestIncludeMeta );
399403 }
400404 {
401405 String q = "FROM nomatch,cluster-a:nomatch*" ;
402- String expectedError = "Unknown index [cluster-a:nomatch*, nomatch]" ;
403- expectVerificationExceptionForQuery (q , expectedError , requestIncludeMeta );
406+ String expectedError = "no such index [nomatch]" ;
407+ expectNotFoundExceptionForQuery (q , expectedError , requestIncludeMeta );
404408 }
405409
406410 // --- test against 3 clusters
@@ -422,11 +426,32 @@ record ExpectedCluster(String clusterAlias, String indexExpression, EsqlExecutio
422426 * extra processing step to ensure that ESQL coordinator-only operations throw the same VerificationError.
423427 */
424428 private void expectVerificationExceptionForQuery (String query , String error , Boolean requestIncludeMeta ) {
425- VerificationException e = expectThrows (VerificationException .class , () -> runQuery (query , requestIncludeMeta ));
429+ expectExceptionForQuery (query , error , requestIncludeMeta , VerificationException .class );
430+ }
431+
432+ /**
433+ * Runs the provided query, expecting a VerificationError. It then runs the same query with a "| LIMIT 0"
434+ * extra processing step to ensure that ESQL coordinator-only operations throw the same VerificationError.
435+ */
436+ private void expectNotFoundExceptionForQuery (String query , String error , Boolean requestIncludeMeta ) {
437+ expectExceptionForQuery (query , error , requestIncludeMeta , IndexNotFoundException .class );
438+ }
439+
440+ /**
441+ * Runs the provided query, expecting a VerificationError. It then runs the same query with a "| LIMIT 0"
442+ * extra processing step to ensure that ESQL coordinator-only operations throw the same VerificationError.
443+ */
444+ private <ET extends ElasticsearchException > void expectExceptionForQuery (
445+ String query ,
446+ String error ,
447+ Boolean requestIncludeMeta ,
448+ Class <ET > clazz
449+ ) {
450+ ET e = expectThrows (clazz , () -> runQuery (query , requestIncludeMeta ));
426451 assertThat (e .getDetailedMessage (), containsString (error ));
427452
428453 String limit0 = query + " | LIMIT 0" ;
429- e = expectThrows (VerificationException . class , () -> runQuery (limit0 , requestIncludeMeta ));
454+ e = expectThrows (clazz , () -> runQuery (limit0 , requestIncludeMeta ));
430455 assertThat (e .getDetailedMessage (), containsString (error ));
431456 }
432457
0 commit comments