|
@@ -15,6 +15,7 @@ import org.elasticsearch.license.XPackLicenseState;
|
|
|
import org.elasticsearch.license.internal.XPackLicenseStatus;
|
|
|
import org.elasticsearch.test.ESTestCase;
|
|
|
import org.elasticsearch.xpack.esql.EsqlTestUtils;
|
|
|
+import org.elasticsearch.xpack.esql.LicenseAware;
|
|
|
import org.elasticsearch.xpack.esql.VerificationException;
|
|
|
import org.elasticsearch.xpack.esql.analysis.Analyzer;
|
|
|
import org.elasticsearch.xpack.esql.analysis.AnalyzerContext;
|
|
@@ -25,10 +26,12 @@ import org.elasticsearch.xpack.esql.core.tree.NodeInfo;
|
|
|
import org.elasticsearch.xpack.esql.core.tree.Source;
|
|
|
import org.elasticsearch.xpack.esql.core.type.DataType;
|
|
|
import org.elasticsearch.xpack.esql.parser.EsqlParser;
|
|
|
+import org.elasticsearch.xpack.esql.plan.logical.Limit;
|
|
|
import org.elasticsearch.xpack.esql.plan.logical.LogicalPlan;
|
|
|
import org.elasticsearch.xpack.esql.stats.Metrics;
|
|
|
|
|
|
import java.util.List;
|
|
|
+import java.util.Objects;
|
|
|
|
|
|
import static org.elasticsearch.xpack.esql.analysis.AnalyzerTestUtils.analyzerDefaultMapping;
|
|
|
import static org.elasticsearch.xpack.esql.analysis.AnalyzerTestUtils.defaultEnrichResolution;
|
|
@@ -44,25 +47,28 @@ public class CheckLicenseTests extends ESTestCase {
|
|
|
final LicensedFeature functionLicenseFeature = random().nextBoolean()
|
|
|
? LicensedFeature.momentary("test", "license", functionLicense)
|
|
|
: LicensedFeature.persistent("test", "license", functionLicense);
|
|
|
- final EsqlFunctionRegistry.FunctionBuilder builder = (source, expression, cfg) -> {
|
|
|
- final LicensedFunction licensedFunction = new LicensedFunction(source);
|
|
|
- licensedFunction.setLicensedFeature(functionLicenseFeature);
|
|
|
- return licensedFunction;
|
|
|
- };
|
|
|
for (License.OperationMode operationMode : License.OperationMode.values()) {
|
|
|
if (License.OperationMode.TRIAL != operationMode && License.OperationMode.compare(operationMode, functionLicense) < 0) {
|
|
|
// non-compliant license
|
|
|
- final VerificationException ex = expectThrows(VerificationException.class, () -> analyze(builder, operationMode));
|
|
|
- assertThat(ex.getMessage(), containsString("current license is non-compliant for function [license()]"));
|
|
|
+ final VerificationException ex = expectThrows(
|
|
|
+ VerificationException.class,
|
|
|
+ () -> analyze(operationMode, functionLicenseFeature)
|
|
|
+ );
|
|
|
+ assertThat(ex.getMessage(), containsString("current license is non-compliant for [license()]"));
|
|
|
+ assertThat(ex.getMessage(), containsString("current license is non-compliant for [LicensedLimit]"));
|
|
|
} else {
|
|
|
// compliant license
|
|
|
- assertNotNull(analyze(builder, operationMode));
|
|
|
+ assertNotNull(analyze(operationMode, functionLicenseFeature));
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private LogicalPlan analyze(EsqlFunctionRegistry.FunctionBuilder builder, License.OperationMode operationMode) {
|
|
|
+ private LogicalPlan analyze(License.OperationMode operationMode, LicensedFeature functionLicenseFeature) {
|
|
|
+ final EsqlFunctionRegistry.FunctionBuilder builder = (source, expression, cfg) -> new LicensedFunction(
|
|
|
+ source,
|
|
|
+ functionLicenseFeature
|
|
|
+ );
|
|
|
final FunctionDefinition def = EsqlFunctionRegistry.def(LicensedFunction.class, builder, "license");
|
|
|
final EsqlFunctionRegistry registry = new EsqlFunctionRegistry(def) {
|
|
|
@Override
|
|
@@ -70,7 +76,13 @@ public class CheckLicenseTests extends ESTestCase {
|
|
|
return this;
|
|
|
}
|
|
|
};
|
|
|
- return analyzer(registry, operationMode).analyze(parser.createStatement(esql));
|
|
|
+
|
|
|
+ var plan = parser.createStatement(esql);
|
|
|
+ plan = plan.transformDown(
|
|
|
+ Limit.class,
|
|
|
+ l -> Objects.equals(l.limit().fold(), 10) ? new LicensedLimit(l.source(), l.limit(), l.child(), functionLicenseFeature) : l
|
|
|
+ );
|
|
|
+ return analyzer(registry, operationMode).analyze(plan);
|
|
|
}
|
|
|
|
|
|
private static Analyzer analyzer(EsqlFunctionRegistry registry, License.OperationMode operationMode) {
|
|
@@ -88,25 +100,18 @@ public class CheckLicenseTests extends ESTestCase {
|
|
|
|
|
|
// It needs to be public because we run validation on it via reflection in org.elasticsearch.xpack.esql.tree.EsqlNodeSubclassTests.
|
|
|
// This test prevents to add the license as constructor parameter too.
|
|
|
- public static class LicensedFunction extends Function {
|
|
|
+ public static class LicensedFunction extends Function implements LicenseAware {
|
|
|
|
|
|
- private LicensedFeature licensedFeature;
|
|
|
+ private final LicensedFeature licensedFeature;
|
|
|
|
|
|
- public LicensedFunction(Source source) {
|
|
|
+ public LicensedFunction(Source source, LicensedFeature licensedFeature) {
|
|
|
super(source, List.of());
|
|
|
- }
|
|
|
-
|
|
|
- void setLicensedFeature(LicensedFeature licensedFeature) {
|
|
|
this.licensedFeature = licensedFeature;
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public boolean checkLicense(XPackLicenseState state) {
|
|
|
- if (licensedFeature instanceof LicensedFeature.Momentary momentary) {
|
|
|
- return momentary.check(state);
|
|
|
- } else {
|
|
|
- return licensedFeature.checkWithoutTracking(state);
|
|
|
- }
|
|
|
+ public boolean licenseCheck(XPackLicenseState state) {
|
|
|
+ return checkLicense(state, licensedFeature);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
@@ -121,7 +126,7 @@ public class CheckLicenseTests extends ESTestCase {
|
|
|
|
|
|
@Override
|
|
|
protected NodeInfo<? extends Expression> info() {
|
|
|
- return NodeInfo.create(this);
|
|
|
+ return NodeInfo.create(this, LicensedFunction::new, licensedFeature);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
@@ -135,4 +140,39 @@ public class CheckLicenseTests extends ESTestCase {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ public static class LicensedLimit extends Limit implements LicenseAware {
|
|
|
+
|
|
|
+ private final LicensedFeature licensedFeature;
|
|
|
+
|
|
|
+ public LicensedLimit(Source source, Expression limit, LogicalPlan child, LicensedFeature licensedFeature) {
|
|
|
+ super(source, limit, child);
|
|
|
+ this.licensedFeature = licensedFeature;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean licenseCheck(XPackLicenseState state) {
|
|
|
+ return checkLicense(state, licensedFeature);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Limit replaceChild(LogicalPlan newChild) {
|
|
|
+ return new LicensedLimit(source(), limit(), newChild, licensedFeature);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected NodeInfo<Limit> info() {
|
|
|
+ return NodeInfo.create(this, LicensedLimit::new, limit(), child(), licensedFeature);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String sourceText() {
|
|
|
+ return "LicensedLimit";
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static boolean checkLicense(XPackLicenseState state, LicensedFeature licensedFeature) {
|
|
|
+ return licensedFeature instanceof LicensedFeature.Momentary momentary
|
|
|
+ ? momentary.check(state)
|
|
|
+ : licensedFeature.checkWithoutTracking(state);
|
|
|
+ }
|
|
|
}
|