1111import org .elasticsearch .client .Request ;
1212import org .elasticsearch .client .Response ;
1313import org .elasticsearch .client .ResponseException ;
14+ import org .elasticsearch .client .RestClient ;
1415import org .elasticsearch .test .rest .ESRestTestCase ;
1516import org .elasticsearch .xcontent .XContentType ;
1617import org .elasticsearch .xpack .esql .AssertWarnings ;
3031import static org .elasticsearch .xpack .esql .qa .rest .RestEsqlTestCase .entityToMap ;
3132import static org .elasticsearch .xpack .esql .qa .rest .RestEsqlTestCase .requestObjectBuilder ;
3233import static org .hamcrest .Matchers .allOf ;
34+ import static org .hamcrest .Matchers .anyOf ;
3335import static org .hamcrest .Matchers .containsString ;
34- import static org .hamcrest .Matchers .equalTo ;
3536import static org .hamcrest .Matchers .greaterThanOrEqualTo ;
3637import static org .hamcrest .Matchers .hasSize ;
3738import static org .hamcrest .Matchers .instanceOf ;
3839import static org .hamcrest .Matchers .nullValue ;
40+ import static org .hamcrest .Matchers .oneOf ;
3941
4042public abstract class RequestIndexFilteringTestCase extends ESRestTestCase {
4143
@@ -49,14 +51,18 @@ public void wipeTestData() throws IOException {
4951 }
5052 }
5153
54+ protected String from (String ... indexName ) {
55+ return "FROM " + String .join ("," , indexName );
56+ }
57+
5258 public void testTimestampFilterFromQuery () throws IOException {
5359 int docsTest1 = 50 ;
5460 int docsTest2 = 30 ;
5561 indexTimestampData (docsTest1 , "test1" , "2024-11-26" , "id1" );
5662 indexTimestampData (docsTest2 , "test2" , "2023-11-26" , "id2" );
5763
5864 // filter includes both indices in the result (all columns, all rows)
59- RestEsqlTestCase .RequestObjectBuilder builder = timestampFilter ("gte" , "2023-01-01" ).query ("FROM test*" );
65+ RestEsqlTestCase .RequestObjectBuilder builder = timestampFilter ("gte" , "2023-01-01" ).query (from ( " test*") );
6066 Map <String , Object > result = runEsql (builder );
6167 assertMap (
6268 result ,
@@ -70,7 +76,7 @@ public void testTimestampFilterFromQuery() throws IOException {
7076 );
7177
7278 // filter includes only test1. Columns from test2 are filtered out, as well (not only rows)!
73- builder = timestampFilter ("gte" , "2024-01-01" ).query ("FROM test*" );
79+ builder = timestampFilter ("gte" , "2024-01-01" ).query (from ( " test*") );
7480 assertMap (
7581 runEsql (builder ),
7682 matchesMap ().entry (
@@ -83,7 +89,7 @@ public void testTimestampFilterFromQuery() throws IOException {
8389
8490 // filter excludes both indices (no rows); the first analysis step fails because there are no columns, a second attempt succeeds
8591 // after eliminating the index filter. All columns are returned.
86- builder = timestampFilter ("gte" , "2025-01-01" ).query ("FROM test*" );
92+ builder = timestampFilter ("gte" , "2025-01-01" ).query (from ( " test*") );
8793 assertMap (
8894 runEsql (builder ),
8995 matchesMap ().entry (
@@ -103,7 +109,7 @@ public void testFieldExistsFilter_KeepWildcard() throws IOException {
103109 indexTimestampData (docsTest2 , "test2" , "2023-11-26" , "id2" );
104110
105111 // filter includes only test1. Columns and rows of test2 are filtered out
106- RestEsqlTestCase .RequestObjectBuilder builder = existsFilter ("id1" ).query ("FROM test*" );
112+ RestEsqlTestCase .RequestObjectBuilder builder = existsFilter ("id1" ).query (from ( " test*") );
107113 Map <String , Object > result = runEsql (builder );
108114 assertMap (
109115 result ,
@@ -116,7 +122,7 @@ public void testFieldExistsFilter_KeepWildcard() throws IOException {
116122 );
117123
118124 // filter includes only test1. Columns from test2 are filtered out, as well (not only rows)!
119- builder = existsFilter ("id1" ).query ("FROM test* METADATA _index | KEEP _index, id*" );
125+ builder = existsFilter ("id1" ).query (from ( " test*" ) + " METADATA _index | KEEP _index, id*" );
120126 result = runEsql (builder );
121127 assertMap (
122128 result ,
@@ -129,7 +135,7 @@ public void testFieldExistsFilter_KeepWildcard() throws IOException {
129135 @ SuppressWarnings ("unchecked" )
130136 var values = (List <List <Object >>) result .get ("values" );
131137 for (List <Object > row : values ) {
132- assertThat (row .get (0 ), equalTo ( " test1" ));
138+ assertThat (row .get (0 ), oneOf ( "test1" , "remote_cluster: test1" ));
133139 assertThat (row .get (1 ), instanceOf (Integer .class ));
134140 }
135141 }
@@ -142,7 +148,7 @@ public void testFieldExistsFilter_With_ExplicitUseOfDiscardedIndexFields() throw
142148
143149 // test2 is explicitly used in a query with "SORT id2" even if the index filter should discard test2
144150 RestEsqlTestCase .RequestObjectBuilder builder = existsFilter ("id1" ).query (
145- "FROM test* METADATA _index | SORT id2 | KEEP _index, id*"
151+ from ( " test*" ) + " METADATA _index | SORT id2 | KEEP _index, id*"
146152 );
147153 Map <String , Object > result = runEsql (builder );
148154 assertMap (
@@ -157,7 +163,7 @@ public void testFieldExistsFilter_With_ExplicitUseOfDiscardedIndexFields() throw
157163 @ SuppressWarnings ("unchecked" )
158164 var values = (List <List <Object >>) result .get ("values" );
159165 for (List <Object > row : values ) {
160- assertThat (row .get (0 ), equalTo ( " test1" ));
166+ assertThat (row .get (0 ), oneOf ( "test1" , "remote_cluster: test1" ));
161167 assertThat (row .get (1 ), instanceOf (Integer .class ));
162168 assertThat (row .get (2 ), nullValue ());
163169 }
@@ -172,59 +178,59 @@ public void testFieldNameTypo() throws IOException {
172178 // idx field name is explicitly used, though it doesn't exist in any of the indices. First test - without filter
173179 ResponseException e = expectThrows (
174180 ResponseException .class ,
175- () -> runEsql (requestObjectBuilder ().query ("FROM test* | WHERE idx == 123" ))
181+ () -> runEsql (requestObjectBuilder ().query (from ( " test*" ) + " | WHERE idx == 123" ))
176182 );
177183 assertEquals (400 , e .getResponse ().getStatusLine ().getStatusCode ());
178184 assertThat (e .getMessage (), containsString ("verification_exception" ));
179185 assertThat (e .getMessage (), containsString ("Found 1 problem" ));
180- assertThat (e .getMessage (), containsString ("line 1:20: Unknown column [idx]" ));
186+ assertThat (e .getMessage (), containsString ("Unknown column [idx]" ));
181187
182- e = expectThrows (ResponseException .class , () -> runEsql (requestObjectBuilder ().query ("FROM test1 | WHERE idx == 123" )));
188+ e = expectThrows (ResponseException .class , () -> runEsql (requestObjectBuilder ().query (from ( " test1" ) + " | WHERE idx == 123" )));
183189 assertEquals (400 , e .getResponse ().getStatusLine ().getStatusCode ());
184190 assertThat (e .getMessage (), containsString ("verification_exception" ));
185191 assertThat (e .getMessage (), containsString ("Found 1 problem" ));
186- assertThat (e .getMessage (), containsString ("line 1:20: Unknown column [idx]" ));
192+ assertThat (e .getMessage (), containsString ("Unknown column [idx]" ));
187193
188194 e = expectThrows (
189195 ResponseException .class ,
190- () -> runEsql (timestampFilter ("gte" , "2020-01-01" ).query ("FROM test* | WHERE idx == 123" ))
196+ () -> runEsql (timestampFilter ("gte" , "2020-01-01" ).query (from ( " test*" ) + " | WHERE idx == 123" ))
191197 );
192198 assertEquals (400 , e .getResponse ().getStatusLine ().getStatusCode ());
193199 assertThat (e .getMessage (), containsString ("Found 1 problem" ));
194- assertThat (e .getMessage (), containsString ("line 1:20: Unknown column [idx]" ));
200+ assertThat (e .getMessage (), containsString ("Unknown column [idx]" ));
195201
196202 e = expectThrows (
197203 ResponseException .class ,
198- () -> runEsql (timestampFilter ("gte" , "2020-01-01" ).query ("FROM test2 | WHERE idx == 123" ))
204+ () -> runEsql (timestampFilter ("gte" , "2020-01-01" ).query (from ( " test2" ) + " | WHERE idx == 123" ))
199205 );
200206 assertEquals (400 , e .getResponse ().getStatusLine ().getStatusCode ());
201207 assertThat (e .getMessage (), containsString ("Found 1 problem" ));
202- assertThat (e .getMessage (), containsString ("line 1:20: Unknown column [idx]" ));
208+ assertThat (e .getMessage (), containsString ("Unknown column [idx]" ));
203209 }
204210
205211 public void testIndicesDontExist () throws IOException {
206212 int docsTest1 = 0 ; // we are interested only in the created index, not necessarily that it has data
207213 indexTimestampData (docsTest1 , "test1" , "2024-11-26" , "id1" );
208214
209- ResponseException e = expectThrows (ResponseException .class , () -> runEsql (timestampFilter ("gte" , "2020-01-01" ).query ("FROM foo" )));
215+ ResponseException e = expectThrows (ResponseException .class , () -> runEsql (timestampFilter ("gte" , "2020-01-01" ).query (from ( " foo") )));
210216 assertEquals (400 , e .getResponse ().getStatusLine ().getStatusCode ());
211217 assertThat (e .getMessage (), containsString ("verification_exception" ));
212- assertThat (e .getMessage (), containsString ("Unknown index [foo]" ));
218+ assertThat (e .getMessage (), anyOf ( containsString ("Unknown index [foo]" ), containsString ( "Unknown index [remote_cluster:foo]" ) ));
213219
214- e = expectThrows (ResponseException .class , () -> runEsql (timestampFilter ("gte" , "2020-01-01" ).query ("FROM foo*" )));
220+ e = expectThrows (ResponseException .class , () -> runEsql (timestampFilter ("gte" , "2020-01-01" ).query (from ( " foo*") )));
215221 assertEquals (400 , e .getResponse ().getStatusLine ().getStatusCode ());
216222 assertThat (e .getMessage (), containsString ("verification_exception" ));
217- assertThat (e .getMessage (), containsString ("Unknown index [foo*]" ));
223+ assertThat (e .getMessage (), anyOf ( containsString ("Unknown index [foo*]" ), containsString ( "Unknown index [remote_cluster:foo*]" ) ));
218224
219- e = expectThrows (ResponseException .class , () -> runEsql (timestampFilter ("gte" , "2020-01-01" ).query ("FROM foo, test1" )));
225+ e = expectThrows (ResponseException .class , () -> runEsql (timestampFilter ("gte" , "2020-01-01" ).query (from ( " foo" , " test1") )));
220226 assertEquals (404 , e .getResponse ().getStatusLine ().getStatusCode ());
221227 assertThat (e .getMessage (), containsString ("index_not_found_exception" ));
222- assertThat (e .getMessage (), containsString ("no such index [foo]" ));
228+ assertThat (e .getMessage (), anyOf ( containsString ("no such index [foo]" ), containsString ( "no such index [remote_cluster:foo]" ) ));
223229
224230 if (EsqlCapabilities .Cap .JOIN_LOOKUP_V10 .isEnabled ()) {
225231 e = expectThrows (
226232 ResponseException .class ,
227- () -> runEsql (timestampFilter ("gte" , "2020-01-01" ).query ("FROM test1 | LOOKUP JOIN foo ON id1" ))
233+ () -> runEsql (timestampFilter ("gte" , "2020-01-01" ).query (from ( " test1" ) + " | LOOKUP JOIN foo ON id1" ))
228234 );
229235 assertEquals (400 , e .getResponse ().getStatusLine ().getStatusCode ());
230236 assertThat (e .getMessage (), containsString ("verification_exception" ));
@@ -251,6 +257,11 @@ public Map<String, Object> runEsql(RestEsqlTestCase.RequestObjectBuilder request
251257 }
252258
253259 protected void indexTimestampData (int docs , String indexName , String date , String differentiatorFieldName ) throws IOException {
260+ indexTimestampDataForClient (client (), docs , indexName , date , differentiatorFieldName );
261+ }
262+
263+ protected void indexTimestampDataForClient (RestClient client , int docs , String indexName , String date , String differentiatorFieldName )
264+ throws IOException {
254265 Request createIndex = new Request ("PUT" , indexName );
255266 createIndex .setJsonEntity ("""
256267 {
@@ -273,7 +284,7 @@ protected void indexTimestampData(int docs, String indexName, String date, Strin
273284 }
274285 }
275286 }""" .replace ("%differentiator_field_name%" , differentiatorFieldName ));
276- Response response = client () .performRequest (createIndex );
287+ Response response = client .performRequest (createIndex );
277288 assertThat (
278289 entityToMap (response .getEntity (), XContentType .JSON ),
279290 matchesMap ().entry ("shards_acknowledged" , true ).entry ("index" , indexName ).entry ("acknowledged" , true )
@@ -291,7 +302,7 @@ protected void indexTimestampData(int docs, String indexName, String date, Strin
291302 bulk .addParameter ("refresh" , "true" );
292303 bulk .addParameter ("filter_path" , "errors" );
293304 bulk .setJsonEntity (b .toString ());
294- response = client () .performRequest (bulk );
305+ response = client .performRequest (bulk );
295306 Assert .assertEquals ("{\" errors\" :false}" , EntityUtils .toString (response .getEntity (), StandardCharsets .UTF_8 ));
296307 }
297308 }
0 commit comments