From e4cda8a3e86a34a9b72d477708429b845370dd91 Mon Sep 17 00:00:00 2001 From: Craig Taverner Date: Wed, 7 May 2025 10:02:17 +0200 Subject: [PATCH] Output function signature license requirements to Kibana definitions (#127717) Output function signature license requirements to Kibana definition files, and also test that this matches the actual licensing behaviour of the functions. ES|QL functions that enforce license checks do so with the `LicenseAware` interface. This does not expose what that functions license level is, but only whether the current active license will be sufficient for that function and its current signature (data types passed in as fields). Rather than add to this interface, we've made the license level information test-only information. This means if a function implements LicenseAware, it also needs to add a method to its test class to specify the license level for the signature being called. All functions will be tested for compliance, so failing to add this will result in test failure. Also if the test license level does not match the enforced license, that will also cause a failure. --- .../definition/functions/categorize.json | 3 + .../definition/functions/st_extent_agg.json | 2 + .../xpack/esql/core/type/DataType.java | 4 + .../function/AbstractFunctionTestCase.java | 107 +++++++++++++++++- .../expression/function/DocsV3Support.java | 63 +++++++++-- .../function/DocsV3SupportTests.java | 6 +- .../aggregate/SpatialAggregationTestCase.java | 36 ++++++ .../aggregate/SpatialCentroidTests.java | 5 + .../aggregate/SpatialExtentTests.java | 8 +- .../function/grouping/CategorizeTests.java | 5 + .../function/scalar/string/RLikeTests.java | 3 +- .../scalar/string/WildcardLikeTests.java | 3 +- .../predicate/operator/CastOperatorTests.java | 3 +- .../operator/NullPredicatesTests.java | 5 +- .../operator/comparison/InTests.java | 3 +- 15 files changed, 227 insertions(+), 29 deletions(-) create mode 100644 x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/aggregate/SpatialAggregationTestCase.java diff --git a/docs/reference/query-languages/esql/kibana/definition/functions/categorize.json b/docs/reference/query-languages/esql/kibana/definition/functions/categorize.json index 088384a3fa1a8..4f6e1379275e3 100644 --- a/docs/reference/query-languages/esql/kibana/definition/functions/categorize.json +++ b/docs/reference/query-languages/esql/kibana/definition/functions/categorize.json @@ -2,6 +2,7 @@ "comment" : "This is generated by ESQL’s AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.", "type" : "grouping", "name" : "categorize", + "license" : "PLATINUM", "description" : "Groups text messages into categories of similarly formatted text values.", "signatures" : [ { @@ -13,6 +14,7 @@ "description" : "Expression to categorize" } ], + "license" : "PLATINUM", "variadic" : false, "returnType" : "keyword" }, @@ -25,6 +27,7 @@ "description" : "Expression to categorize" } ], + "license" : "PLATINUM", "variadic" : false, "returnType" : "keyword" } diff --git a/docs/reference/query-languages/esql/kibana/definition/functions/st_extent_agg.json b/docs/reference/query-languages/esql/kibana/definition/functions/st_extent_agg.json index fa129eec29da2..9c05870b2cfd1 100644 --- a/docs/reference/query-languages/esql/kibana/definition/functions/st_extent_agg.json +++ b/docs/reference/query-languages/esql/kibana/definition/functions/st_extent_agg.json @@ -25,6 +25,7 @@ "description" : "" } ], + "license" : "PLATINUM", "variadic" : false, "returnType" : "cartesian_shape" }, @@ -49,6 +50,7 @@ "description" : "" } ], + "license" : "PLATINUM", "variadic" : false, "returnType" : "geo_shape" } diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/DataType.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/DataType.java index 671e2df3650dd..79d4cb3b6d1d5 100644 --- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/DataType.java +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/DataType.java @@ -568,6 +568,10 @@ public static boolean isSpatialPoint(DataType t) { return t == GEO_POINT || t == CARTESIAN_POINT; } + public static boolean isSpatialShape(DataType t) { + return t == GEO_SHAPE || t == CARTESIAN_SHAPE; + } + public static boolean isSpatialGeo(DataType t) { return t == GEO_POINT || t == GEO_SHAPE; } diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/AbstractFunctionTestCase.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/AbstractFunctionTestCase.java index 7fe6bbeddc1de..1d502e98973fc 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/AbstractFunctionTestCase.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/AbstractFunctionTestCase.java @@ -24,9 +24,13 @@ import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; import org.elasticsearch.compute.test.TestBlockFactory; import org.elasticsearch.indices.CrankyCircuitBreakerService; +import org.elasticsearch.license.License; +import org.elasticsearch.license.XPackLicenseState; +import org.elasticsearch.license.internal.XPackLicenseStatus; import org.elasticsearch.logging.LogManager; import org.elasticsearch.logging.Logger; import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.LicenseAware; import org.elasticsearch.xpack.esql.core.expression.Attribute; import org.elasticsearch.xpack.esql.core.expression.Expression; import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; @@ -51,7 +55,6 @@ import org.junit.After; import org.junit.AfterClass; -import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -701,7 +704,8 @@ public void testSerializationOfSimple() { */ @AfterClass public static void testFunctionInfo() { - Logger log = LogManager.getLogger(getTestClass()); + Class testClass = getTestClass(); + Logger log = LogManager.getLogger(testClass); FunctionDefinition definition = definition(functionName()); if (definition == null) { log.info("Skipping function info checks because the function isn't registered"); @@ -724,7 +728,7 @@ public static void testFunctionInfo() { for (int i = 0; i < args.size(); i++) { typesFromSignature.add(new HashSet<>()); } - for (Map.Entry, DataType> entry : signatures(getTestClass()).entrySet()) { + for (Map.Entry, DataType> entry : signatures(testClass).entrySet()) { List types = entry.getKey(); for (int i = 0; i < args.size() && i < types.size(); i++) { typesFromSignature.get(i).add(types.get(i).esNameIfPossible()); @@ -767,6 +771,101 @@ public static void testFunctionInfo() { assertEquals(returnFromSignature, returnTypes); } + /** + * This test is meant to validate that the license checks documented match those enforced. + * The expectations are set in the test class using a method with this signature: + * + * public static License.OperationMode licenseRequirement(List<DataType> fieldTypes); + * + * License enforcement in the function class is achieved using the interface LicenseAware. + * This test will make sure the two are in agreement, and does not require that the function class actually + * report its license level. If we add license checks to any function, but fail to also add the expected + * license level to the test class, this test will fail. + */ + @AfterClass + public static void testFunctionLicenseChecks() throws Exception { + Class testClass = getTestClass(); + Logger log = LogManager.getLogger(testClass); + FunctionDefinition definition = definition(functionName()); + if (definition == null) { + log.info("Skipping function info checks because the function isn't registered"); + return; + } + log.info("Running function license checks"); + DocsV3Support.LicenseRequirementChecker licenseChecker = new DocsV3Support.LicenseRequirementChecker(testClass); + License.OperationMode functionLicense = licenseChecker.invoke(null); + Constructor ctor = constructorWithFunctionInfo(definition.clazz()); + if (LicenseAware.class.isAssignableFrom(definition.clazz()) == false) { + // Perform simpler no-signature tests + assertThat( + "Function " + definition.name() + " should be licensed under " + functionLicense, + functionLicense, + equalTo(License.OperationMode.BASIC) + ); + return; + } + // For classes with LicenseAware, we need to check that the license is correct + TestCheckLicense checkLicense = new TestCheckLicense(); + + // Go through all signatures and assert that the license is as expected + signatures(testClass).forEach((signature, returnType) -> { + try { + License.OperationMode license = licenseChecker.invoke(signature); + assertNotNull("License should not be null", license); + + // Construct an instance of the class and then call it's licenseCheck method, and compare the results + Object[] args = new Object[signature.size() + 1]; + args[0] = Source.EMPTY; + for (int i = 0; i < signature.size(); i++) { + args[i + 1] = new Literal(Source.EMPTY, null, signature.get(i)); + } + Object instance = ctor.newInstance(args); + // Check that object implements the LicenseAware interface + if (LicenseAware.class.isAssignableFrom(instance.getClass())) { + LicenseAware licenseAware = (LicenseAware) instance; + switch (license) { + case BASIC -> checkLicense.assertLicenseCheck(licenseAware, signature, true, true, true); + case PLATINUM -> checkLicense.assertLicenseCheck(licenseAware, signature, false, true, true); + case ENTERPRISE -> checkLicense.assertLicenseCheck(licenseAware, signature, false, false, true); + } + } else { + fail("Function " + definition.name() + " does not implement LicenseAware"); + } + } catch (Exception e) { + fail(e); + } + }); + } + + private static class TestCheckLicense { + XPackLicenseState basicLicense = makeLicenseState(License.OperationMode.BASIC); + XPackLicenseState platinumLicense = makeLicenseState(License.OperationMode.PLATINUM); + XPackLicenseState enterpriseLicense = makeLicenseState(License.OperationMode.ENTERPRISE); + + private void assertLicenseCheck( + LicenseAware licenseAware, + List signature, + boolean allowsBasic, + boolean allowsPlatinum, + boolean allowsEnterprise + ) { + boolean basic = licenseAware.licenseCheck(basicLicense); + boolean platinum = licenseAware.licenseCheck(platinumLicense); + boolean enterprise = licenseAware.licenseCheck(enterpriseLicense); + assertThat("Basic license should be accepted for " + signature, basic, equalTo(allowsBasic)); + assertThat("Platinum license should be accepted for " + signature, platinum, equalTo(allowsPlatinum)); + assertThat("Enterprise license should be accepted for " + signature, enterprise, equalTo(allowsEnterprise)); + } + + private void assertLicenseCheck(List signature, boolean allowed, boolean expected) { + assertThat("Basic license should " + (expected ? "" : "not ") + "be accepted for " + signature, allowed, equalTo(expected)); + } + } + + private static XPackLicenseState makeLicenseState(License.OperationMode mode) { + return new XPackLicenseState(System::currentTimeMillis, new XPackLicenseStatus(mode, true, "")); + } + /** * Asserts the result of a test case matches the expected result and warnings. *

@@ -836,7 +935,7 @@ public static Map, DataType> signatures(Class testClass) { } @AfterClass - public static void renderDocs() throws IOException { + public static void renderDocs() throws Exception { if (System.getProperty("generateDocs") == null) { return; } diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/DocsV3Support.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/DocsV3Support.java index 44624fd75cd7c..8f15dc5b7d9d3 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/DocsV3Support.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/DocsV3Support.java @@ -11,6 +11,7 @@ import org.elasticsearch.common.Strings; import org.elasticsearch.core.PathUtils; +import org.elasticsearch.license.License; import org.elasticsearch.logging.LogManager; import org.elasticsearch.logging.Logger; import org.elasticsearch.xcontent.XContentBuilder; @@ -46,6 +47,7 @@ import java.io.InputStreamReader; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; +import java.lang.reflect.Method; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; @@ -107,7 +109,7 @@ static OperatorsDocsSupport forOperators(String name, Class testClass) { return new OperatorsDocsSupport(name, testClass); } - static void renderDocs(String name, Class testClass) throws IOException { + static void renderDocs(String name, Class testClass) throws Exception { if (OPERATORS.containsKey(name)) { var docs = DocsV3Support.forOperators(name, testClass); docs.renderSignature(); @@ -126,7 +128,7 @@ public static void renderNegatedOperator( String name, Function description, Class testClass - ) throws IOException { + ) throws Exception { var docs = forOperators("not " + name.toLowerCase(Locale.ROOT), testClass); docs.renderDocsForNegatedOperators(ctor, description); } @@ -272,12 +274,46 @@ public void writeToTempDir(Path dir, String extension, String str) throws IOExce } } + /** + * This class is used to check if a license requirement method exists in the test class. + * This is used to add license requirement information to the generated documentation. + */ + public static class LicenseRequirementChecker { + private Method staticMethod; + private Function, License.OperationMode> fallbackLambda; + + public LicenseRequirementChecker(Class testClass) { + try { + staticMethod = testClass.getMethod("licenseRequirement", List.class); + if (License.OperationMode.class.equals(staticMethod.getReturnType()) == false + || java.lang.reflect.Modifier.isStatic(staticMethod.getModifiers()) == false) { + staticMethod = null; // Reset if the method doesn't match the signature + } + } catch (NoSuchMethodException e) { + staticMethod = null; + } + + if (staticMethod == null) { + fallbackLambda = fieldTypes -> License.OperationMode.BASIC; + } + } + + public License.OperationMode invoke(List fieldTypes) throws Exception { + if (staticMethod != null) { + return (License.OperationMode) staticMethod.invoke(null, fieldTypes); + } else { + return fallbackLambda.apply(fieldTypes); + } + } + } + protected final String category; protected final String name; protected final FunctionDefinition definition; protected final Logger logger; private final Supplier, DataType>> signatures; private TempFileWriter tempFileWriter; + private final LicenseRequirementChecker licenseChecker; protected DocsV3Support(String category, String name, Class testClass, Supplier, DataType>> signatures) { this(category, name, null, testClass, signatures); @@ -296,6 +332,7 @@ private DocsV3Support( this.logger = LogManager.getLogger(testClass); this.signatures = signatures; this.tempFileWriter = new DocsFileWriter(); + this.licenseChecker = new LicenseRequirementChecker(testClass); } /** Used in tests to capture output for asserting on the content */ @@ -460,7 +497,7 @@ void writeToTempKibanaDir(String subdir, String extension, String str) throws IO protected abstract void renderSignature() throws IOException; - protected abstract void renderDocs() throws IOException; + protected abstract void renderDocs() throws Exception; static class FunctionDocsSupport extends DocsV3Support { private FunctionDocsSupport(String name, Class testClass) { @@ -488,7 +525,7 @@ protected void renderSignature() throws IOException { } @Override - protected void renderDocs() throws IOException { + protected void renderDocs() throws Exception { if (definition == null) { logger.info("Skipping rendering docs because the function '{}' isn't registered", name); } else { @@ -497,7 +534,7 @@ protected void renderDocs() throws IOException { } } - private void renderDocs(FunctionDefinition definition) throws IOException { + private void renderDocs(FunctionDefinition definition) throws Exception { EsqlFunctionRegistry.FunctionDescription description = EsqlFunctionRegistry.description(definition); if (name.equals("case")) { /* @@ -711,7 +748,7 @@ public void renderSignature() throws IOException { } @Override - public void renderDocs() throws IOException { + public void renderDocs() throws Exception { Constructor ctor = constructorWithFunctionInfo(op.clazz()); if (ctor != null) { FunctionInfo functionInfo = ctor.getAnnotation(FunctionInfo.class); @@ -722,7 +759,7 @@ public void renderDocs() throws IOException { } } - void renderDocsForNegatedOperators(Constructor ctor, Function description) throws IOException { + void renderDocsForNegatedOperators(Constructor ctor, Function description) throws Exception { String baseName = name.toLowerCase(Locale.ROOT).replace("not ", ""); OperatorConfig op = OPERATORS.get(baseName); assert op != null; @@ -795,7 +832,7 @@ public Example[] examples() { } void renderDocsForOperators(String name, String titleName, Constructor ctor, FunctionInfo info, boolean variadic) - throws IOException { + throws Exception { renderKibanaInlineDocs(name, titleName, info); var params = ctor.getParameters(); @@ -999,7 +1036,7 @@ void renderKibanaFunctionDefinition( FunctionInfo info, List args, boolean variadic - ) throws IOException { + ) throws Exception { try (XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint().lfAtEnd().startObject()) { builder.field( @@ -1019,6 +1056,10 @@ void renderKibanaFunctionDefinition( }); } builder.field("name", name); + License.OperationMode license = licenseChecker.invoke(null); + if (license != null && license != License.OperationMode.BASIC) { + builder.field("license", license.toString()); + } if (titleName != null && titleName.equals(name) == false) { builder.field("titleName", titleName); } @@ -1073,6 +1114,10 @@ void renderKibanaFunctionDefinition( builder.endObject(); } builder.endArray(); + license = licenseChecker.invoke(sig.getKey()); + if (license != null && license != License.OperationMode.BASIC) { + builder.field("license", license.toString()); + } builder.field("variadic", variadic); builder.field("returnType", sig.getValue().esNameIfPossible()); builder.endObject(); diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/DocsV3SupportTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/DocsV3SupportTests.java index 275849b9bb0fb..86fe852ab9002 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/DocsV3SupportTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/DocsV3SupportTests.java @@ -228,7 +228,7 @@ public void testRenderingExampleResultEmojis() throws IOException { assertThat(results, equalTo(expectedResults)); } - public void testRenderingExampleFromClass() throws IOException { + public void testRenderingExampleFromClass() throws Exception { String expected = """ % This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it. @@ -306,7 +306,7 @@ public void testRenderingExampleFromClass() throws IOException { assertThat(rendered.trim(), equalTo(expected.trim())); } - public void testRenderingLayoutFromClass() throws IOException { + public void testRenderingLayoutFromClass() throws Exception { String expected = """ % This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it. @@ -353,7 +353,7 @@ public void testRenderingLayoutFromClass() throws IOException { assertThat(rendered.trim(), equalTo(expected.trim())); } - private TestDocsFileWriter renderTestClassDocs() throws IOException { + private TestDocsFileWriter renderTestClassDocs() throws Exception { FunctionInfo info = functionInfo(TestClass.class); assert info != null; FunctionDefinition definition = EsqlFunctionRegistry.def(TestClass.class, TestClass::new, "count"); diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/aggregate/SpatialAggregationTestCase.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/aggregate/SpatialAggregationTestCase.java new file mode 100644 index 0000000000000..3ac6179cd1a3a --- /dev/null +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/aggregate/SpatialAggregationTestCase.java @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.expression.function.aggregate; + +import org.elasticsearch.license.License; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.expression.function.AbstractAggregationTestCase; + +import java.util.List; + +public abstract class SpatialAggregationTestCase extends AbstractAggregationTestCase { + + /** + * All spatial aggregations have the same licensing requirements, which is that the function itself is not licensed, but + * the field types are. Aggregations over shapes are licensed under platinum, while aggregations over points are licensed under basic. + * @param fieldTypes (null for the function itself, otherwise a map of field named to types) + * @return The license requirement for the function with that type signature + */ + protected static License.OperationMode licenseRequirement(List fieldTypes) { + if (fieldTypes == null || fieldTypes.isEmpty()) { + // The function itself is not licensed, but the field types are. + return License.OperationMode.BASIC; + } + if (fieldTypes.stream().anyMatch(DataType::isSpatialShape)) { + // Only aggregations over shapes are licensed under platinum. + return License.OperationMode.PLATINUM; + } + // All other field types are licensed under basic. + return License.OperationMode.BASIC; + } +} diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/aggregate/SpatialCentroidTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/aggregate/SpatialCentroidTests.java index a99cb8f60e3fa..25bb6e242cf8c 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/aggregate/SpatialCentroidTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/aggregate/SpatialCentroidTests.java @@ -14,6 +14,7 @@ import org.elasticsearch.geometry.Point; import org.elasticsearch.geometry.utils.GeometryValidator; import org.elasticsearch.geometry.utils.WellKnownBinary; +import org.elasticsearch.license.License; import org.elasticsearch.search.aggregations.metrics.CompensatedSum; import org.elasticsearch.xpack.esql.core.expression.Expression; import org.elasticsearch.xpack.esql.core.tree.Source; @@ -39,6 +40,10 @@ public SpatialCentroidTests(@Name("TestCase") Supplier fieldTypes) { + return SpatialAggregationTestCase.licenseRequirement(fieldTypes); + } + @ParametersFactory public static Iterable parameters() { var suppliers = Stream.of( diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/aggregate/SpatialExtentTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/aggregate/SpatialExtentTests.java index 9a0a62ce2d06e..a73a00741e3c5 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/aggregate/SpatialExtentTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/aggregate/SpatialExtentTests.java @@ -17,12 +17,12 @@ import org.elasticsearch.geometry.utils.SpatialEnvelopeVisitor; import org.elasticsearch.geometry.utils.SpatialEnvelopeVisitor.WrapLongitude; import org.elasticsearch.geometry.utils.WellKnownBinary; +import org.elasticsearch.license.License; import org.elasticsearch.test.hamcrest.RectangleMatcher; import org.elasticsearch.test.hamcrest.WellKnownBinaryBytesRefMatcher; import org.elasticsearch.xpack.esql.core.expression.Expression; import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.core.type.DataType; -import org.elasticsearch.xpack.esql.expression.function.AbstractAggregationTestCase; import org.elasticsearch.xpack.esql.expression.function.FunctionName; import org.elasticsearch.xpack.esql.expression.function.MultiRowTestCaseSupplier; import org.elasticsearch.xpack.esql.expression.function.MultiRowTestCaseSupplier.IncludingAltitude; @@ -33,11 +33,15 @@ import java.util.stream.Stream; @FunctionName("st_extent_agg") -public class SpatialExtentTests extends AbstractAggregationTestCase { +public class SpatialExtentTests extends SpatialAggregationTestCase { public SpatialExtentTests(@Name("TestCase") Supplier testCaseSupplier) { this.testCase = testCaseSupplier.get(); } + public static License.OperationMode licenseRequirement(List fieldTypes) { + return SpatialAggregationTestCase.licenseRequirement(fieldTypes); + } + @ParametersFactory public static Iterable parameters() { var suppliers = Stream.of( diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/grouping/CategorizeTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/grouping/CategorizeTests.java index dfdfd82d08afe..f69bb7eb3e7bb 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/grouping/CategorizeTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/grouping/CategorizeTests.java @@ -11,6 +11,7 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; +import org.elasticsearch.license.License; import org.elasticsearch.xpack.esql.core.expression.Expression; import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.core.type.DataType; @@ -34,6 +35,10 @@ public CategorizeTests(@Name("TestCase") Supplier tes this.testCase = testCaseSupplier.get(); } + public static License.OperationMode licenseRequirement(List fieldTypes) { + return License.OperationMode.PLATINUM; + } + @ParametersFactory public static Iterable parameters() { List suppliers = new ArrayList<>(); diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/RLikeTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/RLikeTests.java index 5578b2bfb1919..c2397f0340e67 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/RLikeTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/RLikeTests.java @@ -22,7 +22,6 @@ import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.junit.AfterClass; -import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.function.Function; @@ -155,7 +154,7 @@ static Expression buildRLike(Logger logger, Source source, List args } @AfterClass - public static void renderNotRLike() throws IOException { + public static void renderNotRLike() throws Exception { renderNegatedOperator(constructorWithFunctionInfo(RLike.class), "RLIKE", d -> d, getTestClass()); } } diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/WildcardLikeTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/WildcardLikeTests.java index f53ece7bca73d..eb548b085969b 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/WildcardLikeTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/WildcardLikeTests.java @@ -22,7 +22,6 @@ import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.junit.AfterClass; -import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.function.Supplier; @@ -92,7 +91,7 @@ static Expression buildWildcardLike(Source source, List args) { } @AfterClass - public static void renderNotLike() throws IOException { + public static void renderNotLike() throws Exception { renderNegatedOperator(constructorWithFunctionInfo(WildcardLike.class), "LIKE", d -> d, getTestClass()); } } diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/CastOperatorTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/CastOperatorTests.java index c1f5b9faed8e4..ff1f1f69a6590 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/CastOperatorTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/CastOperatorTests.java @@ -16,7 +16,6 @@ import org.elasticsearch.xpack.esql.expression.function.Param; import org.junit.AfterClass; -import java.io.IOException; import java.util.List; import java.util.Map; @@ -26,7 +25,7 @@ public void testDummy() { } @AfterClass - public static void renderDocs() throws IOException { + public static void renderDocs() throws Exception { if (System.getProperty("generateDocs") == null) { return; } diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/NullPredicatesTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/NullPredicatesTests.java index 7af61532fed4c..69bfcc99a21ea 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/NullPredicatesTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/NullPredicatesTests.java @@ -18,7 +18,6 @@ import org.elasticsearch.xpack.esql.expression.function.scalar.convert.ToStringTests; import org.junit.AfterClass; -import java.io.IOException; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -32,7 +31,7 @@ public void testDummy() { } @AfterClass - public static void renderDocs() throws IOException { + public static void renderDocs() throws Exception { if (System.getProperty("generateDocs") == null) { return; } @@ -62,7 +61,7 @@ public static void renderDocs() throws IOException { ); } - private static void renderNullPredicate(DocsV3Support.OperatorConfig op) throws IOException { + private static void renderNullPredicate(DocsV3Support.OperatorConfig op) throws Exception { var docs = new DocsV3Support.OperatorsDocsSupport(op.name(), NullPredicatesTests.class, op, NullPredicatesTests::signatures); docs.renderSignature(); docs.renderDocs(); diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/InTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/InTests.java index 8177ac22abaad..62e3e1577740f 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/InTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/InTests.java @@ -21,7 +21,6 @@ import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.junit.AfterClass; -import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -338,7 +337,7 @@ protected Expression build(Source source, List args) { } @AfterClass - public static void renderNotIn() throws IOException { + public static void renderNotIn() throws Exception { renderNegatedOperator( constructorWithFunctionInfo(In.class), "IN",