77
88package org .elasticsearch .xpack .esql .plugin ;
99
10- import org .elasticsearch .ElasticsearchTimeoutException ;
10+ import org .elasticsearch .index .query .MatchAllQueryBuilder ;
11+ import org .elasticsearch .index .query .MatchNoneQueryBuilder ;
1112import org .elasticsearch .transport .NoSuchRemoteClusterException ;
1213import org .elasticsearch .xpack .esql .VerificationException ;
1314import org .elasticsearch .xpack .esql .action .AbstractCrossClusterTestCase ;
15+ import org .elasticsearch .xpack .esql .action .EsqlExecutionInfo .Cluster .Status ;
1416import org .elasticsearch .xpack .esql .action .EsqlQueryAction ;
1517import org .elasticsearch .xpack .esql .action .EsqlQueryRequest ;
1618import org .elasticsearch .xpack .esql .action .EsqlQueryResponse ;
1719import org .elasticsearch .xpack .esql .core .expression .MetadataAttribute ;
1820
21+ import java .util .List ;
1922import java .util .Objects ;
2023import java .util .concurrent .TimeUnit ;
2124
@@ -29,9 +32,14 @@ public class RemoteIndexResolutionIT extends AbstractCrossClusterTestCase {
2932 public void testResolvesRemoteIndex () {
3033 indexRandom (REMOTE_CLUSTER_1 , true , "index-1" , 1 );
3134
32- try (var response = run (syncEsqlQueryRequest ().query ("FROM " + REMOTE_CLUSTER_1 + ":index-1 METADATA _index" ))) {
35+ try (
36+ var response = run (
37+ syncEsqlQueryRequest ().query ("FROM " + REMOTE_CLUSTER_1 + ":index-1 METADATA _index" ).includeCCSMetadata (true )
38+ )
39+ ) {
3340 assertOk (response );
3441 assertResultConcreteIndices (response , REMOTE_CLUSTER_1 + ":index-1" );
42+ assertExecutionInfo (response , new EsqlResponseExecutionInfo (REMOTE_CLUSTER_1 , "index-1" , Status .SUCCESSFUL ));
3543 }
3644 }
3745
@@ -40,6 +48,17 @@ public void testResolveRemoteUnknownIndex() {
4048 // This index is mixed into the resultset to test error handling of the missing concrete remote, not the empty result.
4149 indexRandom (LOCAL_CLUSTER , true , "data" , 1 );
4250
51+ expectThrows (
52+ VerificationException .class ,
53+ containsString ("Unknown index [" + REMOTE_CLUSTER_1 + ":fake]" ),
54+ () -> run (syncEsqlQueryRequest ().query ("FROM data," + REMOTE_CLUSTER_1 + ":fake" ))
55+ );
56+ expectThrows (
57+ VerificationException .class ,
58+ containsString ("Unknown index [" + REMOTE_CLUSTER_1 + ":fake]" ),
59+ () -> run (syncEsqlQueryRequest ().query ("FROM data," + REMOTE_CLUSTER_1 + ":fake" ).allowPartialResults (true ))
60+ );
61+
4362 setSkipUnavailable (REMOTE_CLUSTER_1 , false );
4463 expectThrows (
4564 VerificationException .class ,
@@ -48,25 +67,52 @@ public void testResolveRemoteUnknownIndex() {
4867 );
4968
5069 setSkipUnavailable (REMOTE_CLUSTER_1 , true );
51- try (var response = run (syncEsqlQueryRequest ().query ("FROM data," + REMOTE_CLUSTER_1 + ":fake METADATA _index" ))) {
70+ try (
71+ var response = run (
72+ syncEsqlQueryRequest ().query ("FROM data," + REMOTE_CLUSTER_1 + ":fake METADATA _index" ).includeCCSMetadata (true )
73+ )
74+ ) {
5275 assertPartial (response );
5376 assertResultConcreteIndices (response , "data" );
77+ assertExecutionInfo (
78+ response ,
79+ new EsqlResponseExecutionInfo (LOCAL_CLUSTER , "data" , Status .SUCCESSFUL ),
80+ new EsqlResponseExecutionInfo (REMOTE_CLUSTER_1 , "fake" , Status .SKIPPED )
81+ );
5482 }
5583
5684 setSkipUnavailable (REMOTE_CLUSTER_1 , null );
57- try (var response = run (syncEsqlQueryRequest ().query ("FROM data," + REMOTE_CLUSTER_1 + ":fake METADATA _index" ))) {
85+ try (
86+ var response = run (
87+ syncEsqlQueryRequest ().query ("FROM data," + REMOTE_CLUSTER_1 + ":fake METADATA _index" ).includeCCSMetadata (true )
88+ )
89+ ) {
5890 assertPartial (response );
5991 assertResultConcreteIndices (response , "data" );
92+ assertExecutionInfo (
93+ response ,
94+ new EsqlResponseExecutionInfo (LOCAL_CLUSTER , "data" , Status .SUCCESSFUL ),
95+ new EsqlResponseExecutionInfo (REMOTE_CLUSTER_1 , "fake" , Status .SKIPPED )
96+ );
6097 }
6198 }
6299
63100 public void testResolvesLocalAndRemoteIndex () {
64101 indexRandom (LOCAL_CLUSTER , true , "index-1" , 1 );
65102 indexRandom (REMOTE_CLUSTER_1 , true , "index-1" , 1 );
66103
67- try (var response = run (syncEsqlQueryRequest ().query ("FROM index-1," + REMOTE_CLUSTER_1 + ":index-1 METADATA _index" ))) {
104+ try (
105+ var response = run (
106+ syncEsqlQueryRequest ().query ("FROM index-1," + REMOTE_CLUSTER_1 + ":index-1 METADATA _index" ).includeCCSMetadata (true )
107+ )
108+ ) {
68109 assertOk (response );
69110 assertResultConcreteIndices (response , "index-1" , REMOTE_CLUSTER_1 + ":index-1" );
111+ assertExecutionInfo (
112+ response ,
113+ new EsqlResponseExecutionInfo (LOCAL_CLUSTER , "index-1" , Status .SUCCESSFUL ),
114+ new EsqlResponseExecutionInfo (REMOTE_CLUSTER_1 , "index-1" , Status .SUCCESSFUL )
115+ );
70116 }
71117 }
72118
@@ -75,13 +121,19 @@ public void testResolvesRemotesWithPattern() {
75121 indexRandom (REMOTE_CLUSTER_1 , true , "index-1" , 1 );
76122 indexRandom (REMOTE_CLUSTER_2 , true , "index-1" , 1 );
77123
78- try (var response = run (syncEsqlQueryRequest ().query ("FROM *:index-1 METADATA _index" ))) {
124+ try (var response = run (syncEsqlQueryRequest ().query ("FROM *:index-1 METADATA _index" ). includeCCSMetadata ( true ) )) {
79125 assertOk (response );
80126 assertResultConcreteIndices (response , REMOTE_CLUSTER_1 + ":index-1" , REMOTE_CLUSTER_2 + ":index-1" ); // local is not included
127+ assertExecutionInfo (
128+ response ,
129+ new EsqlResponseExecutionInfo (REMOTE_CLUSTER_1 , "index-1" , Status .SUCCESSFUL ),
130+ new EsqlResponseExecutionInfo (REMOTE_CLUSTER_2 , "index-1" , Status .SUCCESSFUL )
131+ );
81132 }
82- try (var response = run (syncEsqlQueryRequest ().query ("FROM fake*:index-1 METADATA _index" ))) {
133+ try (var response = run (syncEsqlQueryRequest ().query ("FROM fake*:index-1 METADATA _index" ). includeCCSMetadata ( true ) )) {
83134 assertOk (response );
84135 assertResultConcreteIndices (response ); // empty
136+ assertExecutionInfo (response ); // empty
85137 }
86138 }
87139
@@ -93,14 +145,33 @@ public void testDoesNotResolvesUnknownRemote() {
93145 );
94146 }
95147
96- private EsqlQueryResponse run (EsqlQueryRequest request ) {
97- try {
98- return client (LOCAL_CLUSTER ).execute (EsqlQueryAction .INSTANCE , request ).actionGet (30 , TimeUnit .SECONDS );
99- } catch (ElasticsearchTimeoutException e ) {
100- throw new AssertionError ("timeout" , e );
148+ public void testResolutionWithFilter () {
149+ indexRandom (REMOTE_CLUSTER_1 , true , "index-1" , 1 );
150+
151+ try (
152+ var response = run (
153+ syncEsqlQueryRequest ().query ("FROM " + REMOTE_CLUSTER_1 + ":index-1 METADATA _index" ).filter (new MatchAllQueryBuilder ())
154+ )
155+ ) {
156+ assertOk (response );
157+ assertResultConcreteIndices (response , REMOTE_CLUSTER_1 + ":index-1" );
158+ assertExecutionInfo (response , new EsqlResponseExecutionInfo (REMOTE_CLUSTER_1 , "index-1" , Status .SUCCESSFUL ));
159+ }
160+ try (
161+ var response = run (
162+ syncEsqlQueryRequest ().query ("FROM " + REMOTE_CLUSTER_1 + ":index-1 METADATA _index" ).filter (new MatchNoneQueryBuilder ())
163+ )
164+ ) {
165+ assertOk (response );
166+ assertResultConcreteIndices (response );
167+ assertExecutionInfo (response , new EsqlResponseExecutionInfo (REMOTE_CLUSTER_1 , "index-1" , Status .SUCCESSFUL ));
101168 }
102169 }
103170
171+ private EsqlQueryResponse run (EsqlQueryRequest request ) {
172+ return client (LOCAL_CLUSTER ).execute (EsqlQueryAction .INSTANCE , request ).actionGet (30 , TimeUnit .SECONDS );
173+ }
174+
104175 private void indexRandom (String clusterAlias , boolean forceRefresh , String index , int numDocs ) {
105176 assert numDocs == 1 ;
106177 var client = client (clusterAlias );
@@ -123,6 +194,10 @@ private static void assertResultConcreteIndices(EsqlQueryResponse response, Obje
123194 assertThat (() -> response .column (indexColumn ), containsInAnyOrder (indices ));
124195 }
125196
197+ private static void assertExecutionInfo (EsqlQueryResponse response , EsqlResponseExecutionInfo ... infos ) {
198+ assertThat (executionInfo (response ), containsInAnyOrder (infos ));
199+ }
200+
126201 private static int findIndexColumn (EsqlQueryResponse response ) {
127202 for (int c = 0 ; c < response .columns ().size (); c ++) {
128203 if (Objects .equals (response .columns ().get (c ).name (), MetadataAttribute .INDEX )) {
@@ -131,4 +206,15 @@ private static int findIndexColumn(EsqlQueryResponse response) {
131206 }
132207 throw new AssertionError ("no _index column found" );
133208 }
209+
210+ private static List <EsqlResponseExecutionInfo > executionInfo (EsqlQueryResponse response ) {
211+ return response .getExecutionInfo ()
212+ .getClusters ()
213+ .values ()
214+ .stream ()
215+ .map (cluster -> new EsqlResponseExecutionInfo (cluster .getClusterAlias (), cluster .getIndexExpression (), cluster .getStatus ()))
216+ .toList ();
217+ }
218+
219+ private record EsqlResponseExecutionInfo (String alias , String index , Status status ) {}
134220}
0 commit comments