6060import static org .elasticsearch .test .MapMatcher .assertMap ;
6161import static org .elasticsearch .test .MapMatcher .matchesMap ;
6262import static org .elasticsearch .xpack .esql .EsqlTestUtils .as ;
63- import static org .elasticsearch .xpack .esql .qa .rest .EsqlSpecTestCase .assertNotPartial ;
6463import static org .elasticsearch .xpack .esql .qa .rest .RestEsqlTestCase .Mode .ASYNC ;
6564import static org .elasticsearch .xpack .esql .qa .rest .RestEsqlTestCase .Mode .SYNC ;
6665import static org .elasticsearch .xpack .esql .type .EsqlDataTypeConverter .dateTimeToString ;
6766import static org .hamcrest .Matchers .any ;
67+ import static org .hamcrest .Matchers .anyOf ;
6868import static org .hamcrest .Matchers .containsString ;
6969import static org .hamcrest .Matchers .either ;
7070import static org .hamcrest .Matchers .emptyOrNullString ;
@@ -1256,10 +1256,20 @@ public static Map<String, Object> runEsql(
12561256 AssertWarnings assertWarnings ,
12571257 Mode mode ,
12581258 boolean checkPartialResults
1259+ ) throws IOException {
1260+ return runEsql (requestObject , assertWarnings , null , mode , checkPartialResults );
1261+ }
1262+
1263+ public static Map <String , Object > runEsql (
1264+ RequestObjectBuilder requestObject ,
1265+ AssertWarnings assertWarnings ,
1266+ @ Nullable ProfileLogger profileLogger ,
1267+ Mode mode ,
1268+ boolean checkPartialResults
12591269 ) throws IOException {
12601270 var results = mode == ASYNC
1261- ? runEsqlAsync (requestObject , randomBoolean (), assertWarnings )
1262- : runEsqlSync (requestObject , assertWarnings );
1271+ ? runEsqlAsync (requestObject , randomBoolean (), assertWarnings , profileLogger )
1272+ : runEsqlSync (requestObject , assertWarnings , profileLogger );
12631273 if (checkPartialResults ) {
12641274 assertNotPartial (results );
12651275 }
@@ -1271,53 +1281,70 @@ public static Map<String, Object> runEsql(RequestObjectBuilder requestObject, As
12711281 return runEsql (requestObject , assertWarnings , mode , true );
12721282 }
12731283
1274- /**
1275- * A response from an ESQL query.
1276- * @param response the HTTP response that contains the JSON response body
1277- * @param json the parsed JSON response body
1278- * @param asyncInitialResponse for async only. The response that was returned from the initial async request.
1279- * May be the same as {@code response} if the async request completed immediately.
1280- */
1281- public record EsqlResponse (Response response , Map <String , Object > json , Response asyncInitialResponse ) {
1282- public EsqlResponse (Response response , Map <String , Object > json ) {
1283- this (response , json , null );
1284- }
1284+ public static Map <String , Object > runEsql (RequestObjectBuilder requestObject , AssertWarnings assertWarnings ,
1285+ @ Nullable ProfileLogger profileLogger , Mode mode )
1286+ throws IOException {
1287+ return runEsql (requestObject , assertWarnings , profileLogger , mode , true );
12851288 }
12861289
12871290 public static Map <String , Object > runEsqlSync (RequestObjectBuilder requestObject , AssertWarnings assertWarnings ) throws IOException {
1288- EsqlResponse response = runEsqlSyncNoWarningsChecks (requestObject );
1289- assertWarnings (response .response , assertWarnings );
1290- return response .json ;
1291+ return runEsqlSync (requestObject , assertWarnings , null );
12911292 }
12921293
1293- public static EsqlResponse runEsqlSyncNoWarningsChecks (RequestObjectBuilder requestObject ) throws IOException {
1294+ public static Map <String , Object > runEsqlSync (
1295+ RequestObjectBuilder requestObject ,
1296+ AssertWarnings assertWarnings ,
1297+ @ Nullable ProfileLogger profileLogger
1298+ ) throws IOException {
1299+ Boolean profileEnabled = requestObject .profile ;
1300+ if (profileLogger != null ) {
1301+ requestObject .profile (true );
1302+ }
12941303 Request request = prepareRequestWithOptions (requestObject , SYNC );
1304+
12951305 Response response = performRequest (request );
1296- Map <String , Object > json = entityToMap (response .getEntity (), requestObject .contentType ());
1297- return new EsqlResponse (response , json );
1306+ HttpEntity entity = response .getEntity ();
1307+ Map <String , Object > json = entityToMap (entity , requestObject .contentType ());
1308+
1309+ if (profileLogger != null ) {
1310+ profileLogger .extractProfile (json , profileEnabled );
1311+ }
1312+
1313+ assertWarnings (response , assertWarnings );
1314+
1315+ return json ;
12981316 }
12991317
13001318 public static Map <String , Object > runEsqlAsync (RequestObjectBuilder requestObject , AssertWarnings assertWarnings ) throws IOException {
13011319 return runEsqlAsync (requestObject , randomBoolean (), assertWarnings );
13021320 }
13031321
1322+ public static Map <String , Object > runEsqlAsync (
1323+ RequestObjectBuilder requestObject ,
1324+ AssertWarnings assertWarnings ,
1325+ @ Nullable ProfileLogger profileLogger
1326+ ) throws IOException {
1327+ return runEsqlAsync (requestObject , randomBoolean (), assertWarnings , profileLogger );
1328+ }
1329+
13041330 public static Map <String , Object > runEsqlAsync (
13051331 RequestObjectBuilder requestObject ,
13061332 boolean keepOnCompletion ,
13071333 AssertWarnings assertWarnings
13081334 ) throws IOException {
1309- EsqlResponse response = runEsqlAsyncNoWarningsChecks (requestObject , keepOnCompletion );
1310-
1311- assertWarnings (response .response (), assertWarnings );
1312- if (response .asyncInitialResponse () != response .response ()) {
1313- assertWarnings (response .asyncInitialResponse (), assertWarnings );
1314- }
1315-
1316- return response .json ;
1335+ return runEsqlAsync (requestObject , keepOnCompletion , assertWarnings , null );
13171336 }
13181337
1319- public static EsqlResponse runEsqlAsyncNoWarningsChecks (RequestObjectBuilder requestObject , boolean keepOnCompletion )
1320- throws IOException {
1338+ public static Map <String , Object > runEsqlAsync (
1339+ RequestObjectBuilder requestObject ,
1340+ boolean keepOnCompletion ,
1341+ AssertWarnings assertWarnings ,
1342+ @ Nullable ProfileLogger profileLogger
1343+ ) throws IOException {
1344+ Boolean profileEnabled = requestObject .profile ;
1345+ if (profileLogger != null ) {
1346+ requestObject .profile (true );
1347+ }
13211348 addAsyncParameters (requestObject , keepOnCompletion );
13221349 Request request = prepareRequestWithOptions (requestObject , ASYNC );
13231350
@@ -1326,7 +1353,6 @@ public static EsqlResponse runEsqlAsyncNoWarningsChecks(RequestObjectBuilder req
13261353 }
13271354
13281355 Response response = performRequest (request );
1329- Response initialResponse = response ;
13301356 HttpEntity entity = response .getEntity ();
13311357
13321358 Object initialColumns = null ;
@@ -1346,15 +1372,23 @@ public static EsqlResponse runEsqlAsyncNoWarningsChecks(RequestObjectBuilder req
13461372 assertThat (response .getHeader ("X-Elasticsearch-Async-Id" ), nullValue ());
13471373 assertThat (response .getHeader ("X-Elasticsearch-Async-Is-Running" ), is ("?0" ));
13481374 }
1375+ if (profileLogger != null ) {
1376+ profileLogger .extractProfile (json , profileEnabled );
1377+ }
1378+ assertWarnings (response , assertWarnings );
13491379 json .remove ("is_running" ); // remove this to not mess up later map assertions
1350- return new EsqlResponse ( response , Collections .unmodifiableMap (json ), initialResponse );
1380+ return Collections .unmodifiableMap (json );
13511381 } else {
13521382 // async may not return results immediately, so may need an async get
13531383 assertThat (id , is (not (emptyOrNullString ())));
13541384 boolean isRunning = (boolean ) json .get ("is_running" );
13551385 if (isRunning == false ) {
13561386 // must have completed immediately so keep_on_completion must be true
13571387 assertThat (requestObject .keepOnCompletion (), is (true ));
1388+ if (profileLogger != null ) {
1389+ profileLogger .extractProfile (json , profileEnabled );
1390+ }
1391+ assertWarnings (response , assertWarnings );
13581392 // we already have the results, but let's remember them so that we can compare to async get
13591393 initialColumns = json .get ("columns" );
13601394 initialValues = json .get ("values" );
@@ -1391,8 +1425,12 @@ public static EsqlResponse runEsqlAsyncNoWarningsChecks(RequestObjectBuilder req
13911425 assertEquals (initialValues , result .get ("values" ));
13921426 }
13931427
1428+ if (profileLogger != null ) {
1429+ profileLogger .extractProfile (result , profileEnabled );
1430+ }
1431+ assertWarnings (response , assertWarnings );
13941432 assertDeletable (id );
1395- return new EsqlResponse ( response , removeAsyncProperties (result ), initialResponse );
1433+ return removeAsyncProperties (result );
13961434 }
13971435
13981436 private static Object removeOriginalTypesAndSuggestedCast (Object response ) {
@@ -1624,8 +1662,8 @@ static String runEsqlAsTextWithFormat(RequestObjectBuilder builder, String forma
16241662
16251663 Response response = performRequest (request );
16261664 assertWarnings (response , new AssertWarnings .NoWarnings ());
1627-
16281665 HttpEntity entity = response .getEntity ();
1666+
16291667 // get the content, it could be empty because the request might have not completed
16301668 String initialValue = Streams .copyToString (new InputStreamReader (entity .getContent (), StandardCharsets .UTF_8 ));
16311669 String id = response .getHeader ("X-Elasticsearch-Async-Id" );
@@ -1727,7 +1765,13 @@ protected static Response performRequest(Request request) throws IOException {
17271765 return response ;
17281766 }
17291767
1730- public static void assertWarnings (Response response , AssertWarnings assertWarnings ) {
1768+ static void assertNotPartial (Map <String , Object > answer ) {
1769+ var clusters = answer .get ("_clusters" );
1770+ var reason = "unexpected partial results" + (clusters != null ? ": _clusters=" + clusters : "" );
1771+ assertThat (reason , answer .get ("is_partial" ), anyOf (nullValue (), is (false )));
1772+ }
1773+
1774+ private static void assertWarnings (Response response , AssertWarnings assertWarnings ) {
17311775 List <String > warnings = new ArrayList <>(response .getWarnings ());
17321776 warnings .removeAll (mutedWarnings ());
17331777 if (shouldLog ()) {
0 commit comments