From 65bc1934ce5eb4112427c1fefb465eda0f80e7ef Mon Sep 17 00:00:00 2001 From: Lorenzo Dematte Date: Mon, 27 Oct 2025 15:57:21 +0100 Subject: [PATCH 1/3] Abstract version features checking to work with non-semantic versions --- .../rest/yaml/CcsCommonYamlTestSuiteIT.java | 10 ++----- .../yaml/RcsCcsCommonYamlTestSuiteIT.java | 10 ++----- .../org/elasticsearch/node/NodeService.java | 4 +-- .../test/rest/ESRestTestCase.java | 15 ++++------ .../test/rest/ESRestTestFeatureService.java | 30 +++++++++++++++---- .../rest/yaml/ESClientYamlSuiteTestCase.java | 8 ++--- .../xpack/esql/ccq/MultiClusterSpecIT.java | 12 ++++---- 7 files changed, 44 insertions(+), 45 deletions(-) diff --git a/qa/ccs-common-rest/src/yamlRestTest/java/org/elasticsearch/test/rest/yaml/CcsCommonYamlTestSuiteIT.java b/qa/ccs-common-rest/src/yamlRestTest/java/org/elasticsearch/test/rest/yaml/CcsCommonYamlTestSuiteIT.java index da7f1feeae2ea..fa26c4fa84700 100644 --- a/qa/ccs-common-rest/src/yamlRestTest/java/org/elasticsearch/test/rest/yaml/CcsCommonYamlTestSuiteIT.java +++ b/qa/ccs-common-rest/src/yamlRestTest/java/org/elasticsearch/test/rest/yaml/CcsCommonYamlTestSuiteIT.java @@ -28,7 +28,7 @@ import org.elasticsearch.test.cluster.ElasticsearchCluster; import org.elasticsearch.test.cluster.FeatureFlag; import org.elasticsearch.test.cluster.local.LocalClusterConfigProvider; -import org.elasticsearch.test.rest.ESRestTestCase; +import org.elasticsearch.test.rest.ESRestTestFeatureService; import org.elasticsearch.test.rest.ObjectPath; import org.elasticsearch.test.rest.TestFeatureService; import org.elasticsearch.test.rest.yaml.restspec.ClientYamlSuiteRestApi; @@ -50,7 +50,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; @@ -315,13 +314,10 @@ protected ClientYamlTestExecutionContext createRestTestExecutionContext( // Reconcile and provide unified features, os, version(s), based on both clientYamlTestClient and searchYamlTestClient var searchOs = readOsFromNodesInfo(adminSearchClient); var searchNodeVersions = readVersionsFromNodesInfo(adminSearchClient); - var semanticNodeVersions = searchNodeVersions.stream() - .map(ESRestTestCase::parseLegacyVersion) - .flatMap(Optional::stream) - .collect(Collectors.toSet()); + final TestFeatureService searchTestFeatureService = createTestFeatureService( getClusterStateFeatures(adminSearchClient), - semanticNodeVersions + ESRestTestFeatureService.fromSemanticVersions(searchNodeVersions) ); final TestFeatureService combinedTestFeatureService = (featureId, any) -> { boolean adminFeature = testFeatureService.clusterHasFeature(featureId, any); diff --git a/qa/ccs-common-rest/src/yamlRestTest/java/org/elasticsearch/test/rest/yaml/RcsCcsCommonYamlTestSuiteIT.java b/qa/ccs-common-rest/src/yamlRestTest/java/org/elasticsearch/test/rest/yaml/RcsCcsCommonYamlTestSuiteIT.java index e7c3673dadc96..e582f3baf0c2d 100644 --- a/qa/ccs-common-rest/src/yamlRestTest/java/org/elasticsearch/test/rest/yaml/RcsCcsCommonYamlTestSuiteIT.java +++ b/qa/ccs-common-rest/src/yamlRestTest/java/org/elasticsearch/test/rest/yaml/RcsCcsCommonYamlTestSuiteIT.java @@ -30,7 +30,7 @@ import org.elasticsearch.test.cluster.FeatureFlag; import org.elasticsearch.test.cluster.local.LocalClusterConfigProvider; import org.elasticsearch.test.cluster.util.resource.Resource; -import org.elasticsearch.test.rest.ESRestTestCase; +import org.elasticsearch.test.rest.ESRestTestFeatureService; import org.elasticsearch.test.rest.ObjectPath; import org.elasticsearch.test.rest.TestFeatureService; import org.elasticsearch.test.rest.yaml.CcsCommonYamlTestSuiteIT.TestCandidateAwareClient; @@ -45,7 +45,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; @@ -298,14 +297,9 @@ protected ClientYamlTestExecutionContext createRestTestExecutionContext( var searchOs = readOsFromNodesInfo(adminSearchClient); var searchNodeVersions = readVersionsFromNodesInfo(adminSearchClient); - var semanticNodeVersions = searchNodeVersions.stream() - .map(ESRestTestCase::parseLegacyVersion) - .flatMap(Optional::stream) - .collect(Collectors.toSet()); - final TestFeatureService searchTestFeatureService = createTestFeatureService( getClusterStateFeatures(adminSearchClient), - semanticNodeVersions + ESRestTestFeatureService.fromSemanticVersions(searchNodeVersions) ); final TestFeatureService combinedTestFeatureService = (featureId, any) -> { diff --git a/server/src/main/java/org/elasticsearch/node/NodeService.java b/server/src/main/java/org/elasticsearch/node/NodeService.java index 7c71487ed68ca..8ad63b6bd3da3 100644 --- a/server/src/main/java/org/elasticsearch/node/NodeService.java +++ b/server/src/main/java/org/elasticsearch/node/NodeService.java @@ -10,7 +10,6 @@ package org.elasticsearch.node; import org.elasticsearch.Build; -import org.elasticsearch.Version; import org.elasticsearch.action.admin.cluster.node.info.ComponentVersionNumber; import org.elasticsearch.action.admin.cluster.node.info.NodeInfo; import org.elasticsearch.action.admin.cluster.node.stats.NodeStats; @@ -125,8 +124,7 @@ public NodeInfo info( boolean indices ) { return new NodeInfo( - // TODO: revert to Build.current().version() when Kibana is updated - Version.CURRENT.toString(), + Build.current().version(), compatibilityVersions, IndexVersion.current(), componentVersions, diff --git a/test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestCase.java index 5ddd925e4e803..85a2c7ce12254 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestCase.java @@ -446,13 +446,10 @@ public void initClient() throws IOException { } } nodesVersions = Collections.unmodifiableSet(versions); - - var semanticNodeVersions = nodesVersions.stream() - .map(ESRestTestCase::parseLegacyVersion) - .flatMap(Optional::stream) - .collect(Collectors.toSet()); - assert semanticNodeVersions.isEmpty() == false || serverless; - testFeatureService = createTestFeatureService(getClusterStateFeatures(adminClient), semanticNodeVersions); + testFeatureService = createTestFeatureService( + getClusterStateFeatures(adminClient), + ESRestTestFeatureService.fromSemanticVersions(nodesVersions) + ); configureProjects(); } @@ -467,9 +464,9 @@ public void initClient() throws IOException { protected final TestFeatureService createTestFeatureService( Map> clusterStateFeatures, - Set semanticNodeVersions + ESRestTestFeatureService.VersionFeaturesPredicate versionFeaturesPredicate ) { - return new ESRestTestFeatureService(semanticNodeVersions, clusterStateFeatures.values()); + return new ESRestTestFeatureService(versionFeaturesPredicate, clusterStateFeatures.values()); } protected static boolean has(ProductFeature feature) { diff --git a/test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestFeatureService.java b/test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestFeatureService.java index 4c23c05ddda3c..bffc2ae47ffd2 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestFeatureService.java +++ b/test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestFeatureService.java @@ -26,15 +26,17 @@ import java.util.Collection; import java.util.Collections; import java.util.HashSet; +import java.util.Optional; import java.util.Set; import java.util.function.BiConsumer; import java.util.function.Predicate; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; import static java.util.Collections.emptySet; -class ESRestTestFeatureService implements TestFeatureService { +public class ESRestTestFeatureService implements TestFeatureService { /** * In order to migrate from version checks to cluster feature checks, @@ -42,11 +44,29 @@ class ESRestTestFeatureService implements TestFeatureService { */ private static final Pattern VERSION_FEATURE_PATTERN = Pattern.compile("gte_v(\\d+\\.\\d+\\.\\d+)"); - private final Collection nodeVersions; + public interface VersionFeaturesPredicate { + boolean test(Version featureVersion, boolean any); + } + + public static VersionFeaturesPredicate fromSemanticVersions(Set nodesVersions) { + Set semanticNodeVersions = nodesVersions.stream() + .map(ESRestTestCase::parseLegacyVersion) + .flatMap(Optional::stream) + .collect(Collectors.toSet()); + if (semanticNodeVersions.isEmpty()) { + // Nodes do not have a semantic version (e.g. serverless). + // We assume the cluster is on the "latest version", and all is supported. + return ((featureVersion, any) -> true); + } + + return (featureVersion, any) -> checkCollection(semanticNodeVersions, nodeVersion -> nodeVersion.onOrAfter(featureVersion), any); + } + + private final VersionFeaturesPredicate versionFeaturesPredicate; private final Collection> nodeFeatures; - ESRestTestFeatureService(Set nodeVersions, Collection> nodeFeatures) { - this.nodeVersions = nodeVersions; + ESRestTestFeatureService(VersionFeaturesPredicate versionFeaturesPredicate, Collection> nodeFeatures) { + this.versionFeaturesPredicate = versionFeaturesPredicate; this.nodeFeatures = nodeFeatures; } @@ -88,7 +108,7 @@ public boolean clusterHasFeature(String featureId, boolean any) { ); } - return checkCollection(nodeVersions, v -> v.onOrAfter(extractedVersion), any); + return versionFeaturesPredicate.test(extractedVersion, any); } if (hasFeatureMetadata()) { diff --git a/test/yaml-rest-runner/src/main/java/org/elasticsearch/test/rest/yaml/ESClientYamlSuiteTestCase.java b/test/yaml-rest-runner/src/main/java/org/elasticsearch/test/rest/yaml/ESClientYamlSuiteTestCase.java index aade3c0e86cde..eb6f15bf67b9e 100644 --- a/test/yaml-rest-runner/src/main/java/org/elasticsearch/test/rest/yaml/ESClientYamlSuiteTestCase.java +++ b/test/yaml-rest-runner/src/main/java/org/elasticsearch/test/rest/yaml/ESClientYamlSuiteTestCase.java @@ -27,6 +27,7 @@ import org.elasticsearch.core.IOUtils; import org.elasticsearch.test.ClasspathUtils; import org.elasticsearch.test.rest.ESRestTestCase; +import org.elasticsearch.test.rest.ESRestTestFeatureService; import org.elasticsearch.test.rest.TestFeatureService; import org.elasticsearch.test.rest.yaml.restspec.ClientYamlSuiteRestApi; import org.elasticsearch.test.rest.yaml.restspec.ClientYamlSuiteRestSpec; @@ -54,7 +55,6 @@ import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; -import java.util.stream.Collectors; /** * Runs a suite of yaml tests shared with all the official Elasticsearch @@ -127,13 +127,9 @@ public void initAndResetContext() throws Exception { logger.info("initializing client, node versions [{}], hosts {}, os [{}]", nodesVersions, hosts, os); - var semanticNodeVersions = nodesVersions.stream() - .map(ESRestTestCase::parseLegacyVersion) - .flatMap(Optional::stream) - .collect(Collectors.toSet()); final TestFeatureService testFeatureService = createTestFeatureService( getClusterStateFeatures(adminClient()), - semanticNodeVersions + ESRestTestFeatureService.fromSemanticVersions(nodesVersions) ); logger.info("initializing client, node versions [{}], hosts {}, os [{}]", nodesVersions, hosts, os); 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 71687afcec6e8..ab9e5b24772e6 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 @@ -20,7 +20,7 @@ import org.elasticsearch.core.IOUtils; import org.elasticsearch.test.TestClustersThreadFilter; import org.elasticsearch.test.cluster.ElasticsearchCluster; -import org.elasticsearch.test.rest.ESRestTestCase; +import org.elasticsearch.test.rest.ESRestTestFeatureService; import org.elasticsearch.test.rest.TestFeatureService; import org.elasticsearch.xpack.esql.CsvSpecReader; import org.elasticsearch.xpack.esql.CsvSpecReader.CsvTestCase; @@ -38,7 +38,6 @@ import java.util.Arrays; import java.util.List; import java.util.Locale; -import java.util.Optional; import java.util.Set; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -172,11 +171,10 @@ protected void shouldSkipTest(String testName) throws IOException { private TestFeatureService remoteFeaturesService() throws IOException { if (remoteFeaturesService == null) { var remoteNodeVersions = readVersionsFromNodesInfo(remoteClusterClient()); - var semanticNodeVersions = remoteNodeVersions.stream() - .map(ESRestTestCase::parseLegacyVersion) - .flatMap(Optional::stream) - .collect(Collectors.toSet()); - remoteFeaturesService = createTestFeatureService(getClusterStateFeatures(remoteClusterClient()), semanticNodeVersions); + remoteFeaturesService = createTestFeatureService( + getClusterStateFeatures(remoteClusterClient()), + ESRestTestFeatureService.fromSemanticVersions(remoteNodeVersions) + ); } return remoteFeaturesService; } From d85d8891b77421845eefc22e4cf353206014d8f4 Mon Sep 17 00:00:00 2001 From: Lorenzo Dematte Date: Tue, 28 Oct 2025 09:27:38 +0100 Subject: [PATCH 2/3] Revert change to NodeService --- server/src/main/java/org/elasticsearch/node/NodeService.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/server/src/main/java/org/elasticsearch/node/NodeService.java b/server/src/main/java/org/elasticsearch/node/NodeService.java index 8ad63b6bd3da3..7c71487ed68ca 100644 --- a/server/src/main/java/org/elasticsearch/node/NodeService.java +++ b/server/src/main/java/org/elasticsearch/node/NodeService.java @@ -10,6 +10,7 @@ package org.elasticsearch.node; import org.elasticsearch.Build; +import org.elasticsearch.Version; import org.elasticsearch.action.admin.cluster.node.info.ComponentVersionNumber; import org.elasticsearch.action.admin.cluster.node.info.NodeInfo; import org.elasticsearch.action.admin.cluster.node.stats.NodeStats; @@ -124,7 +125,8 @@ public NodeInfo info( boolean indices ) { return new NodeInfo( - Build.current().version(), + // TODO: revert to Build.current().version() when Kibana is updated + Version.CURRENT.toString(), compatibilityVersions, IndexVersion.current(), componentVersions, From 816216289a98e2041ede561bb0fadde3e70e9203 Mon Sep 17 00:00:00 2001 From: Lorenzo Dematte Date: Tue, 28 Oct 2025 10:01:38 +0100 Subject: [PATCH 3/3] PR comments --- .../rest/yaml/CcsCommonYamlTestSuiteIT.java | 3 +- .../yaml/RcsCcsCommonYamlTestSuiteIT.java | 3 +- .../test/rest/ESRestTestCase.java | 32 ++++++++++++++++--- .../test/rest/ESRestTestFeatureService.java | 32 ++++--------------- .../rest/yaml/ESClientYamlSuiteTestCase.java | 3 +- .../xpack/esql/ccq/MultiClusterSpecIT.java | 3 +- 6 files changed, 37 insertions(+), 39 deletions(-) diff --git a/qa/ccs-common-rest/src/yamlRestTest/java/org/elasticsearch/test/rest/yaml/CcsCommonYamlTestSuiteIT.java b/qa/ccs-common-rest/src/yamlRestTest/java/org/elasticsearch/test/rest/yaml/CcsCommonYamlTestSuiteIT.java index fa26c4fa84700..b5cdf1a355f59 100644 --- a/qa/ccs-common-rest/src/yamlRestTest/java/org/elasticsearch/test/rest/yaml/CcsCommonYamlTestSuiteIT.java +++ b/qa/ccs-common-rest/src/yamlRestTest/java/org/elasticsearch/test/rest/yaml/CcsCommonYamlTestSuiteIT.java @@ -28,7 +28,6 @@ import org.elasticsearch.test.cluster.ElasticsearchCluster; import org.elasticsearch.test.cluster.FeatureFlag; import org.elasticsearch.test.cluster.local.LocalClusterConfigProvider; -import org.elasticsearch.test.rest.ESRestTestFeatureService; import org.elasticsearch.test.rest.ObjectPath; import org.elasticsearch.test.rest.TestFeatureService; import org.elasticsearch.test.rest.yaml.restspec.ClientYamlSuiteRestApi; @@ -317,7 +316,7 @@ protected ClientYamlTestExecutionContext createRestTestExecutionContext( final TestFeatureService searchTestFeatureService = createTestFeatureService( getClusterStateFeatures(adminSearchClient), - ESRestTestFeatureService.fromSemanticVersions(searchNodeVersions) + fromSemanticVersions(searchNodeVersions) ); final TestFeatureService combinedTestFeatureService = (featureId, any) -> { boolean adminFeature = testFeatureService.clusterHasFeature(featureId, any); diff --git a/qa/ccs-common-rest/src/yamlRestTest/java/org/elasticsearch/test/rest/yaml/RcsCcsCommonYamlTestSuiteIT.java b/qa/ccs-common-rest/src/yamlRestTest/java/org/elasticsearch/test/rest/yaml/RcsCcsCommonYamlTestSuiteIT.java index e582f3baf0c2d..5bb66985a3ab8 100644 --- a/qa/ccs-common-rest/src/yamlRestTest/java/org/elasticsearch/test/rest/yaml/RcsCcsCommonYamlTestSuiteIT.java +++ b/qa/ccs-common-rest/src/yamlRestTest/java/org/elasticsearch/test/rest/yaml/RcsCcsCommonYamlTestSuiteIT.java @@ -30,7 +30,6 @@ import org.elasticsearch.test.cluster.FeatureFlag; import org.elasticsearch.test.cluster.local.LocalClusterConfigProvider; import org.elasticsearch.test.cluster.util.resource.Resource; -import org.elasticsearch.test.rest.ESRestTestFeatureService; import org.elasticsearch.test.rest.ObjectPath; import org.elasticsearch.test.rest.TestFeatureService; import org.elasticsearch.test.rest.yaml.CcsCommonYamlTestSuiteIT.TestCandidateAwareClient; @@ -299,7 +298,7 @@ protected ClientYamlTestExecutionContext createRestTestExecutionContext( final TestFeatureService searchTestFeatureService = createTestFeatureService( getClusterStateFeatures(adminSearchClient), - ESRestTestFeatureService.fromSemanticVersions(searchNodeVersions) + fromSemanticVersions(searchNodeVersions) ); final TestFeatureService combinedTestFeatureService = (featureId, any) -> { diff --git a/test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestCase.java index 85a2c7ce12254..3fb11cfe5e153 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestCase.java @@ -176,6 +176,10 @@ public abstract class ESRestTestCase extends ESTestCase { private static final Pattern SEMANTIC_VERSION_PATTERN = Pattern.compile("^(\\d+\\.\\d+\\.\\d+)\\D?.*"); + public interface VersionFeaturesPredicate { + boolean test(Version featureVersion, boolean canMatchAnyNode); + } + private static final Logger SUITE_LOGGER = LogManager.getLogger(ESRestTestCase.class); private static final String EXPECTED_ROLLUP_WARNING_MESSAGE = @@ -446,10 +450,7 @@ public void initClient() throws IOException { } } nodesVersions = Collections.unmodifiableSet(versions); - testFeatureService = createTestFeatureService( - getClusterStateFeatures(adminClient), - ESRestTestFeatureService.fromSemanticVersions(nodesVersions) - ); + testFeatureService = createTestFeatureService(getClusterStateFeatures(adminClient), fromSemanticVersions(nodesVersions)); configureProjects(); } @@ -464,7 +465,7 @@ public void initClient() throws IOException { protected final TestFeatureService createTestFeatureService( Map> clusterStateFeatures, - ESRestTestFeatureService.VersionFeaturesPredicate versionFeaturesPredicate + VersionFeaturesPredicate versionFeaturesPredicate ) { return new ESRestTestFeatureService(versionFeaturesPredicate, clusterStateFeatures.values()); } @@ -2581,6 +2582,27 @@ public static Optional parseLegacyVersion(String version) { return Optional.empty(); } + public static VersionFeaturesPredicate fromSemanticVersions(Set nodesVersions) { + Set semanticNodeVersions = nodesVersions.stream() + .map(ESRestTestCase::parseLegacyVersion) + .flatMap(Optional::stream) + .collect(Collectors.toSet()); + if (semanticNodeVersions.isEmpty()) { + // Nodes do not have a semantic version (e.g. serverless). + // We assume the cluster is on the "latest version", and all is supported. + return ((featureVersion, canMatchAnyNode) -> true); + } + + return (featureVersion, canMatchAnyNode) -> { + if (canMatchAnyNode) { + return semanticNodeVersions.stream().anyMatch(nodeVersion -> nodeVersion.onOrAfter(featureVersion)); + } else { + return semanticNodeVersions.isEmpty() == false + && semanticNodeVersions.stream().allMatch(nodeVersion -> nodeVersion.onOrAfter(featureVersion)); + } + }; + } + /** * Wait for the license to be applied and active. The specified admin client is used to check the license and this is done using * {@link ESTestCase#assertBusy(CheckedRunnable)} to give some time to the License to be applied on nodes. diff --git a/test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestFeatureService.java b/test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestFeatureService.java index bffc2ae47ffd2..2006abdf25632 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestFeatureService.java +++ b/test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestFeatureService.java @@ -26,17 +26,15 @@ import java.util.Collection; import java.util.Collections; import java.util.HashSet; -import java.util.Optional; import java.util.Set; import java.util.function.BiConsumer; import java.util.function.Predicate; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collectors; import static java.util.Collections.emptySet; -public class ESRestTestFeatureService implements TestFeatureService { +class ESRestTestFeatureService implements TestFeatureService { /** * In order to migrate from version checks to cluster feature checks, @@ -44,28 +42,10 @@ public class ESRestTestFeatureService implements TestFeatureService { */ private static final Pattern VERSION_FEATURE_PATTERN = Pattern.compile("gte_v(\\d+\\.\\d+\\.\\d+)"); - public interface VersionFeaturesPredicate { - boolean test(Version featureVersion, boolean any); - } - - public static VersionFeaturesPredicate fromSemanticVersions(Set nodesVersions) { - Set semanticNodeVersions = nodesVersions.stream() - .map(ESRestTestCase::parseLegacyVersion) - .flatMap(Optional::stream) - .collect(Collectors.toSet()); - if (semanticNodeVersions.isEmpty()) { - // Nodes do not have a semantic version (e.g. serverless). - // We assume the cluster is on the "latest version", and all is supported. - return ((featureVersion, any) -> true); - } - - return (featureVersion, any) -> checkCollection(semanticNodeVersions, nodeVersion -> nodeVersion.onOrAfter(featureVersion), any); - } - - private final VersionFeaturesPredicate versionFeaturesPredicate; + private final ESRestTestCase.VersionFeaturesPredicate versionFeaturesPredicate; private final Collection> nodeFeatures; - ESRestTestFeatureService(VersionFeaturesPredicate versionFeaturesPredicate, Collection> nodeFeatures) { + ESRestTestFeatureService(ESRestTestCase.VersionFeaturesPredicate versionFeaturesPredicate, Collection> nodeFeatures) { this.versionFeaturesPredicate = versionFeaturesPredicate; this.nodeFeatures = nodeFeatures; } @@ -75,8 +55,8 @@ private static boolean checkCollection(Collection coll, Predicate pred } @Override - public boolean clusterHasFeature(String featureId, boolean any) { - if (checkCollection(nodeFeatures, s -> s.contains(featureId), any)) { + public boolean clusterHasFeature(String featureId, boolean canMatchAnyNode) { + if (checkCollection(nodeFeatures, s -> s.contains(featureId), canMatchAnyNode)) { return true; } if (MetadataHolder.FEATURE_NAMES.contains(featureId)) { @@ -108,7 +88,7 @@ public boolean clusterHasFeature(String featureId, boolean any) { ); } - return versionFeaturesPredicate.test(extractedVersion, any); + return versionFeaturesPredicate.test(extractedVersion, canMatchAnyNode); } if (hasFeatureMetadata()) { diff --git a/test/yaml-rest-runner/src/main/java/org/elasticsearch/test/rest/yaml/ESClientYamlSuiteTestCase.java b/test/yaml-rest-runner/src/main/java/org/elasticsearch/test/rest/yaml/ESClientYamlSuiteTestCase.java index eb6f15bf67b9e..0948f1ae63283 100644 --- a/test/yaml-rest-runner/src/main/java/org/elasticsearch/test/rest/yaml/ESClientYamlSuiteTestCase.java +++ b/test/yaml-rest-runner/src/main/java/org/elasticsearch/test/rest/yaml/ESClientYamlSuiteTestCase.java @@ -27,7 +27,6 @@ import org.elasticsearch.core.IOUtils; import org.elasticsearch.test.ClasspathUtils; import org.elasticsearch.test.rest.ESRestTestCase; -import org.elasticsearch.test.rest.ESRestTestFeatureService; import org.elasticsearch.test.rest.TestFeatureService; import org.elasticsearch.test.rest.yaml.restspec.ClientYamlSuiteRestApi; import org.elasticsearch.test.rest.yaml.restspec.ClientYamlSuiteRestSpec; @@ -129,7 +128,7 @@ public void initAndResetContext() throws Exception { final TestFeatureService testFeatureService = createTestFeatureService( getClusterStateFeatures(adminClient()), - ESRestTestFeatureService.fromSemanticVersions(nodesVersions) + fromSemanticVersions(nodesVersions) ); logger.info("initializing client, node versions [{}], hosts {}, os [{}]", nodesVersions, hosts, os); 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 ef3ba53fb282b..ac4a5ec4d4721 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 @@ -20,7 +20,6 @@ import org.elasticsearch.core.IOUtils; import org.elasticsearch.test.TestClustersThreadFilter; import org.elasticsearch.test.cluster.ElasticsearchCluster; -import org.elasticsearch.test.rest.ESRestTestFeatureService; import org.elasticsearch.test.rest.TestFeatureService; import org.elasticsearch.xpack.esql.CsvSpecReader; import org.elasticsearch.xpack.esql.CsvSpecReader.CsvTestCase; @@ -180,7 +179,7 @@ private TestFeatureService remoteFeaturesService() throws IOException { var remoteNodeVersions = readVersionsFromNodesInfo(remoteClusterClient()); remoteFeaturesService = createTestFeatureService( getClusterStateFeatures(remoteClusterClient()), - ESRestTestFeatureService.fromSemanticVersions(remoteNodeVersions) + fromSemanticVersions(remoteNodeVersions) ); } return remoteFeaturesService;