From 79ebb5ef0a2c758a29b709e2565eb53105d7bedb Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Fri, 25 Jul 2025 14:23:36 -0400 Subject: [PATCH 1/9] ESQL: Check speed up spec tests Speeds up the spec tests by: * Randomize `async`/`sync` instead of both * Check the took time rarely * Don't check if index exists every time * Reduce transfer when checking breaker * Cache capabilities checks The first one is most of the speed up but the rest save another couple of minutes. Time drops from 13m45s to 6m or so on my laptop. --- .../esql/qa/mixed/MixedClusterEsqlSpecIT.java | 11 +-- .../xpack/esql/ccq/MultiClusterSpecIT.java | 22 +---- .../xpack/esql/qa/multi_node/EsqlSpecIT.java | 14 +--- .../xpack/esql/qa/single_node/EsqlSpecIT.java | 13 +-- .../esql/qa/single_node/GenerativeForkIT.java | 6 +- .../xpack/esql/qa/rest/EsqlSpecTestCase.java | 80 +++++-------------- .../xpack/esql/qa/rest/RestEsqlTestCase.java | 22 ++++- .../esql/qa/rest/RestRerankTestCase.java | 2 +- .../esql/qa/rest/RestSampleTestCase.java | 2 +- .../generative/GenerativeForkRestTest.java | 7 +- .../rest/generative/GenerativeRestTest.java | 4 +- .../xpack/esql/CsvTestsDataLoader.java | 20 +++-- 12 files changed, 70 insertions(+), 133 deletions(-) diff --git a/x-pack/plugin/esql/qa/server/mixed-cluster/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/mixed/MixedClusterEsqlSpecIT.java b/x-pack/plugin/esql/qa/server/mixed-cluster/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/mixed/MixedClusterEsqlSpecIT.java index 5578eff5cc67a..fc08861ee3cae 100644 --- a/x-pack/plugin/esql/qa/server/mixed-cluster/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/mixed/MixedClusterEsqlSpecIT.java +++ b/x-pack/plugin/esql/qa/server/mixed-cluster/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/mixed/MixedClusterEsqlSpecIT.java @@ -12,7 +12,6 @@ import org.elasticsearch.test.rest.TestFeatureService; import org.elasticsearch.xpack.esql.CsvSpecReader.CsvTestCase; import org.elasticsearch.xpack.esql.qa.rest.EsqlSpecTestCase; -import org.elasticsearch.xpack.esql.qa.rest.RestEsqlTestCase.Mode; import org.junit.AfterClass; import org.junit.Before; import org.junit.ClassRule; @@ -43,11 +42,6 @@ public void extractOldClusterFeatures() { } } - protected static boolean oldClusterHasFeature(String featureId) { - assert oldClusterTestFeatureService != null; - return oldClusterTestFeatureService.clusterHasFeature(featureId); - } - @AfterClass public static void cleanUp() { oldClusterTestFeatureService = null; @@ -59,10 +53,9 @@ public MixedClusterEsqlSpecIT( String testName, Integer lineNumber, CsvTestCase testCase, - String instructions, - Mode mode + String instructions ) { - super(fileName, groupName, testName, lineNumber, testCase, instructions, mode); + super(fileName, groupName, testName, lineNumber, testCase, instructions); } @Override diff --git a/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClusterSpecIT.java b/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClusterSpecIT.java index 38b3794329bf4..a98cf66cba1a7 100644 --- a/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClusterSpecIT.java +++ b/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClusterSpecIT.java @@ -27,7 +27,6 @@ import org.elasticsearch.xpack.esql.CsvTestsDataLoader; import org.elasticsearch.xpack.esql.SpecReader; import org.elasticsearch.xpack.esql.qa.rest.EsqlSpecTestCase; -import org.elasticsearch.xpack.esql.qa.rest.RestEsqlTestCase.Mode; import org.junit.AfterClass; import org.junit.ClassRule; import org.junit.rules.RuleChain; @@ -36,7 +35,6 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.net.URL; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Locale; @@ -59,7 +57,6 @@ import static org.elasticsearch.xpack.esql.action.EsqlCapabilities.Cap.JOIN_PLANNING_V1; import static org.elasticsearch.xpack.esql.action.EsqlCapabilities.Cap.METADATA_FIELDS_REMOTE_TEST; import static org.elasticsearch.xpack.esql.action.EsqlCapabilities.Cap.UNMAPPED_FIELDS; -import static org.elasticsearch.xpack.esql.qa.rest.RestEsqlTestCase.Mode.SYNC; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; @@ -87,19 +84,7 @@ public class MultiClusterSpecIT extends EsqlSpecTestCase { public static List readScriptSpec() throws Exception { List urls = classpathResources("/*.csv-spec"); assertTrue("Not enough specs found " + urls, urls.size() > 0); - List specs = SpecReader.readScriptSpec(urls, specParser()); - - int len = specs.get(0).length; - List testcases = new ArrayList<>(); - for (var spec : specs) { - for (Mode mode : List.of(SYNC)) { // No async, for now - Object[] obj = new Object[len + 1]; - System.arraycopy(spec, 0, obj, 0, len); - obj[len] = mode; - testcases.add(obj); - } - } - return testcases; + return SpecReader.readScriptSpec(urls, specParser()); } public MultiClusterSpecIT( @@ -108,10 +93,9 @@ public MultiClusterSpecIT( String testName, Integer lineNumber, CsvTestCase testCase, - String instructions, - Mode mode + String instructions ) { - super(fileName, groupName, testName, lineNumber, convertToRemoteIndices(testCase), instructions, mode); + super(fileName, groupName, testName, lineNumber, convertToRemoteIndices(testCase), instructions); } // TODO: think how to handle this better diff --git a/x-pack/plugin/esql/qa/server/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/multi_node/EsqlSpecIT.java b/x-pack/plugin/esql/qa/server/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/multi_node/EsqlSpecIT.java index ffdf0eb336a1a..7738f172dc15f 100644 --- a/x-pack/plugin/esql/qa/server/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/multi_node/EsqlSpecIT.java +++ b/x-pack/plugin/esql/qa/server/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/multi_node/EsqlSpecIT.java @@ -8,9 +8,9 @@ package org.elasticsearch.xpack.esql.qa.multi_node; import org.elasticsearch.test.cluster.ElasticsearchCluster; +import org.elasticsearch.test.junit.annotations.TestLogging; import org.elasticsearch.xpack.esql.CsvSpecReader.CsvTestCase; import org.elasticsearch.xpack.esql.qa.rest.EsqlSpecTestCase; -import org.elasticsearch.xpack.esql.qa.rest.RestEsqlTestCase.Mode; import org.junit.ClassRule; import java.io.IOException; @@ -24,16 +24,8 @@ protected String getTestRestCluster() { return cluster.getHttpAddresses(); } - public EsqlSpecIT( - String fileName, - String groupName, - String testName, - Integer lineNumber, - CsvTestCase testCase, - String instructions, - Mode mode - ) { - super(fileName, groupName, testName, lineNumber, testCase, instructions, mode); + public EsqlSpecIT(String fileName, String groupName, String testName, Integer lineNumber, CsvTestCase testCase, String instructions) { + super(fileName, groupName, testName, lineNumber, testCase, instructions); } @Override diff --git a/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/EsqlSpecIT.java b/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/EsqlSpecIT.java index 4c4ce020eb773..f4ec3f099e068 100644 --- a/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/EsqlSpecIT.java +++ b/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/EsqlSpecIT.java @@ -19,7 +19,6 @@ import org.elasticsearch.xpack.esql.planner.PhysicalSettings; import org.elasticsearch.xpack.esql.plugin.ComputeService; import org.elasticsearch.xpack.esql.qa.rest.EsqlSpecTestCase; -import org.elasticsearch.xpack.esql.qa.rest.RestEsqlTestCase.Mode; import org.junit.Before; import org.junit.ClassRule; @@ -37,16 +36,8 @@ protected String getTestRestCluster() { return cluster.getHttpAddresses(); } - public EsqlSpecIT( - String fileName, - String groupName, - String testName, - Integer lineNumber, - CsvTestCase testCase, - String instructions, - Mode mode - ) { - super(fileName, groupName, testName, lineNumber, testCase, instructions, mode); + public EsqlSpecIT(String fileName, String groupName, String testName, Integer lineNumber, CsvTestCase testCase, String instructions) { + super(fileName, groupName, testName, lineNumber, testCase, instructions); } @Override diff --git a/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/GenerativeForkIT.java b/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/GenerativeForkIT.java index cb1f4383600d8..a2ddb87cf0f44 100644 --- a/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/GenerativeForkIT.java +++ b/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/GenerativeForkIT.java @@ -12,7 +12,6 @@ import org.elasticsearch.test.TestClustersThreadFilter; import org.elasticsearch.test.cluster.ElasticsearchCluster; import org.elasticsearch.xpack.esql.CsvSpecReader; -import org.elasticsearch.xpack.esql.qa.rest.RestEsqlTestCase.Mode; import org.elasticsearch.xpack.esql.qa.rest.generative.GenerativeForkRestTest; import org.junit.ClassRule; @@ -32,10 +31,9 @@ public GenerativeForkIT( String testName, Integer lineNumber, CsvSpecReader.CsvTestCase testCase, - String instructions, - Mode mode + String instructions ) { - super(fileName, groupName, testName, lineNumber, testCase, instructions, mode); + super(fileName, groupName, testName, lineNumber, testCase, instructions); } @Override 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 fa4f5a4b3909f..241be44f9abf0 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 @@ -68,7 +68,6 @@ import static org.elasticsearch.xpack.esql.CsvTestUtils.ExpectedResults; import static org.elasticsearch.xpack.esql.CsvTestUtils.isEnabled; import static org.elasticsearch.xpack.esql.CsvTestUtils.loadCsvSpecValues; -import static org.elasticsearch.xpack.esql.CsvTestsDataLoader.availableDatasetsForEs; import static org.elasticsearch.xpack.esql.CsvTestsDataLoader.createInferenceEndpoints; import static org.elasticsearch.xpack.esql.CsvTestsDataLoader.deleteInferenceEndpoints; import static org.elasticsearch.xpack.esql.CsvTestsDataLoader.loadDataSetIntoEs; @@ -79,6 +78,7 @@ import static org.elasticsearch.xpack.esql.action.EsqlCapabilities.Cap.SEMANTIC_TEXT_FIELD_CAPS; import static org.elasticsearch.xpack.esql.action.EsqlCapabilities.Cap.SOURCE_FIELD_MAPPING; import static org.elasticsearch.xpack.esql.qa.rest.RestEsqlTestCase.assertNotPartial; +import static org.elasticsearch.xpack.esql.qa.rest.RestEsqlTestCase.hasCapabilities; // This test can run very long in serverless configurations @TimeoutSuite(millis = 30 * TimeUnits.MINUTE) @@ -101,19 +101,7 @@ public abstract class EsqlSpecTestCase extends ESRestTestCase { public static List readScriptSpec() throws Exception { List urls = classpathResources("/*.csv-spec"); assertTrue("Not enough specs found " + urls, urls.size() > 0); - List specs = SpecReader.readScriptSpec(urls, specParser()); - - int len = specs.get(0).length; - List testcases = new ArrayList<>(); - for (var spec : specs) { - for (Mode mode : Mode.values()) { - Object[] obj = new Object[len + 1]; - System.arraycopy(spec, 0, obj, 0, len); - obj[len] = mode; - testcases.add(obj); - } - } - return testcases; + return SpecReader.readScriptSpec(urls, specParser()); } protected EsqlSpecTestCase( @@ -122,8 +110,7 @@ protected EsqlSpecTestCase( String testName, Integer lineNumber, CsvTestCase testCase, - String instructions, - Mode mode + String instructions ) { this.fileName = fileName; this.groupName = groupName; @@ -131,25 +118,30 @@ protected EsqlSpecTestCase( this.lineNumber = lineNumber; this.testCase = testCase; this.instructions = instructions; - this.mode = mode; + this.mode = randomFrom(Mode.values()); } + private static boolean dataLoaded = false; + @Before public void setup() throws IOException { - if (supportsInferenceTestService()) { - createInferenceEndpoints(adminClient()); - } - boolean supportsLookup = supportsIndexModeLookup(); boolean supportsSourceMapping = supportsSourceFieldMapping(); - if (indexExists(availableDatasetsForEs(client(), supportsLookup, supportsSourceMapping).iterator().next().indexName()) == false) { - loadDataSetIntoEs(client(), supportsLookup, supportsSourceMapping); + boolean supportsInferenceTestService = supportsInferenceTestService(); + if (dataLoaded == false) { + if (supportsInferenceTestService) { + createInferenceEndpoints(adminClient()); + } + + loadDataSetIntoEs(client(), supportsLookup, supportsSourceMapping, supportsInferenceTestService); + dataLoaded = true; } } @AfterClass public static void wipeTestData() throws IOException { try { + dataLoaded = false; adminClient().performRequest(new Request("DELETE", "/*")); } catch (ResponseException e) { // 404 here just means we had no indexes @@ -159,7 +151,6 @@ public static void wipeTestData() throws IOException { } deleteInferenceEndpoints(adminClient()); - } public boolean logResults() { @@ -211,38 +202,6 @@ protected static void checkCapabilities(RestClient client, TestFeatureService te } } - protected static boolean hasCapabilities(List requiredCapabilities) throws IOException { - return hasCapabilities(adminClient(), requiredCapabilities); - } - - public static boolean hasCapabilities(RestClient client, List requiredCapabilities) throws IOException { - if (requiredCapabilities.isEmpty()) { - return true; - } - try { - if (clusterHasCapability(client, "POST", "/_query", List.of(), requiredCapabilities).orElse(false)) { - return true; - } - LOGGER.info("capabilities API returned false, we might be in a mixed version cluster so falling back to cluster features"); - } catch (ResponseException e) { - if (e.getResponse().getStatusLine().getStatusCode() / 100 == 4) { - /* - * The node we're testing against is too old for the capabilities - * API which means it has to be pretty old. Very old capabilities - * are ALSO present in the features API, so we can check them instead. - * - * It's kind of weird that we check for *any* 400, but that's required - * because old versions of Elasticsearch return 400, not the expected - * 404. - */ - LOGGER.info("capabilities API failed, falling back to cluster features"); - } else { - throw e; - } - } - return false; - } - protected boolean supportsInferenceTestService() { return true; } @@ -271,7 +230,9 @@ protected final void doTest(String query) throws Throwable { builder.tables(tables()); } - Map prevTooks = supportsTook() ? tooks() : null; + boolean checkTook = supportsTook() && rarely(); + + Map prevTooks = checkTook ? tooks() : null; Map answer = RestEsqlTestCase.runEsql( builder.query(query), testCase.assertWarnings(deduplicateExactWarnings()), @@ -296,7 +257,7 @@ protected final void doTest(String query) throws Throwable { assertResults(expectedColumnsWithValues, actualColumns, actualValues, testCase.ignoreOrder, logger); - if (supportsTook()) { + if (checkTook) { LOGGER.info("checking took incremented from {}", prevTooks); long took = ((Number) answer.get("took")).longValue(); int prevTookHisto = ((Number) prevTooks.remove(tookKey(took))).intValue(); @@ -413,7 +374,6 @@ protected boolean preserveClusterUponCompletion() { return true; } - @Before @After public void assertRequestBreakerEmptyAfterTests() throws Exception { assertRequestBreakerEmpty(); @@ -421,7 +381,7 @@ public void assertRequestBreakerEmptyAfterTests() throws Exception { public static void assertRequestBreakerEmpty() throws Exception { assertBusy(() -> { - HttpEntity entity = adminClient().performRequest(new Request("GET", "/_nodes/stats")).getEntity(); + HttpEntity entity = adminClient().performRequest(new Request("GET", "/_nodes/stats?metric=breaker")).getEntity(); Map stats = XContentHelper.convertToMap(XContentType.JSON.xContent(), entity.getContent(), false); Map nodes = (Map) stats.get("nodes"); 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 d191cfcafa80f..8208138a5e2a7 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 @@ -16,6 +16,7 @@ import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.Response; import org.elasticsearch.client.ResponseException; +import org.elasticsearch.client.RestClient; import org.elasticsearch.client.WarningsHandler; import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.io.Streams; @@ -52,6 +53,7 @@ import java.util.Locale; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.IntFunction; import static java.util.Collections.emptySet; @@ -1334,8 +1336,8 @@ public static Map runEsqlAsync( checkKeepOnCompletion(requestObject, json, keepOnCompletion); String id = (String) json.get("id"); - var supportsAsyncHeaders = clusterHasCapability("POST", "/_query", List.of(), List.of("async_query_status_headers")).orElse(false); - var supportsSuggestedCast = clusterHasCapability("POST", "/_query", List.of(), List.of("suggested_cast")).orElse(false); + var supportsAsyncHeaders = hasCapabilities(client(), List.of("async_query_status_headers")); + var supportsSuggestedCast = hasCapabilities(client(), List.of("suggested_cast")); if (id == null) { // no id returned from an async call, must have completed immediately and without keep_on_completion @@ -1409,13 +1411,27 @@ public static Map runEsqlAsync( private static void prepareProfileLogger(RequestObjectBuilder requestObject, @Nullable ProfileLogger profileLogger) throws IOException { if (profileLogger != null) { profileLogger.clearProfile(); - var isProfileSafe = clusterHasCapability("POST", "/_query", List.of(), List.of("fixed_profile_serialization")).orElse(false); + var isProfileSafe = hasCapabilities(client(), List.of("fixed_profile_serialization")); if (isProfileSafe) { requestObject.profile(true); } } } + private static final Map, Boolean> capabilities = new ConcurrentHashMap<>(); + + public static boolean hasCapabilities(RestClient client, List requiredCapabilities) throws IOException { + if (requiredCapabilities.isEmpty()) { + return true; + } + Boolean cap = capabilities.get(requiredCapabilities); + if (cap == null) { + cap = clusterHasCapability(client, "POST", "/_query", List.of(), requiredCapabilities).orElse(false); + capabilities.put(requiredCapabilities, cap); + } + return cap; + } + private static Object removeOriginalTypesAndSuggestedCast(Object response) { if (response instanceof ArrayList columns) { var newColumns = new ArrayList<>(); diff --git a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RestRerankTestCase.java b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RestRerankTestCase.java index 17d88f1e21a13..99e2b22b91fc6 100644 --- a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RestRerankTestCase.java +++ b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RestRerankTestCase.java @@ -33,7 +33,7 @@ public class RestRerankTestCase extends ESRestTestCase { public void skipWhenRerankDisabled() throws IOException { assumeTrue( "Requires RERANK capability", - EsqlSpecTestCase.hasCapabilities(adminClient(), List.of(EsqlCapabilities.Cap.RERANK.capabilityName())) + RestEsqlTestCase.hasCapabilities(adminClient(), List.of(EsqlCapabilities.Cap.RERANK.capabilityName())) ); } diff --git a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RestSampleTestCase.java b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RestSampleTestCase.java index 17b60ed94be20..4e7f207269721 100644 --- a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RestSampleTestCase.java +++ b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RestSampleTestCase.java @@ -38,7 +38,7 @@ public class RestSampleTestCase extends ESRestTestCase { public void skipWhenSampleDisabled() throws IOException { assumeTrue( "Requires SAMPLE capability", - EsqlSpecTestCase.hasCapabilities(adminClient(), List.of(EsqlCapabilities.Cap.SAMPLE_V3.capabilityName())) + RestEsqlTestCase.hasCapabilities(adminClient(), List.of(EsqlCapabilities.Cap.SAMPLE_V3.capabilityName())) ); } diff --git a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/generative/GenerativeForkRestTest.java b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/generative/GenerativeForkRestTest.java index c3ba8c9036eea..04173aa79621d 100644 --- a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/generative/GenerativeForkRestTest.java +++ b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/generative/GenerativeForkRestTest.java @@ -9,12 +9,12 @@ import org.elasticsearch.xpack.esql.CsvSpecReader; import org.elasticsearch.xpack.esql.qa.rest.EsqlSpecTestCase; -import org.elasticsearch.xpack.esql.qa.rest.RestEsqlTestCase.Mode; import java.io.IOException; import java.util.List; import static org.elasticsearch.xpack.esql.action.EsqlCapabilities.Cap.*; +import static org.elasticsearch.xpack.esql.qa.rest.RestEsqlTestCase.hasCapabilities; /** * Tests for FORK. We generate tests for FORK from existing CSV tests. @@ -30,10 +30,9 @@ public GenerativeForkRestTest( String testName, Integer lineNumber, CsvSpecReader.CsvTestCase testCase, - String instructions, - Mode mode + String instructions ) { - super(fileName, groupName, testName, lineNumber, testCase, instructions, mode); + super(fileName, groupName, testName, lineNumber, testCase, instructions); } @Override diff --git a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/generative/GenerativeRestTest.java b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/generative/GenerativeRestTest.java index 9677a7e06948f..053f026cd0eda 100644 --- a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/generative/GenerativeRestTest.java +++ b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/generative/GenerativeRestTest.java @@ -70,7 +70,7 @@ public abstract class GenerativeRestTest extends ESRestTestCase { @Before public void setup() throws IOException { if (indexExists(CSV_DATASET_MAP.keySet().iterator().next()) == false) { - loadDataSetIntoEs(client(), true, supportsSourceFieldMapping()); + loadDataSetIntoEs(client(), true, supportsSourceFieldMapping(), false); } } @@ -209,7 +209,7 @@ private static List outputSchema(Map } private List availableIndices() throws IOException { - return availableDatasetsForEs(client(), true, supportsSourceFieldMapping()).stream() + return availableDatasetsForEs(true, supportsSourceFieldMapping(), false).stream() .filter(x -> x.requiresInferenceEndpoint() == false) .map(x -> x.indexName()) .toList(); diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvTestsDataLoader.java b/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvTestsDataLoader.java index 53a223c1453e1..b04525479e7a8 100644 --- a/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvTestsDataLoader.java +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvTestsDataLoader.java @@ -302,7 +302,7 @@ public static void main(String[] args) throws IOException { } try (RestClient client = builder.build()) { - loadDataSetIntoEs(client, true, true, (restClient, indexName, indexMapping, indexSettings) -> { + loadDataSetIntoEs(client, true, true, false, (restClient, indexName, indexMapping, indexSettings) -> { // don't use ESRestTestCase methods here or, if you do, test running the main method before making the change StringBuilder jsonBody = new StringBuilder("{"); if (indexSettings != null && indexSettings.isEmpty() == false) { @@ -322,12 +322,10 @@ public static void main(String[] args) throws IOException { } public static Set availableDatasetsForEs( - RestClient client, boolean supportsIndexModeLookup, - boolean supportsSourceFieldMapping + boolean supportsSourceFieldMapping, + boolean inferenceEnabled ) throws IOException { - boolean inferenceEnabled = clusterHasSparseEmbeddingInferenceEndpoint(client); - Set testDataSets = new HashSet<>(); for (TestDataset dataset : CSV_DATASET_MAP.values()) { @@ -357,12 +355,17 @@ private static boolean isSourceMappingDataset(TestDataset dataset) throws IOExce return mappingNode.get("_source") != null; } - public static void loadDataSetIntoEs(RestClient client, boolean supportsIndexModeLookup, boolean supportsSourceFieldMapping) - throws IOException { + public static void loadDataSetIntoEs( + RestClient client, + boolean supportsIndexModeLookup, + boolean supportsSourceFieldMapping, + boolean inferenceEnabled + ) throws IOException { loadDataSetIntoEs( client, supportsIndexModeLookup, supportsSourceFieldMapping, + inferenceEnabled, (restClient, indexName, indexMapping, indexSettings) -> { ESRestTestCase.createIndex(restClient, indexName, indexSettings, indexMapping, null); } @@ -373,12 +376,13 @@ private static void loadDataSetIntoEs( RestClient client, boolean supportsIndexModeLookup, boolean supportsSourceFieldMapping, + boolean inferenceEnabled, IndexCreator indexCreator ) throws IOException { Logger logger = LogManager.getLogger(CsvTestsDataLoader.class); Set loadedDatasets = new HashSet<>(); - for (var dataset : availableDatasetsForEs(client, supportsIndexModeLookup, supportsSourceFieldMapping)) { + for (var dataset : availableDatasetsForEs(supportsIndexModeLookup, supportsSourceFieldMapping, inferenceEnabled)) { load(client, dataset, logger, indexCreator); loadedDatasets.add(dataset.indexName); } From 75e4f98a41f8545f5e082b7190cab4b6e4b936fb Mon Sep 17 00:00:00 2001 From: elasticsearchmachine Date: Fri, 25 Jul 2025 22:51:51 +0000 Subject: [PATCH 2/9] [CI] Auto commit changes from spotless --- .../org/elasticsearch/xpack/esql/qa/multi_node/EsqlSpecIT.java | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/plugin/esql/qa/server/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/multi_node/EsqlSpecIT.java b/x-pack/plugin/esql/qa/server/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/multi_node/EsqlSpecIT.java index 7738f172dc15f..e36bd451c8298 100644 --- a/x-pack/plugin/esql/qa/server/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/multi_node/EsqlSpecIT.java +++ b/x-pack/plugin/esql/qa/server/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/multi_node/EsqlSpecIT.java @@ -8,7 +8,6 @@ package org.elasticsearch.xpack.esql.qa.multi_node; import org.elasticsearch.test.cluster.ElasticsearchCluster; -import org.elasticsearch.test.junit.annotations.TestLogging; import org.elasticsearch.xpack.esql.CsvSpecReader.CsvTestCase; import org.elasticsearch.xpack.esql.qa.rest.EsqlSpecTestCase; import org.junit.ClassRule; From c09517b2f9eebb38dc85772aa2b67c6aeb4d629f Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Sat, 26 Jul 2025 20:24:55 -0400 Subject: [PATCH 3/9] Fix --- .../elasticsearch/xpack/esql/ccq/MultiClusterSpecIT.java | 8 ++++++-- .../xpack/esql/qa/rest/RestEsqlTestCase.java | 3 +++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClusterSpecIT.java b/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClusterSpecIT.java index a98cf66cba1a7..32810e9408dd4 100644 --- a/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClusterSpecIT.java +++ b/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClusterSpecIT.java @@ -57,6 +57,7 @@ import static org.elasticsearch.xpack.esql.action.EsqlCapabilities.Cap.JOIN_PLANNING_V1; import static org.elasticsearch.xpack.esql.action.EsqlCapabilities.Cap.METADATA_FIELDS_REMOTE_TEST; import static org.elasticsearch.xpack.esql.action.EsqlCapabilities.Cap.UNMAPPED_FIELDS; +import static org.elasticsearch.xpack.esql.qa.rest.RestEsqlTestCase.hasCapabilities; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; @@ -138,7 +139,10 @@ protected void shouldSkipTest(String testName) throws IOException { assumeFalse("INLINESTATS not yet supported in CCS", testCase.requiredCapabilities.contains(JOIN_PLANNING_V1.capabilityName())); assumeFalse("INLINESTATS not yet supported in CCS", testCase.requiredCapabilities.contains(INLINESTATS_V8.capabilityName())); if (testCase.requiredCapabilities.contains(JOIN_LOOKUP_V12.capabilityName())) { - assumeTrue("LOOKUP JOIN not yet supported in CCS", hasCapabilities(List.of(ENABLE_LOOKUP_JOIN_ON_REMOTE.capabilityName()))); + assumeTrue( + "LOOKUP JOIN not yet supported in CCS", + hasCapabilities(client(), List.of(ENABLE_LOOKUP_JOIN_ON_REMOTE.capabilityName())) + ); } // Unmapped fields require a coorect capability response from every cluster, which isn't currently implemented. assumeFalse("UNMAPPED FIELDS not yet supported in CCS", testCase.requiredCapabilities.contains(UNMAPPED_FIELDS.capabilityName())); @@ -387,7 +391,7 @@ protected boolean supportsInferenceTestService() { @Override protected boolean supportsIndexModeLookup() throws IOException { - return hasCapabilities(List.of(JOIN_LOOKUP_V12.capabilityName())); + return hasCapabilities(client(), List.of(JOIN_LOOKUP_V12.capabilityName())); } @Override 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 8208138a5e2a7..0b7278b2a8108 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 @@ -1418,6 +1418,9 @@ private static void prepareProfileLogger(RequestObjectBuilder requestObject, @Nu } } + /** + * Cache of capabilities. + */ private static final Map, Boolean> capabilities = new ConcurrentHashMap<>(); public static boolean hasCapabilities(RestClient client, List requiredCapabilities) throws IOException { From 2d6d9cc1b33d1251e2d9ad2611e670820838088f Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Mon, 28 Jul 2025 10:04:23 -0400 Subject: [PATCH 4/9] Update x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RestEsqlTestCase.java Co-authored-by: Ievgen Degtiarenko --- .../org/elasticsearch/xpack/esql/qa/rest/RestEsqlTestCase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 0b7278b2a8108..e41e0edf20eac 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 @@ -1421,7 +1421,7 @@ private static void prepareProfileLogger(RequestObjectBuilder requestObject, @Nu /** * Cache of capabilities. */ - private static final Map, Boolean> capabilities = new ConcurrentHashMap<>(); + private static final ConcurrentMap, Boolean> capabilities = new ConcurrentHashMap<>(); public static boolean hasCapabilities(RestClient client, List requiredCapabilities) throws IOException { if (requiredCapabilities.isEmpty()) { From dbdc721f86431a3cef6580b3e7facd305aef260f Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Mon, 28 Jul 2025 10:49:03 -0400 Subject: [PATCH 5/9] Fixup --- .../xpack/esql/EsqlSecurityIT.java | 12 ++++++------ .../esql/qa/mixed/MixedClusterEsqlSpecIT.java | 7 ++++--- .../xpack/esql/qa/rest/EsqlSpecTestCase.java | 8 ++++++-- .../xpack/esql/qa/rest/RestEsqlTestCase.java | 17 ++++++++++------- 4 files changed, 26 insertions(+), 18 deletions(-) diff --git a/x-pack/plugin/esql/qa/security/src/javaRestTest/java/org/elasticsearch/xpack/esql/EsqlSecurityIT.java b/x-pack/plugin/esql/qa/security/src/javaRestTest/java/org/elasticsearch/xpack/esql/EsqlSecurityIT.java index 6494a29e83075..73cd7b77968fe 100644 --- a/x-pack/plugin/esql/qa/security/src/javaRestTest/java/org/elasticsearch/xpack/esql/EsqlSecurityIT.java +++ b/x-pack/plugin/esql/qa/security/src/javaRestTest/java/org/elasticsearch/xpack/esql/EsqlSecurityIT.java @@ -27,7 +27,6 @@ import org.elasticsearch.xcontent.XContentBuilder; import org.elasticsearch.xcontent.json.JsonXContent; import org.elasticsearch.xpack.esql.action.EsqlCapabilities; -import org.elasticsearch.xpack.esql.qa.rest.EsqlSpecTestCase; import org.junit.Before; import org.junit.ClassRule; @@ -40,6 +39,7 @@ import static org.elasticsearch.test.ListMatcher.matchesList; import static org.elasticsearch.test.MapMatcher.assertMap; import static org.elasticsearch.test.MapMatcher.matchesMap; +import static org.elasticsearch.xpack.esql.qa.rest.RestEsqlTestCase.hasCapabilities; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; @@ -594,7 +594,7 @@ record Listen(long timestamp, String songId, double duration) { public void testLookupJoinIndexAllowed() throws Exception { assumeTrue( "Requires LOOKUP JOIN capability", - EsqlSpecTestCase.hasCapabilities(adminClient(), List.of(EsqlCapabilities.Cap.JOIN_LOOKUP_V12.capabilityName())) + hasCapabilities(adminClient(), List.of(EsqlCapabilities.Cap.JOIN_LOOKUP_V12.capabilityName())) ); Response resp = runESQLCommand( @@ -685,7 +685,7 @@ public void testLookupJoinIndexAllowed() throws Exception { public void testLookupJoinDocLevelSecurity() throws Exception { assumeTrue( "Requires LOOKUP JOIN capability", - EsqlSpecTestCase.hasCapabilities(adminClient(), List.of(EsqlCapabilities.Cap.JOIN_LOOKUP_V12.capabilityName())) + hasCapabilities(adminClient(), List.of(EsqlCapabilities.Cap.JOIN_LOOKUP_V12.capabilityName())) ); Response resp = runESQLCommand("dls_user", "ROW x = 40.0 | EVAL value = x | LOOKUP JOIN lookup-user2 ON value | KEEP x, org"); @@ -734,7 +734,7 @@ public void testLookupJoinDocLevelSecurity() throws Exception { public void testLookupJoinFieldLevelSecurity() throws Exception { assumeTrue( "Requires LOOKUP JOIN capability", - EsqlSpecTestCase.hasCapabilities(adminClient(), List.of(EsqlCapabilities.Cap.JOIN_LOOKUP_V12.capabilityName())) + hasCapabilities(adminClient(), List.of(EsqlCapabilities.Cap.JOIN_LOOKUP_V12.capabilityName())) ); Response resp = runESQLCommand("fls_user2", "ROW x = 40.0 | EVAL value = x | LOOKUP JOIN lookup-user2 ON value"); @@ -792,7 +792,7 @@ public void testLookupJoinFieldLevelSecurity() throws Exception { public void testLookupJoinFieldLevelSecurityOnAlias() throws Exception { assumeTrue( "Requires LOOKUP JOIN capability", - EsqlSpecTestCase.hasCapabilities(adminClient(), List.of(EsqlCapabilities.Cap.JOIN_LOOKUP_V12.capabilityName())) + hasCapabilities(adminClient(), List.of(EsqlCapabilities.Cap.JOIN_LOOKUP_V12.capabilityName())) ); Response resp = runESQLCommand("fls_user2_alias", "ROW x = 40.0 | EVAL value = x | LOOKUP JOIN lookup-second-alias ON value"); @@ -850,7 +850,7 @@ public void testLookupJoinFieldLevelSecurityOnAlias() throws Exception { public void testLookupJoinIndexForbidden() throws Exception { assumeTrue( "Requires LOOKUP JOIN capability", - EsqlSpecTestCase.hasCapabilities(adminClient(), List.of(EsqlCapabilities.Cap.JOIN_LOOKUP_V12.capabilityName())) + hasCapabilities(adminClient(), List.of(EsqlCapabilities.Cap.JOIN_LOOKUP_V12.capabilityName())) ); var resp = expectThrows( diff --git a/x-pack/plugin/esql/qa/server/mixed-cluster/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/mixed/MixedClusterEsqlSpecIT.java b/x-pack/plugin/esql/qa/server/mixed-cluster/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/mixed/MixedClusterEsqlSpecIT.java index fc08861ee3cae..ecf110b45ca08 100644 --- a/x-pack/plugin/esql/qa/server/mixed-cluster/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/mixed/MixedClusterEsqlSpecIT.java +++ b/x-pack/plugin/esql/qa/server/mixed-cluster/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/mixed/MixedClusterEsqlSpecIT.java @@ -21,6 +21,7 @@ import static org.elasticsearch.xpack.esql.CsvTestUtils.isEnabled; import static org.elasticsearch.xpack.esql.action.EsqlCapabilities.Cap.JOIN_LOOKUP_V12; +import static org.elasticsearch.xpack.esql.qa.rest.RestEsqlTestCase.hasCapabilities; public class MixedClusterEsqlSpecIT extends EsqlSpecTestCase { @ClassRule @@ -80,12 +81,12 @@ protected boolean supportsInferenceTestService() { } @Override - protected boolean supportsIndexModeLookup() throws IOException { - return hasCapabilities(List.of(JOIN_LOOKUP_V12.capabilityName())); + protected boolean supportsIndexModeLookup() { + return hasCapabilities(client(), List.of(JOIN_LOOKUP_V12.capabilityName())); } @Override - protected boolean supportsSourceFieldMapping() throws IOException { + protected boolean supportsSourceFieldMapping() { return false; } 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 241be44f9abf0..b3a0f0fc8b012 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 @@ -187,8 +187,12 @@ protected boolean supportTimeSeriesCommand() { return true; } - protected static void checkCapabilities(RestClient client, TestFeatureService testFeatureService, String testName, CsvTestCase testCase) - throws IOException { + protected static void checkCapabilities( + RestClient client, + TestFeatureService testFeatureService, + String testName, + CsvTestCase testCase + ) { if (hasCapabilities(client, testCase.requiredCapabilities)) { return; } 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 e41e0edf20eac..0f079694009c8 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 @@ -43,6 +43,7 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; +import java.io.UncheckedIOException; import java.nio.charset.StandardCharsets; import java.time.ZoneId; import java.util.ArrayList; @@ -54,6 +55,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.function.IntFunction; import static java.util.Collections.emptySet; @@ -1423,16 +1425,17 @@ private static void prepareProfileLogger(RequestObjectBuilder requestObject, @Nu */ private static final ConcurrentMap, Boolean> capabilities = new ConcurrentHashMap<>(); - public static boolean hasCapabilities(RestClient client, List requiredCapabilities) throws IOException { + public static boolean hasCapabilities(RestClient client, List requiredCapabilities) { if (requiredCapabilities.isEmpty()) { return true; } - Boolean cap = capabilities.get(requiredCapabilities); - if (cap == null) { - cap = clusterHasCapability(client, "POST", "/_query", List.of(), requiredCapabilities).orElse(false); - capabilities.put(requiredCapabilities, cap); - } - return cap; + return capabilities.computeIfAbsent(requiredCapabilities, r -> { + try { + return clusterHasCapability(client, "POST", "/_query", List.of(), requiredCapabilities).orElse(false); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }); } private static Object removeOriginalTypesAndSuggestedCast(Object response) { From 2b86b1477565f61b038e591297e3d1d97ed7a765 Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Wed, 30 Jul 2025 14:43:01 -0400 Subject: [PATCH 6/9] Switch to admin client --- .../xpack/esql/qa/mixed/MixedClusterEsqlSpecIT.java | 2 +- .../elasticsearch/xpack/esql/ccq/MultiClusterSpecIT.java | 4 ++-- .../elasticsearch/xpack/esql/qa/rest/EsqlSpecTestCase.java | 2 +- .../elasticsearch/xpack/esql/qa/rest/RestEsqlTestCase.java | 6 +++--- .../esql/qa/rest/generative/GenerativeForkRestTest.java | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/x-pack/plugin/esql/qa/server/mixed-cluster/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/mixed/MixedClusterEsqlSpecIT.java b/x-pack/plugin/esql/qa/server/mixed-cluster/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/mixed/MixedClusterEsqlSpecIT.java index ecf110b45ca08..9695411b2c33b 100644 --- a/x-pack/plugin/esql/qa/server/mixed-cluster/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/mixed/MixedClusterEsqlSpecIT.java +++ b/x-pack/plugin/esql/qa/server/mixed-cluster/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/mixed/MixedClusterEsqlSpecIT.java @@ -82,7 +82,7 @@ protected boolean supportsInferenceTestService() { @Override protected boolean supportsIndexModeLookup() { - return hasCapabilities(client(), List.of(JOIN_LOOKUP_V12.capabilityName())); + return hasCapabilities(adminClient(), List.of(JOIN_LOOKUP_V12.capabilityName())); } @Override diff --git a/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClusterSpecIT.java b/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClusterSpecIT.java index 8cc10fd246861..38885d4a3263f 100644 --- a/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClusterSpecIT.java +++ b/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClusterSpecIT.java @@ -139,7 +139,7 @@ protected void shouldSkipTest(String testName) throws IOException { if (testCase.requiredCapabilities.contains(JOIN_LOOKUP_V12.capabilityName())) { assumeTrue( "LOOKUP JOIN not yet supported in CCS", - hasCapabilities(client(), List.of(ENABLE_LOOKUP_JOIN_ON_REMOTE.capabilityName())) + hasCapabilities(adminClient(), List.of(ENABLE_LOOKUP_JOIN_ON_REMOTE.capabilityName())) ); } // Unmapped fields require a coorect capability response from every cluster, which isn't currently implemented. @@ -389,7 +389,7 @@ protected boolean supportsInferenceTestService() { @Override protected boolean supportsIndexModeLookup() throws IOException { - return hasCapabilities(client(), List.of(JOIN_LOOKUP_V12.capabilityName())); + return hasCapabilities(adminClient(), List.of(JOIN_LOOKUP_V12.capabilityName())); } @Override 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 b3a0f0fc8b012..5ca7e4e8b03aa 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 @@ -459,7 +459,7 @@ private Map> tables() { protected boolean supportsTook() throws IOException { if (supportsTook == null) { - supportsTook = hasCapabilities(client(), List.of("usage_contains_took")); + supportsTook = hasCapabilities(adminClient(), List.of("usage_contains_took")); } return supportsTook; } 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 0f079694009c8..295da47b7429a 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 @@ -1338,8 +1338,8 @@ public static Map runEsqlAsync( checkKeepOnCompletion(requestObject, json, keepOnCompletion); String id = (String) json.get("id"); - var supportsAsyncHeaders = hasCapabilities(client(), List.of("async_query_status_headers")); - var supportsSuggestedCast = hasCapabilities(client(), List.of("suggested_cast")); + var supportsAsyncHeaders = hasCapabilities(adminClient(), List.of("async_query_status_headers")); + var supportsSuggestedCast = hasCapabilities(adminClient(), List.of("suggested_cast")); if (id == null) { // no id returned from an async call, must have completed immediately and without keep_on_completion @@ -1413,7 +1413,7 @@ public static Map runEsqlAsync( private static void prepareProfileLogger(RequestObjectBuilder requestObject, @Nullable ProfileLogger profileLogger) throws IOException { if (profileLogger != null) { profileLogger.clearProfile(); - var isProfileSafe = hasCapabilities(client(), List.of("fixed_profile_serialization")); + var isProfileSafe = hasCapabilities(adminClient(), List.of("fixed_profile_serialization")); if (isProfileSafe) { requestObject.profile(true); } diff --git a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/generative/GenerativeForkRestTest.java b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/generative/GenerativeForkRestTest.java index 04173aa79621d..30af8d4045d19 100644 --- a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/generative/GenerativeForkRestTest.java +++ b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/generative/GenerativeForkRestTest.java @@ -60,6 +60,6 @@ protected void shouldSkipTest(String testName) throws IOException { testCase.requiredCapabilities.contains(IMPLICIT_CASTING_DATE_AND_DATE_NANOS.capabilityName()) ); - assumeTrue("Cluster needs to support FORK", hasCapabilities(client(), List.of(FORK_V9.capabilityName()))); + assumeTrue("Cluster needs to support FORK", hasCapabilities(adminClient(), List.of(FORK_V9.capabilityName()))); } } From 7f416131e4961fa8b02243df76b257aed747feac Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Wed, 30 Jul 2025 14:52:56 -0400 Subject: [PATCH 7/9] Fix --- .../org/elasticsearch/xpack/esql/ccq/MultiClusterSpecIT.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClusterSpecIT.java b/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClusterSpecIT.java index 38885d4a3263f..d64daa436b7e9 100644 --- a/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClusterSpecIT.java +++ b/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClusterSpecIT.java @@ -139,7 +139,7 @@ protected void shouldSkipTest(String testName) throws IOException { if (testCase.requiredCapabilities.contains(JOIN_LOOKUP_V12.capabilityName())) { assumeTrue( "LOOKUP JOIN not yet supported in CCS", - hasCapabilities(adminClient(), List.of(ENABLE_LOOKUP_JOIN_ON_REMOTE.capabilityName())) + hasCapabilities(remoteClusterClient(), List.of(ENABLE_LOOKUP_JOIN_ON_REMOTE.capabilityName())) ); } // Unmapped fields require a coorect capability response from every cluster, which isn't currently implemented. From e81956abced0c92be88bc196bf318f096424aa69 Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Wed, 30 Jul 2025 15:03:41 -0400 Subject: [PATCH 8/9] Cache better --- .../org/elasticsearch/xpack/esql/ccq/MultiClusterSpecIT.java | 2 +- .../elasticsearch/xpack/esql/qa/rest/RestEsqlTestCase.java | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClusterSpecIT.java b/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClusterSpecIT.java index d64daa436b7e9..38885d4a3263f 100644 --- a/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClusterSpecIT.java +++ b/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClusterSpecIT.java @@ -139,7 +139,7 @@ protected void shouldSkipTest(String testName) throws IOException { if (testCase.requiredCapabilities.contains(JOIN_LOOKUP_V12.capabilityName())) { assumeTrue( "LOOKUP JOIN not yet supported in CCS", - hasCapabilities(remoteClusterClient(), List.of(ENABLE_LOOKUP_JOIN_ON_REMOTE.capabilityName())) + hasCapabilities(adminClient(), List.of(ENABLE_LOOKUP_JOIN_ON_REMOTE.capabilityName())) ); } // Unmapped fields require a coorect capability response from every cluster, which isn't currently implemented. 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 295da47b7429a..eea70b8b46f8e 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 @@ -1420,16 +1420,17 @@ private static void prepareProfileLogger(RequestObjectBuilder requestObject, @Nu } } + record CapabilitesCacheKey(RestClient client, List capabilities) {} /** * Cache of capabilities. */ - private static final ConcurrentMap, Boolean> capabilities = new ConcurrentHashMap<>(); + private static final ConcurrentMap capabilities = new ConcurrentHashMap<>(); public static boolean hasCapabilities(RestClient client, List requiredCapabilities) { if (requiredCapabilities.isEmpty()) { return true; } - return capabilities.computeIfAbsent(requiredCapabilities, r -> { + return capabilities.computeIfAbsent(new CapabilitesCacheKey(client, requiredCapabilities), r -> { try { return clusterHasCapability(client, "POST", "/_query", List.of(), requiredCapabilities).orElse(false); } catch (IOException e) { From e8d54fabf335445b59ca949e6b6c4c82152c36c0 Mon Sep 17 00:00:00 2001 From: elasticsearchmachine Date: Wed, 30 Jul 2025 19:16:03 +0000 Subject: [PATCH 9/9] [CI] Auto commit changes from spotless --- .../org/elasticsearch/xpack/esql/qa/rest/RestEsqlTestCase.java | 1 + 1 file changed, 1 insertion(+) 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 eea70b8b46f8e..83607c259c520 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 @@ -1421,6 +1421,7 @@ private static void prepareProfileLogger(RequestObjectBuilder requestObject, @Nu } record CapabilitesCacheKey(RestClient client, List capabilities) {} + /** * Cache of capabilities. */