diff --git a/docs/changelog/109042.yaml b/docs/changelog/109042.yaml new file mode 100644 index 0000000000000..5aa80db991c0d --- /dev/null +++ b/docs/changelog/109042.yaml @@ -0,0 +1,5 @@ +pr: 109042 +summary: Add Create or update query rule API call +area: Application +type: enhancement +issues: [ ] diff --git a/rest-api-spec/src/main/resources/rest-api-spec/api/query_rule.put.json b/rest-api-spec/src/main/resources/rest-api-spec/api/query_rule.put.json new file mode 100644 index 0000000000000..895f3654b1622 --- /dev/null +++ b/rest-api-spec/src/main/resources/rest-api-spec/api/query_rule.put.json @@ -0,0 +1,42 @@ +{ + "query_rule.put": { + "documentation": { + "url": "https://www.elastic.co/guide/en/elasticsearch/reference/master/put-query-rule.html", + "description": "Creates or updates a query rule within a ruleset." + }, + "stability": "experimental", + "visibility": "public", + "headers": { + "accept": [ + "application/json" + ], + "content_type": [ + "application/json" + ] + }, + "url": { + "paths": [ + { + "path": "/_query_rules/{ruleset_id}/{rule_id}", + "methods": [ + "PUT" + ], + "parts": { + "ruleset_id": { + "type": "string", + "description": "The unique identifier of the ruleset this rule should be added to. The ruleset will be created if it does not exist." + }, + "rule_id": { + "type": "string", + "description": "The unique identifier of the rule to be created or updated." + } + } + } + ] + }, + "body": { + "description": "The query rule configuration, including the type of rule, the criteria to match the rule, and the action that should be taken if the rule matches.", + "required": true + } + } +} diff --git a/server/src/main/java/org/elasticsearch/TransportVersions.java b/server/src/main/java/org/elasticsearch/TransportVersions.java index e6b98971ff8cb..c2be2da12534b 100644 --- a/server/src/main/java/org/elasticsearch/TransportVersions.java +++ b/server/src/main/java/org/elasticsearch/TransportVersions.java @@ -187,6 +187,7 @@ static TransportVersion def(int id) { public static final TransportVersion RANK_FEATURE_PHASE_ADDED = def(8_678_00_0); public static final TransportVersion RANK_DOC_IN_SHARD_FETCH_REQUEST = def(8_679_00_0); public static final TransportVersion SECURITY_SETTINGS_REQUEST_TIMEOUTS = def(8_680_00_0); + public static final TransportVersion QUERY_RULE_CRUD_API_PUT = def(8_681_00_0); /* * STOP! READ THIS FIRST! No, really, diff --git a/x-pack/plugin/ent-search/qa/rest/build.gradle b/x-pack/plugin/ent-search/qa/rest/build.gradle index 37f1d8f13c850..c24b0ffd44c65 100644 --- a/x-pack/plugin/ent-search/qa/rest/build.gradle +++ b/x-pack/plugin/ent-search/qa/rest/build.gradle @@ -7,7 +7,20 @@ dependencies { restResources { restApi { - include '_common', 'bulk', 'cluster', 'connector', 'nodes', 'indices', 'index', 'query_ruleset', 'search_application', 'xpack', 'security', 'search', 'ml' + include '_common', + 'bulk', + 'cluster', + 'connector', + 'nodes', + 'indices', + 'index', + 'query_ruleset', + 'query_rule', + 'search_application', + 'xpack', + 'security', + 'search', + 'ml' } } diff --git a/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/rules/10_query_ruleset_put.yml b/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/rules/10_query_ruleset_put.yml index 7868919dd6d1f..f3f37e41ec756 100644 --- a/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/rules/10_query_ruleset_put.yml +++ b/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/rules/10_query_ruleset_put.yml @@ -1,9 +1,20 @@ - setup: - requires: - cluster_features: ["gte_v8.10.0"] + cluster_features: [ "gte_v8.10.0" ] reason: Introduced in 8.10.0 +--- +teardown: + - do: + query_ruleset.delete: + ruleset_id: test-ruleset + ignore: 404 + + - do: + query_ruleset.delete: + ruleset_id: test-query-ruleset-recreating + ignore: 404 + --- 'Create Query Ruleset': - do: @@ -16,7 +27,7 @@ setup: criteria: - type: exact metadata: query_string - values: [elastic] + values: [ elastic ] actions: ids: - 'id1' @@ -26,7 +37,7 @@ setup: criteria: - type: exact metadata: query_string - values: [kibana] + values: [ kibana ] actions: docs: - '_index': 'test-index1' @@ -47,7 +58,7 @@ setup: criteria: - type: exact metadata: query_string - values: [elastic] + values: [ elastic ] actions: ids: - 'id1' @@ -57,7 +68,7 @@ setup: criteria: - type: exact metadata: query_string - values: [kibana] + values: [ kibana ] actions: docs: - '_index': 'test-index1' @@ -77,7 +88,7 @@ setup: criteria: type: 'exact' metadata: 'query_string' - values: ['elastic'] + values: [ 'elastic' ] actions: ids: - 'id1' @@ -94,7 +105,7 @@ setup: criteria: type: 'exact' metadata: 'query_string' - values: ['elastic'] + values: [ 'elastic' ] actions: ids: - 'id2' @@ -118,7 +129,7 @@ setup: criteria: type: 'exact' metadata: 'query_string' - values: ['elastic'] + values: [ 'elastic' ] actions: ids: - 'id1' diff --git a/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/rules/20_query_ruleset_list.yml b/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/rules/20_query_ruleset_list.yml index 0183dc8930d75..b30f1c2418f4f 100644 --- a/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/rules/20_query_ruleset_list.yml +++ b/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/rules/20_query_ruleset_list.yml @@ -1,6 +1,6 @@ setup: - requires: - cluster_features: ["gte_v8.10.0"] + cluster_features: [ "gte_v8.10.0" ] reason: Introduced in 8.10.0 - do: query_ruleset.put: @@ -12,7 +12,7 @@ setup: criteria: - type: exact metadata: query_string - values: [elastic] + values: [ elastic ] actions: ids: - 'id1' @@ -22,7 +22,7 @@ setup: criteria: - type: exact metadata: query_string - values: [kibana] + values: [ kibana ] actions: ids: - 'id3' @@ -38,7 +38,7 @@ setup: criteria: - type: exact metadata: query_string - values: [elastic] + values: [ elastic ] actions: ids: - 'id1' @@ -48,7 +48,7 @@ setup: criteria: - type: exact metadata: query_string - values: [kibana] + values: [ kibana ] actions: ids: - 'id3' @@ -58,7 +58,7 @@ setup: criteria: - type: exact metadata: query_string - values: [logstash] + values: [ logstash ] actions: ids: - 'id5' @@ -74,7 +74,7 @@ setup: criteria: - type: exact metadata: query_string - values: [elastic] + values: [ elastic ] actions: ids: - 'id1' @@ -84,7 +84,7 @@ setup: criteria: - type: exact metadata: query_string - values: [kibana] + values: [ kibana ] actions: ids: - 'id3' @@ -94,7 +94,7 @@ setup: criteria: - type: exact metadata: query_string - values: [logstash] + values: [ logstash ] actions: ids: - 'id5' @@ -104,11 +104,32 @@ setup: criteria: - type: exact metadata: query_string - values: [beats] + values: [ beats ] actions: ids: - 'id7' - 'id8' +--- +teardown: + - do: + query_ruleset.delete: + ruleset_id: test-query-ruleset-1 + ignore: 404 + + - do: + query_ruleset.delete: + ruleset_id: test-query-ruleset-2 + ignore: 404 + + - do: + query_ruleset.delete: + ruleset_id: test-query-ruleset-3 + ignore: 404 + + - do: + query_ruleset.delete: + ruleset_id: a-test-query-ruleset-with-lots-of-criteria + ignore: 404 --- "List Query Rulesets": @@ -263,3 +284,16 @@ setup: prefix: 1 suffix: 1 always: 1 + +--- +'List Query Rulesets - Insufficient privilege': + - skip: + features: headers + + - do: + catch: forbidden + headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user + query_ruleset.list: { } + + - match: { error.type: 'security_exception' } + diff --git a/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/rules/30_query_ruleset_delete.yml b/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/rules/30_query_ruleset_delete.yml index cfc847b33f665..81e3e6c8411f7 100644 --- a/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/rules/30_query_ruleset_delete.yml +++ b/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/rules/30_query_ruleset_delete.yml @@ -1,6 +1,6 @@ setup: - requires: - cluster_features: ["gte_v8.10.0"] + cluster_features: [ "gte_v8.10.0" ] reason: Introduced in 8.10.0 - do: query_ruleset.put: @@ -12,7 +12,7 @@ setup: criteria: - type: exact metadata: query_string - values: [elastic] + values: [ elastic ] actions: ids: - 'id1' @@ -37,3 +37,16 @@ setup: catch: "missing" query_ruleset.delete: ruleset_id: test-nonexistent-query-ruleset + +--- +'Delete Query Ruleset - Insufficient privilege': + - skip: + features: headers + + - do: + catch: forbidden + headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user + query_ruleset.delete: + ruleset_id: test-query-ruleset-to-delete + + - match: { error.type: 'security_exception' } diff --git a/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/rules/40_rule_query_search.yml b/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/rules/40_rule_query_search.yml index 5b67f966bba68..bfd4c5e8a831e 100644 --- a/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/rules/40_rule_query_search.yml +++ b/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/rules/40_rule_query_search.yml @@ -98,6 +98,23 @@ setup: ids: - 'doc6' +--- +teardown: + - do: + query_ruleset.delete: + ruleset_id: test-ruleset + ignore: 404 + + - do: + query_ruleset.delete: + ruleset_id: another-test-ruleset + ignore: 404 + + - do: + query_ruleset.delete: + ruleset_id: combined-ruleset + ignore: 404 + --- "Perform a rule query specifying a ruleset that does not exist": - do: diff --git a/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/rules/50_query_rule_put.yml b/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/rules/50_query_rule_put.yml new file mode 100644 index 0000000000000..64a933261af90 --- /dev/null +++ b/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/rules/50_query_rule_put.yml @@ -0,0 +1,266 @@ +setup: + - requires: + cluster_features: [ "gte_v8.15.0" ] + reason: Introduced in 8.15.0 + + +--- +teardown: + - do: + query_ruleset.delete: + ruleset_id: test-ruleset + ignore: 404 + + - do: + query_ruleset.delete: + ruleset_id: test-query-rule-recreating + ignore: 404 + + - do: + query_ruleset.delete: + ruleset_id: forbidden-query-ruleset + ignore: 404 + +--- +'Create query rule with existing ruleset respecting priority order': + # Start with 2 rules, one that specifies priority and one that does not (should go at the end) + - do: + query_ruleset.put: + ruleset_id: test-ruleset + body: + rules: + - rule_id: query-rule-id1 + type: pinned + criteria: + - type: exact + metadata: query_string + values: [ elastic ] + actions: + ids: + - 'id1' + - 'id2' + - rule_id: query-rule-id2 + type: pinned + criteria: + - type: exact + metadata: query_string + values: [ kibana ] + actions: + ids: + - 'id3' + - 'id4' + priority: 1 + + - match: { result: 'created' } + + - do: + query_ruleset.get: + ruleset_id: test-ruleset + + - match: { ruleset_id: test-ruleset } + - match: + rules: + - rule_id: query-rule-id2 + type: pinned + criteria: + - type: exact + metadata: query_string + values: [ kibana ] + actions: + ids: + - 'id3' + - 'id4' + priority: 1 + - rule_id: query-rule-id1 + type: pinned + criteria: + - type: exact + metadata: query_string + values: [ elastic ] + actions: + ids: + - 'id1' + - 'id2' + + # Next, add a rule with a priority 2 - this should go in the middle + - do: + query_rule.put: + ruleset_id: test-ruleset + rule_id: query-rule-id3 + body: + type: 'pinned' + criteria: + type: 'exact' + metadata: 'query_string' + values: [ 'logstash' ] + actions: + ids: + - 'id1' + priority: 2 + + - match: { result: 'created' } + + - do: + query_ruleset.get: + ruleset_id: test-ruleset + + - match: { ruleset_id: test-ruleset } + - match: + rules: + - rule_id: query-rule-id2 + type: pinned + criteria: + - type: exact + metadata: query_string + values: [ kibana ] + actions: + ids: + - 'id3' + - 'id4' + priority: 1 + - rule_id: query-rule-id3 + type: pinned + criteria: + - type: exact + metadata: query_string + values: [ logstash ] + actions: + ids: + - 'id1' + priority: 2 + - rule_id: query-rule-id1 + type: pinned + criteria: + - type: exact + metadata: query_string + values: [ elastic ] + actions: + ids: + - 'id1' + - 'id2' + + # Finally, add another single rule with no priority. This should be appended to the ruleset. + - do: + query_rule.put: + ruleset_id: test-ruleset + rule_id: query-rule-id4 + body: + type: 'pinned' + criteria: + type: 'exact' + metadata: 'query_string' + values: [ 'search' ] + actions: + ids: + - 'id2' + + - match: { result: 'created' } + + - do: + query_ruleset.get: + ruleset_id: test-ruleset + + - match: { ruleset_id: test-ruleset } + - match: + rules: + - rule_id: query-rule-id2 + type: pinned + criteria: + - type: exact + metadata: query_string + values: [ kibana ] + actions: + ids: + - 'id3' + - 'id4' + priority: 1 + - rule_id: query-rule-id3 + type: pinned + criteria: + - type: exact + metadata: query_string + values: [ logstash ] + actions: + ids: + - 'id1' + priority: 2 + - rule_id: query-rule-id1 + type: pinned + criteria: + - type: exact + metadata: query_string + values: [ elastic ] + actions: + ids: + - 'id1' + - 'id2' + - rule_id: query-rule-id4 + type: pinned + criteria: + - type: exact + metadata: query_string + values: [ search ] + actions: + ids: + - 'id2' + + +--- +'Create Query Rule - Resource already exists': + - do: + query_rule.put: + ruleset_id: test-query-rule-recreating + rule_id: abc + body: + type: 'pinned' + criteria: + type: 'exact' + metadata: 'query_string' + values: [ 'elastic' ] + actions: + ids: + - 'id1' + priority: 5 + + - match: { result: 'created' } + + - do: + query_rule.put: + ruleset_id: test-query-rule-recreating + rule_id: abc + body: + type: 'pinned' + criteria: + type: 'exact' + metadata: 'query_string' + values: [ 'elastic' ] + actions: + ids: + - 'id2' + priority: 3 + + - match: { result: 'updated' } + +--- +'Create Query Rule - Insufficient privilege': + - skip: + features: headers + + - do: + catch: forbidden + headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user + query_rule.put: + ruleset_id: forbidden-query-ruleset + rule_id: abc + body: + type: 'pinned' + criteria: + type: 'exact' + metadata: 'query_string' + values: [ 'elastic' ] + actions: + ids: + - 'id1' + - 'id2' + + - match: { error.type: 'security_exception' } diff --git a/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/EnterpriseSearch.java b/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/EnterpriseSearch.java index 871bf7fb122b9..9572eb599f2de 100644 --- a/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/EnterpriseSearch.java +++ b/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/EnterpriseSearch.java @@ -151,14 +151,17 @@ import org.elasticsearch.xpack.application.rules.action.DeleteQueryRulesetAction; import org.elasticsearch.xpack.application.rules.action.GetQueryRulesetAction; import org.elasticsearch.xpack.application.rules.action.ListQueryRulesetsAction; +import org.elasticsearch.xpack.application.rules.action.PutQueryRuleAction; import org.elasticsearch.xpack.application.rules.action.PutQueryRulesetAction; import org.elasticsearch.xpack.application.rules.action.RestDeleteQueryRulesetAction; import org.elasticsearch.xpack.application.rules.action.RestGetQueryRulesetAction; import org.elasticsearch.xpack.application.rules.action.RestListQueryRulesetsAction; +import org.elasticsearch.xpack.application.rules.action.RestPutQueryRuleAction; import org.elasticsearch.xpack.application.rules.action.RestPutQueryRulesetAction; import org.elasticsearch.xpack.application.rules.action.TransportDeleteQueryRulesetAction; import org.elasticsearch.xpack.application.rules.action.TransportGetQueryRulesetAction; import org.elasticsearch.xpack.application.rules.action.TransportListQueryRulesetsAction; +import org.elasticsearch.xpack.application.rules.action.TransportPutQueryRuleAction; import org.elasticsearch.xpack.application.rules.action.TransportPutQueryRulesetAction; import org.elasticsearch.xpack.application.search.SearchApplicationIndexService; import org.elasticsearch.xpack.application.search.action.DeleteSearchApplicationAction; @@ -251,6 +254,7 @@ protected XPackLicenseState getLicenseState() { new ActionHandler<>(GetQueryRulesetAction.INSTANCE, TransportGetQueryRulesetAction.class), new ActionHandler<>(ListQueryRulesetsAction.INSTANCE, TransportListQueryRulesetsAction.class), new ActionHandler<>(PutQueryRulesetAction.INSTANCE, TransportPutQueryRulesetAction.class), + new ActionHandler<>(PutQueryRuleAction.INSTANCE, TransportPutQueryRuleAction.class), usageAction, infoAction @@ -354,7 +358,8 @@ public List getRestHandlers( new RestDeleteQueryRulesetAction(getLicenseState()), new RestGetQueryRulesetAction(getLicenseState()), new RestListQueryRulesetsAction(getLicenseState()), - new RestPutQueryRulesetAction(getLicenseState()) + new RestPutQueryRulesetAction(getLicenseState()), + new RestPutQueryRuleAction(getLicenseState()) ) ); diff --git a/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/QueryRule.java b/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/QueryRule.java index b9093a2597d7d..33fa74e5178cf 100644 --- a/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/QueryRule.java +++ b/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/QueryRule.java @@ -8,12 +8,14 @@ package org.elasticsearch.xpack.application.rules; import org.elasticsearch.ElasticsearchParseException; +import org.elasticsearch.TransportVersions; import org.elasticsearch.common.Strings; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.common.xcontent.XContentHelper; +import org.elasticsearch.core.Nullable; import org.elasticsearch.xcontent.ConstructingObjectParser; import org.elasticsearch.xcontent.ParseField; import org.elasticsearch.xcontent.ToXContentObject; @@ -53,6 +55,10 @@ public class QueryRule implements Writeable, ToXContentObject { private final QueryRuleType type; private final List criteria; private final Map actions; + private final Integer priority; + + public static final int MIN_PRIORITY = 0; + public static final int MAX_PRIORITY = 1000000; public enum QueryRuleType { PINNED; @@ -79,11 +85,17 @@ public String toString() { * @param type The {@link QueryRuleType} of this rule * @param criteria The {@link QueryRuleCriteria} required for a query to match this rule * @param actions The actions that should be taken if this rule is matched, dependent on the type of rule + * @param priority If specified, assigns a priority to the rule. Rules with specified priorities are applied before + * rules without specified priorities, in ascending priority order. */ - public QueryRule(String id, QueryRuleType type, List criteria, Map actions) { - if (Strings.isNullOrEmpty(id)) { - throw new IllegalArgumentException("Query rule id cannot be null or blank"); - } + public QueryRule( + @Nullable String id, + QueryRuleType type, + List criteria, + Map actions, + @Nullable Integer priority + ) { + // Interstitial null state allowed during rule creation; validation occurs in CRUD API this.id = id; Objects.requireNonNull(type, "Query rule type cannot be null"); @@ -100,16 +112,27 @@ public QueryRule(String id, QueryRuleType type, List criteria throw new IllegalArgumentException("Query rule actions cannot be empty"); } this.actions = actions; + this.priority = priority; validate(); } + public QueryRule(String id, QueryRule other) { + this(id, other.type, other.criteria, other.actions, other.priority); + } + public QueryRule(StreamInput in) throws IOException { this.id = in.readString(); this.type = QueryRuleType.queryRuleType(in.readString()); this.criteria = in.readCollectionAsList(QueryRuleCriteria::new); this.actions = in.readGenericMap(); + if (in.getTransportVersion().onOrAfter(TransportVersions.QUERY_RULE_CRUD_API_PUT)) { + this.priority = in.readOptionalVInt(); + } else { + this.priority = null; + } + validate(); } @@ -126,6 +149,10 @@ private void validate() { } else { throw new IllegalArgumentException("Unsupported QueryRuleType: " + type); } + + if (priority != null && (priority < MIN_PRIORITY || priority > MAX_PRIORITY)) { + throw new IllegalArgumentException("Priority was " + priority + ", must be between " + MIN_PRIORITY + " and " + MAX_PRIORITY); + } } private void validatePinnedAction(Object action) { @@ -146,6 +173,9 @@ public void writeTo(StreamOutput out) throws IOException { out.writeString(type.toString()); out.writeCollection(criteria); out.writeGenericMap(actions); + if (out.getTransportVersion().onOrAfter(TransportVersions.QUERY_RULE_CRUD_API_PUT)) { + out.writeOptionalVInt(priority); + } } @SuppressWarnings("unchecked") @@ -157,7 +187,8 @@ public void writeTo(StreamOutput out) throws IOException { final QueryRuleType type = QueryRuleType.queryRuleType((String) params[1]); final List criteria = (List) params[2]; final Map actions = (Map) params[3]; - return new QueryRule(id, type, criteria, actions); + final Integer priority = (Integer) params[4]; + return new QueryRule(id, type, criteria, actions, priority); } ); @@ -165,12 +196,14 @@ public void writeTo(StreamOutput out) throws IOException { public static final ParseField TYPE_FIELD = new ParseField("type"); public static final ParseField CRITERIA_FIELD = new ParseField("criteria"); public static final ParseField ACTIONS_FIELD = new ParseField("actions"); + public static final ParseField PRIORITY_FIELD = new ParseField("priority"); static { PARSER.declareStringOrNull(optionalConstructorArg(), ID_FIELD); PARSER.declareString(constructorArg(), TYPE_FIELD); PARSER.declareObjectArray(constructorArg(), (p, c) -> QueryRuleCriteria.fromXContent(p), CRITERIA_FIELD); PARSER.declareObject(constructorArg(), (p, c) -> p.map(), ACTIONS_FIELD); + PARSER.declareInt(optionalConstructorArg(), PRIORITY_FIELD); } /** @@ -213,7 +246,9 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws builder.xContentList(CRITERIA_FIELD.getPreferredName(), criteria); builder.field(ACTIONS_FIELD.getPreferredName()); builder.map(actions); - + if (priority != null) { + builder.field(PRIORITY_FIELD.getPreferredName(), priority); + } } builder.endObject(); return builder; @@ -255,6 +290,10 @@ public Map actions() { return actions; } + public Integer priority() { + return priority; + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -263,12 +302,13 @@ public boolean equals(Object o) { return Objects.equals(id, queryRule.id) && type == queryRule.type && Objects.equals(criteria, queryRule.criteria) - && Objects.equals(actions, queryRule.actions); + && Objects.equals(actions, queryRule.actions) + && Objects.equals(priority, queryRule.priority); } @Override public int hashCode() { - return Objects.hash(id, type, criteria, actions); + return Objects.hash(id, type, criteria, actions, priority); } @Override diff --git a/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/QueryRulesIndexService.java b/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/QueryRulesIndexService.java index 1e98755cc7acf..adcd5da988b82 100644 --- a/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/QueryRulesIndexService.java +++ b/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/QueryRulesIndexService.java @@ -23,6 +23,7 @@ import org.elasticsearch.client.internal.Client; import org.elasticsearch.client.internal.OriginSettingClient; import org.elasticsearch.cluster.metadata.IndexMetadata; +import org.elasticsearch.common.VersionId; import org.elasticsearch.common.settings.ClusterSettings; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Settings; @@ -37,17 +38,20 @@ import org.elasticsearch.search.sort.SortOrder; import org.elasticsearch.xcontent.ToXContent; import org.elasticsearch.xcontent.XContentBuilder; +import org.elasticsearch.xpack.application.rules.action.PutQueryRuleAction; import java.io.IOException; import java.io.UncheckedIOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.Comparator; import java.util.EnumMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.function.Function; import java.util.stream.Collectors; import static org.elasticsearch.xcontent.XContentFactory.jsonBuilder; @@ -60,9 +64,9 @@ public class QueryRulesIndexService { private static final Logger logger = LogManager.getLogger(QueryRulesIndexService.class); public static final String QUERY_RULES_ALIAS_NAME = ".query-rules"; - public static final String QUERY_RULES_CONCRETE_INDEX_NAME = ".query-rules-1"; + public static final String QUERY_RULES_INDEX_PREFIX = ".query-rules-"; + public static final String QUERY_RULES_CONCRETE_INDEX_NAME = QUERY_RULES_INDEX_PREFIX + QueryRulesIndexMappingVersion.latest().id; public static final String QUERY_RULES_INDEX_NAME_PATTERN = ".query-rules-*"; - private static final int QUERY_RULES_INDEX_MAPPINGS_VERSION = 1; private final Client clientWithOrigin; private final ClusterSettings clusterSettings; @@ -77,16 +81,21 @@ public QueryRulesIndexService(Client client, ClusterSettings clusterSettings) { * @return The {@link SystemIndexDescriptor} for the {@link QueryRuleset} system index. */ public static SystemIndexDescriptor getSystemIndexDescriptor() { - return SystemIndexDescriptor.builder() - .setIndexPattern(QUERY_RULES_INDEX_NAME_PATTERN) - .setPrimaryIndex(QUERY_RULES_CONCRETE_INDEX_NAME) - .setDescription("Contains query ruleset configuration for query rules") - .setMappings(getIndexMappings()) - .setSettings(getIndexSettings()) - .setAliasName(QUERY_RULES_ALIAS_NAME) - .setVersionMetaKey("version") - .setOrigin(ENT_SEARCH_ORIGIN) - .setThreadPools(ExecutorNames.DEFAULT_SYSTEM_INDEX_THREAD_POOLS) + final Function systemIndexDescriptorBuilder = + mappingVersion -> SystemIndexDescriptor.builder() + .setIndexPattern(QUERY_RULES_INDEX_NAME_PATTERN) + .setPrimaryIndex(QUERY_RULES_CONCRETE_INDEX_NAME) + .setDescription("Contains query ruleset configuration for query rules") + .setMappings(getIndexMappings(mappingVersion)) + .setSettings(getIndexSettings()) + .setAliasName(QUERY_RULES_ALIAS_NAME) + .setIndexFormat(QueryRulesIndexMappingVersion.latest().id) + .setVersionMetaKey("version") + .setOrigin(ENT_SEARCH_ORIGIN) + .setThreadPools(ExecutorNames.DEFAULT_SYSTEM_INDEX_THREAD_POOLS); + + return systemIndexDescriptorBuilder.apply(QueryRulesIndexMappingVersion.latest()) + .setPriorSystemIndexDescriptors(List.of(systemIndexDescriptorBuilder.apply(QueryRulesIndexMappingVersion.INITIAL).build())) .build(); } @@ -96,18 +105,19 @@ private static Settings getIndexSettings() { .put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0) .put(IndexMetadata.SETTING_AUTO_EXPAND_REPLICAS, "0-1") .put(IndexMetadata.SETTING_PRIORITY, 100) + .put(IndexMetadata.INDEX_FORMAT_SETTING.getKey(), QueryRulesIndexMappingVersion.latest().id) .put("index.refresh_interval", "1s") .build(); } - private static XContentBuilder getIndexMappings() { + private static XContentBuilder getIndexMappings(QueryRulesIndexMappingVersion version) { try { final XContentBuilder builder = jsonBuilder(); builder.startObject(); { builder.startObject("_meta"); builder.field("version", Version.CURRENT.toString()); - builder.field(SystemIndexDescriptor.VERSION_META_KEY, QUERY_RULES_INDEX_MAPPINGS_VERSION); + builder.field(SystemIndexDescriptor.VERSION_META_KEY, version.id); builder.endObject(); builder.field("dynamic", "strict"); @@ -151,6 +161,12 @@ private static XContentBuilder getIndexMappings() { builder.field("type", "object"); builder.field("enabled", false); builder.endObject(); + + if (version.onOrAfter(QueryRulesIndexMappingVersion.ADD_PRIORITY)) { + builder.startObject(QueryRule.PRIORITY_FIELD.getPreferredName()); + builder.field("type", "integer"); + builder.endObject(); + } } builder.endObject(); builder.endObject(); @@ -191,7 +207,8 @@ public void onResponse(GetResponse getResponse) { (String) rule.get(QueryRule.ID_FIELD.getPreferredName()), QueryRuleType.queryRuleType((String) rule.get(QueryRule.TYPE_FIELD.getPreferredName())), parseCriteria((List>) rule.get(QueryRule.CRITERIA_FIELD.getPreferredName())), - (Map) rule.get(QueryRule.ACTIONS_FIELD.getPreferredName()) + (Map) rule.get(QueryRule.ACTIONS_FIELD.getPreferredName()), + (Integer) rule.get(QueryRule.PRIORITY_FIELD.getPreferredName()) ) ) .collect(Collectors.toList()); @@ -243,7 +260,45 @@ public void putQueryRuleset(QueryRuleset queryRuleset, ActionListener listener) { + getQueryRuleset(queryRulesetId, new ActionListener<>() { + @Override + public void onResponse(QueryRuleset queryRuleset) { + final List rules = new ArrayList<>(queryRuleset.rules()).stream() + .filter(rule -> rule.id().equals(queryRule.id()) == false) + .collect(Collectors.toList()); + rules.add(queryRule); + final boolean created = queryRuleset.rules().stream().noneMatch(rule -> rule.id().equals(queryRule.id())); + + putQueryRuleset(new QueryRuleset(queryRulesetId, rules), listener.delegateFailureAndWrap((delegate, docWriteResponse) -> { + DocWriteResponse.Result result = created ? DocWriteResponse.Result.CREATED : docWriteResponse.getResult(); + delegate.onResponse(new PutQueryRuleAction.Response(result)); + })); + } + @Override + public void onFailure(Exception e) { + if (e instanceof ResourceNotFoundException) { + putQueryRuleset( + new QueryRuleset(queryRulesetId, List.of(queryRule)), + listener.delegateFailureAndWrap((delegate, docWriteResponse) -> { + delegate.onResponse(new PutQueryRuleAction.Response(DocWriteResponse.Result.CREATED)); + }) + ); + return; + } + listener.onFailure(e); + } + }); } private void validateQueryRuleset(QueryRuleset queryRuleset) { @@ -355,4 +410,28 @@ private static QueryRulesetListItem hitToQueryRulesetListItem(SearchHit searchHi } public record QueryRulesetResult(List rulesets, long totalResults) {} + + public enum QueryRulesIndexMappingVersion implements VersionId { + INITIAL(1), + ADD_PRIORITY(2),; + + private static final QueryRulesIndexMappingVersion LATEST = Arrays.stream(values()) + .max(Comparator.comparingInt(v -> v.id)) + .orElseThrow(); + + private final int id; + + QueryRulesIndexMappingVersion(int id) { + this.id = id; + } + + @Override + public int id() { + return id; + } + + public static QueryRulesIndexMappingVersion latest() { + return LATEST; + } + } } diff --git a/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/QueryRuleset.java b/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/QueryRuleset.java index f58d01e7afe71..6ce93113cee0e 100644 --- a/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/QueryRuleset.java +++ b/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/QueryRuleset.java @@ -23,8 +23,10 @@ import org.elasticsearch.xcontent.XContentType; import java.io.IOException; +import java.util.Comparator; import java.util.List; import java.util.Objects; +import java.util.stream.Collectors; import static org.elasticsearch.xcontent.ConstructingObjectParser.constructorArg; import static org.elasticsearch.xcontent.ConstructingObjectParser.optionalConstructorArg; @@ -51,7 +53,9 @@ public QueryRuleset(String id, List rules) { if (rules.isEmpty()) { throw new IllegalArgumentException("rules cannot be empty"); } - this.rules = rules; + this.rules = rules.stream() + .sorted(Comparator.comparing(QueryRule::priority, Comparator.nullsLast(Comparator.naturalOrder()))) + .collect(Collectors.toList()); } public QueryRuleset(StreamInput in) throws IOException { diff --git a/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/action/PutQueryRuleAction.java b/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/action/PutQueryRuleAction.java new file mode 100644 index 0000000000000..75ab19ce8dffe --- /dev/null +++ b/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/action/PutQueryRuleAction.java @@ -0,0 +1,198 @@ +/* + * 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.application.rules.action; + +import org.elasticsearch.action.ActionRequest; +import org.elasticsearch.action.ActionRequestValidationException; +import org.elasticsearch.action.ActionResponse; +import org.elasticsearch.action.ActionType; +import org.elasticsearch.action.DocWriteResponse; +import org.elasticsearch.common.Strings; +import org.elasticsearch.common.bytes.BytesReference; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.rest.RestStatus; +import org.elasticsearch.xcontent.ConstructingObjectParser; +import org.elasticsearch.xcontent.ParseField; +import org.elasticsearch.xcontent.ToXContentObject; +import org.elasticsearch.xcontent.XContentBuilder; +import org.elasticsearch.xcontent.XContentParser; +import org.elasticsearch.xcontent.XContentType; +import org.elasticsearch.xpack.application.rules.QueryRule; + +import java.io.IOException; +import java.util.Objects; + +import static org.elasticsearch.action.ValidateActions.addValidationError; +import static org.elasticsearch.xcontent.ConstructingObjectParser.constructorArg; + +public class PutQueryRuleAction { + + public static final String NAME = "cluster:admin/xpack/query_rule/put"; + public static final ActionType INSTANCE = new ActionType<>(NAME); + + private PutQueryRuleAction() {/* no instances */} + + public static class Request extends ActionRequest implements ToXContentObject { + + private final String queryRulesetId; + private final QueryRule queryRule; + private static final ParseField QUERY_RULESET_ID_FIELD = new ParseField("queryRulesetId"); + private static final ParseField QUERY_RULE_FIELD = new ParseField("queryRule"); + + public Request(StreamInput in) throws IOException { + super(in); + this.queryRulesetId = in.readString(); + this.queryRule = new QueryRule(in); + } + + public Request(String queryRulesetId, QueryRule queryRule) { + this.queryRulesetId = queryRulesetId; + this.queryRule = queryRule; + } + + public Request(String rulesetId, String ruleId, BytesReference content, XContentType contentType) { + this.queryRulesetId = rulesetId; + + QueryRule queryRule = QueryRule.fromXContentBytes(content, contentType); + if (queryRule.id() == null) { + this.queryRule = new QueryRule(ruleId, queryRule); + } else if (ruleId.equals(queryRule.id()) == false) { + throw new IllegalArgumentException("rule_id does not match the id in the query rule"); + } else { + this.queryRule = queryRule; + } + } + + @Override + public ActionRequestValidationException validate() { + ActionRequestValidationException validationException = null; + + if (Strings.isNullOrEmpty(queryRulesetId)) { + validationException = addValidationError("ruleset_id cannot be null or empty", validationException); + } + + if (Strings.isNullOrEmpty(queryRule.id())) { + validationException = addValidationError("rule_id cannot be null or empty", validationException); + } + + return validationException; + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + super.writeTo(out); + out.writeString(queryRulesetId); + queryRule.writeTo(out); + } + + public String queryRulesetId() { + return queryRulesetId; + } + + public QueryRule queryRule() { + return queryRule; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Request request = (Request) o; + return Objects.equals(queryRulesetId, request.queryRulesetId) && Objects.equals(queryRule, request.queryRule); + } + + @Override + public int hashCode() { + return Objects.hash(queryRulesetId, queryRule); + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + builder.field(QUERY_RULESET_ID_FIELD.getPreferredName(), queryRulesetId); + builder.field(QUERY_RULE_FIELD.getPreferredName(), queryRule); + builder.endObject(); + return builder; + } + + private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>( + "put_query_rule_request", + p -> new Request((String) p[0], (QueryRule) p[1]) + ); + + static { + PARSER.declareString(constructorArg(), QUERY_RULESET_ID_FIELD); + PARSER.declareObject(constructorArg(), (p, c) -> QueryRule.fromXContent(p), QUERY_RULE_FIELD); + } + + public static PutQueryRuleAction.Request parse(XContentParser parser, String resourceName) { + return PARSER.apply(parser, resourceName); + } + + public static PutQueryRuleAction.Request fromXContent(String queryRulesetId, XContentParser parser) throws IOException { + return new PutQueryRuleAction.Request(queryRulesetId, QueryRule.fromXContent(parser)); + } + + @Override + public String toString() { + return Strings.toString(this); + } + + } + + public static class Response extends ActionResponse implements ToXContentObject { + + final DocWriteResponse.Result result; + + public Response(StreamInput in) throws IOException { + super(in); + result = DocWriteResponse.Result.readFrom(in); + } + + public Response(DocWriteResponse.Result result) { + this.result = result; + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + this.result.writeTo(out); + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + builder.field("result", this.result.getLowercase()); + builder.endObject(); + return builder; + } + + public RestStatus status() { + return switch (result) { + case CREATED -> RestStatus.CREATED; + case NOT_FOUND -> RestStatus.NOT_FOUND; + default -> RestStatus.OK; + }; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Response that = (Response) o; + return Objects.equals(result, that.result); + } + + @Override + public int hashCode() { + return Objects.hash(result); + } + + } + +} diff --git a/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/action/PutQueryRulesetAction.java b/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/action/PutQueryRulesetAction.java index 1a42d4c631a9b..842d5d5e0cee4 100644 --- a/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/action/PutQueryRulesetAction.java +++ b/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/action/PutQueryRulesetAction.java @@ -69,6 +69,15 @@ public ActionRequestValidationException validate() { List rules = queryRuleset.rules(); if (rules == null || rules.isEmpty()) { validationException = addValidationError("rules cannot be null or empty", validationException); + } else { + for (QueryRule rule : rules) { + if (rule.id() == null) { + validationException = addValidationError( + "rule_id cannot be null or empty. rule: [" + rule + "]", + validationException + ); + } + } } return validationException; diff --git a/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/action/RestPutQueryRuleAction.java b/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/action/RestPutQueryRuleAction.java new file mode 100644 index 0000000000000..7abf156c9a144 --- /dev/null +++ b/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/action/RestPutQueryRuleAction.java @@ -0,0 +1,55 @@ +/* + * 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.application.rules.action; + +import org.elasticsearch.client.internal.node.NodeClient; +import org.elasticsearch.license.XPackLicenseState; +import org.elasticsearch.rest.RestRequest; +import org.elasticsearch.rest.Scope; +import org.elasticsearch.rest.ServerlessScope; +import org.elasticsearch.rest.action.RestToXContentListener; +import org.elasticsearch.xpack.application.EnterpriseSearch; +import org.elasticsearch.xpack.application.EnterpriseSearchBaseRestHandler; +import org.elasticsearch.xpack.application.utils.LicenseUtils; + +import java.io.IOException; +import java.util.List; + +import static org.elasticsearch.rest.RestRequest.Method.PUT; + +@ServerlessScope(Scope.PUBLIC) +public class RestPutQueryRuleAction extends EnterpriseSearchBaseRestHandler { + public RestPutQueryRuleAction(XPackLicenseState licenseState) { + super(licenseState, LicenseUtils.Product.QUERY_RULES); + } + + @Override + public String getName() { + return "query_rule_put_action"; + } + + @Override + public List routes() { + return List.of(new Route(PUT, "/" + EnterpriseSearch.QUERY_RULES_API_ENDPOINT + "/{ruleset_id}/{rule_id}")); + } + + @Override + protected RestChannelConsumer innerPrepareRequest(RestRequest restRequest, NodeClient client) throws IOException { + PutQueryRuleAction.Request request = new PutQueryRuleAction.Request( + restRequest.param("ruleset_id"), + restRequest.param("rule_id"), + restRequest.content(), + restRequest.getXContentType() + ); + return channel -> client.execute( + PutQueryRuleAction.INSTANCE, + request, + new RestToXContentListener<>(channel, PutQueryRuleAction.Response::status, r -> null) + ); + } +} diff --git a/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/action/TransportPutQueryRuleAction.java b/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/action/TransportPutQueryRuleAction.java new file mode 100644 index 0000000000000..69a568ff3b1a1 --- /dev/null +++ b/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/action/TransportPutQueryRuleAction.java @@ -0,0 +1,49 @@ +/* + * 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.application.rules.action; + +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.action.support.HandledTransportAction; +import org.elasticsearch.client.internal.Client; +import org.elasticsearch.cluster.service.ClusterService; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.util.concurrent.EsExecutors; +import org.elasticsearch.tasks.Task; +import org.elasticsearch.transport.TransportService; +import org.elasticsearch.xpack.application.rules.QueryRule; +import org.elasticsearch.xpack.application.rules.QueryRulesIndexService; + +public class TransportPutQueryRuleAction extends HandledTransportAction { + protected final QueryRulesIndexService systemIndexService; + + @Inject + public TransportPutQueryRuleAction( + TransportService transportService, + ClusterService clusterService, + ActionFilters actionFilters, + Client client + ) { + super( + PutQueryRuleAction.NAME, + transportService, + actionFilters, + PutQueryRuleAction.Request::new, + EsExecutors.DIRECT_EXECUTOR_SERVICE + ); + this.systemIndexService = new QueryRulesIndexService(client, clusterService.getClusterSettings()); + } + + @Override + protected void doExecute(Task task, PutQueryRuleAction.Request request, ActionListener listener) { + String queryRulesetId = request.queryRulesetId(); + QueryRule queryRule = request.queryRule(); + systemIndexService.putQueryRule(queryRulesetId, queryRule, ActionListener.wrap(listener::onResponse, listener::onFailure)); + + } +} diff --git a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/search/SearchApplicationTestUtils.java b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/EnterpriseSearchModuleTestUtils.java similarity index 85% rename from x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/search/SearchApplicationTestUtils.java rename to x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/EnterpriseSearchModuleTestUtils.java index 711051cbaffd0..06adb29e32691 100644 --- a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/search/SearchApplicationTestUtils.java +++ b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/EnterpriseSearchModuleTestUtils.java @@ -5,7 +5,7 @@ * 2.0. */ -package org.elasticsearch.xpack.application.search; +package org.elasticsearch.xpack.application; import org.elasticsearch.core.Tuple; import org.elasticsearch.script.Script; @@ -15,6 +15,9 @@ import org.elasticsearch.xpack.application.rules.QueryRuleCriteria; import org.elasticsearch.xpack.application.rules.QueryRuleCriteriaType; import org.elasticsearch.xpack.application.rules.QueryRuleset; +import org.elasticsearch.xpack.application.search.SearchApplication; +import org.elasticsearch.xpack.application.search.SearchApplicationTemplate; +import org.elasticsearch.xpack.application.search.TemplateParamValidator; import org.elasticsearch.xpack.core.action.util.PageParams; import java.util.ArrayList; @@ -33,12 +36,13 @@ import static org.elasticsearch.test.ESTestCase.randomList; import static org.elasticsearch.test.ESTestCase.randomLongBetween; import static org.elasticsearch.test.ESTestCase.randomMap; +import static org.elasticsearch.xpack.application.rules.QueryRule.MAX_PRIORITY; +import static org.elasticsearch.xpack.application.rules.QueryRule.MIN_PRIORITY; import static org.elasticsearch.xpack.application.rules.QueryRuleCriteriaType.ALWAYS; -// TODO - move this one package up and rename to EnterpriseSearchModuleTestUtils -public final class SearchApplicationTestUtils { +public final class EnterpriseSearchModuleTestUtils { - private SearchApplicationTestUtils() { + private EnterpriseSearchModuleTestUtils() { throw new UnsupportedOperationException("Don't instantiate this class!"); } @@ -93,7 +97,12 @@ public static QueryRule randomQueryRule() { QueryRule.QueryRuleType type = randomFrom(QueryRule.QueryRuleType.values()); List criteria = List.of(randomQueryRuleCriteria()); Map actions = Map.of(randomFrom("ids", "docs"), List.of(randomAlphaOfLengthBetween(2, 10))); - return new QueryRule(id, type, criteria, actions); + Integer priority = randomQueryRulePriority(); + return new QueryRule(id, type, criteria, actions, priority); + } + + public static Integer randomQueryRulePriority() { + return randomBoolean() ? randomIntBetween(MIN_PRIORITY, MAX_PRIORITY) : null; } public static QueryRuleset randomQueryRuleset() { diff --git a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/action/ListConnectorActionRequestBWCSerializingTests.java b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/action/ListConnectorActionRequestBWCSerializingTests.java index 366001b6dd215..c71fbaf6716e4 100644 --- a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/action/ListConnectorActionRequestBWCSerializingTests.java +++ b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/action/ListConnectorActionRequestBWCSerializingTests.java @@ -10,7 +10,7 @@ import org.elasticsearch.TransportVersion; import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.xcontent.XContentParser; -import org.elasticsearch.xpack.application.search.SearchApplicationTestUtils; +import org.elasticsearch.xpack.application.EnterpriseSearchModuleTestUtils; import org.elasticsearch.xpack.core.action.util.PageParams; import org.elasticsearch.xpack.core.ml.AbstractBWCSerializationTestCase; @@ -25,7 +25,7 @@ protected Writeable.Reader instanceReader() { @Override protected ListConnectorAction.Request createTestInstance() { - PageParams pageParams = SearchApplicationTestUtils.randomPageParams(); + PageParams pageParams = EnterpriseSearchModuleTestUtils.randomPageParams(); return new ListConnectorAction.Request( pageParams, List.of(generateRandomStringArray(10, 10, false)), diff --git a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/syncjob/ConnectorSyncJobTestUtils.java b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/syncjob/ConnectorSyncJobTestUtils.java index eb280334510cb..dcc6c9ba242d6 100644 --- a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/syncjob/ConnectorSyncJobTestUtils.java +++ b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/syncjob/ConnectorSyncJobTestUtils.java @@ -11,6 +11,7 @@ import org.elasticsearch.common.xcontent.XContentHelper; import org.elasticsearch.core.Tuple; import org.elasticsearch.xcontent.XContentType; +import org.elasticsearch.xpack.application.EnterpriseSearchModuleTestUtils; import org.elasticsearch.xpack.application.connector.ConnectorTestUtils; import org.elasticsearch.xpack.application.connector.syncjob.action.CancelConnectorSyncJobAction; import org.elasticsearch.xpack.application.connector.syncjob.action.CheckInConnectorSyncJobAction; @@ -20,7 +21,6 @@ import org.elasticsearch.xpack.application.connector.syncjob.action.PostConnectorSyncJobAction; import org.elasticsearch.xpack.application.connector.syncjob.action.UpdateConnectorSyncJobErrorAction; import org.elasticsearch.xpack.application.connector.syncjob.action.UpdateConnectorSyncJobIngestionStatsAction; -import org.elasticsearch.xpack.application.search.SearchApplicationTestUtils; import java.io.IOException; import java.time.Instant; @@ -188,7 +188,7 @@ public static GetConnectorSyncJobAction.Response getRandomGetConnectorSyncJobRes public static ListConnectorSyncJobsAction.Request getRandomListConnectorSyncJobsActionRequest() { return new ListConnectorSyncJobsAction.Request( - SearchApplicationTestUtils.randomPageParams(), + EnterpriseSearchModuleTestUtils.randomPageParams(), randomAlphaOfLength(10), ConnectorTestUtils.getRandomSyncStatus(), Collections.singletonList(ConnectorTestUtils.getRandomSyncJobType()) diff --git a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/syncjob/action/ListConnectorSyncJobsActionRequestBWCSerializingTests.java b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/syncjob/action/ListConnectorSyncJobsActionRequestBWCSerializingTests.java index 790f588e8937c..967994ebe57e0 100644 --- a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/syncjob/action/ListConnectorSyncJobsActionRequestBWCSerializingTests.java +++ b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/syncjob/action/ListConnectorSyncJobsActionRequestBWCSerializingTests.java @@ -10,10 +10,10 @@ import org.elasticsearch.TransportVersion; import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.xcontent.XContentParser; +import org.elasticsearch.xpack.application.EnterpriseSearchModuleTestUtils; import org.elasticsearch.xpack.application.connector.ConnectorSyncStatus; import org.elasticsearch.xpack.application.connector.ConnectorTestUtils; import org.elasticsearch.xpack.application.connector.syncjob.ConnectorSyncJobType; -import org.elasticsearch.xpack.application.search.SearchApplicationTestUtils; import org.elasticsearch.xpack.core.action.util.PageParams; import org.elasticsearch.xpack.core.ml.AbstractBWCSerializationTestCase; @@ -29,7 +29,7 @@ protected Writeable.Reader instanceReader() @Override protected ListConnectorSyncJobsAction.Request createTestInstance() { - PageParams pageParams = SearchApplicationTestUtils.randomPageParams(); + PageParams pageParams = EnterpriseSearchModuleTestUtils.randomPageParams(); String connectorId = randomAlphaOfLength(10); ConnectorSyncStatus syncStatus = ConnectorTestUtils.getRandomSyncStatus(); ConnectorSyncJobType syncJobType = ConnectorTestUtils.getRandomSyncJobType(); diff --git a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/QueryRuleCriteriaTests.java b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/QueryRuleCriteriaTests.java index 7b5fa7d053df8..881b77442daca 100644 --- a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/QueryRuleCriteriaTests.java +++ b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/QueryRuleCriteriaTests.java @@ -17,7 +17,7 @@ import org.elasticsearch.xcontent.ToXContent; import org.elasticsearch.xcontent.XContentParser; import org.elasticsearch.xcontent.XContentType; -import org.elasticsearch.xpack.application.search.SearchApplicationTestUtils; +import org.elasticsearch.xpack.application.EnterpriseSearchModuleTestUtils; import org.junit.Before; import java.io.IOException; @@ -51,7 +51,7 @@ public void registerNamedObjects() { public final void testRandomSerialization() throws IOException { for (int runs = 0; runs < 10; runs++) { - QueryRuleCriteria testInstance = SearchApplicationTestUtils.randomQueryRuleCriteria(); + QueryRuleCriteria testInstance = EnterpriseSearchModuleTestUtils.randomQueryRuleCriteria(); assertTransportSerialization(testInstance); assertXContent(testInstance, randomBoolean()); } diff --git a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/QueryRuleTests.java b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/QueryRuleTests.java index 5576ec71667f4..a48d6f45589e3 100644 --- a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/QueryRuleTests.java +++ b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/QueryRuleTests.java @@ -17,7 +17,7 @@ import org.elasticsearch.xcontent.ToXContent; import org.elasticsearch.xcontent.XContentParser; import org.elasticsearch.xcontent.XContentType; -import org.elasticsearch.xpack.application.search.SearchApplicationTestUtils; +import org.elasticsearch.xpack.application.EnterpriseSearchModuleTestUtils; import org.junit.Before; import java.io.IOException; @@ -28,6 +28,8 @@ import static java.util.Collections.emptyList; import static org.elasticsearch.common.xcontent.XContentHelper.toXContent; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertToXContentEquivalent; +import static org.elasticsearch.xpack.application.rules.QueryRule.MAX_PRIORITY; +import static org.elasticsearch.xpack.application.rules.QueryRule.MIN_PRIORITY; import static org.elasticsearch.xpack.application.rules.QueryRuleCriteriaType.EXACT; import static org.elasticsearch.xpack.application.rules.QueryRuleCriteriaType.PREFIX; import static org.elasticsearch.xpack.application.rules.QueryRuleCriteriaType.SUFFIX; @@ -46,7 +48,7 @@ public void registerNamedObjects() { public final void testRandomSerialization() throws IOException { for (int runs = 0; runs < 10; runs++) { - QueryRule testInstance = SearchApplicationTestUtils.randomQueryRule(); + QueryRule testInstance = EnterpriseSearchModuleTestUtils.randomQueryRule(); assertTransportSerialization(testInstance); assertXContent(testInstance, randomBoolean()); } @@ -62,7 +64,8 @@ public void testToXContent() throws IOException { ], "actions": { "ids": ["id1", "id2"] - } + }, + "priority": 5 }"""); QueryRule queryRule = QueryRule.fromXContentBytes(new BytesArray(content), XContentType.JSON); @@ -75,20 +78,6 @@ public void testToXContent() throws IOException { assertToXContentEquivalent(originalBytes, toXContent(parsed, XContentType.JSON, humanReadable), XContentType.JSON); } - public void testToXContentMissingQueryRuleId() throws IOException { - String content = XContentHelper.stripWhitespace(""" - { - "type": "pinned", - "criteria": [ - { "type": "exact", "metadata": "query_string", "values": ["foo", "bar"] } - ], - "actions": { - "ids": ["id1", "id2"] - } - }"""); - expectThrows(IllegalArgumentException.class, () -> QueryRule.fromXContentBytes(new BytesArray(content), XContentType.JSON)); - } - public void testToXContentEmptyCriteria() throws IOException { String content = XContentHelper.stripWhitespace(""" { @@ -170,7 +159,8 @@ public void testApplyRuleWithOneCriteria() { randomAlphaOfLength(10), QueryRule.QueryRuleType.PINNED, List.of(new QueryRuleCriteria(EXACT, "query", List.of("elastic"))), - Map.of("ids", List.of("id1", "id2")) + Map.of("ids", List.of("id1", "id2")), + randomBoolean() ? randomIntBetween(MIN_PRIORITY, MAX_PRIORITY) : null ); AppliedQueryRules appliedQueryRules = new AppliedQueryRules(); rule.applyRule(appliedQueryRules, Map.of("query", "elastic")); @@ -186,7 +176,8 @@ public void testApplyRuleWithMultipleCriteria() { randomAlphaOfLength(10), QueryRule.QueryRuleType.PINNED, List.of(new QueryRuleCriteria(PREFIX, "query", List.of("elastic")), new QueryRuleCriteria(SUFFIX, "query", List.of("search"))), - Map.of("ids", List.of("id1", "id2")) + Map.of("ids", List.of("id1", "id2")), + randomBoolean() ? randomIntBetween(MIN_PRIORITY, MAX_PRIORITY) : null ); AppliedQueryRules appliedQueryRules = new AppliedQueryRules(); rule.applyRule(appliedQueryRules, Map.of("query", "elastic - you know, for search")); diff --git a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/QueryRulesIndexServiceTests.java b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/QueryRulesIndexServiceTests.java index 9ce62ee8d4c16..5eeca8465d394 100644 --- a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/QueryRulesIndexServiceTests.java +++ b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/QueryRulesIndexServiceTests.java @@ -19,6 +19,7 @@ import org.elasticsearch.plugins.SystemIndexPlugin; import org.elasticsearch.rest.RestStatus; import org.elasticsearch.test.ESSingleNodeTestCase; +import org.elasticsearch.xpack.application.EnterpriseSearchModuleTestUtils; import org.junit.Before; import java.util.ArrayList; @@ -74,7 +75,8 @@ public void testUpdateQueryRuleset() throws Exception { "my_rule1", QueryRuleType.PINNED, List.of(new QueryRuleCriteria(EXACT, "query_string", List.of("foo"))), - Map.of("ids", List.of("id1", "id2")) + Map.of("ids", List.of("id1", "id2")), + EnterpriseSearchModuleTestUtils.randomQueryRulePriority() ); final QueryRuleset myQueryRuleset = new QueryRuleset("my_ruleset", Collections.singletonList(myQueryRule1)); DocWriteResponse resp = awaitPutQueryRuleset(myQueryRuleset); @@ -89,13 +91,15 @@ public void testUpdateQueryRuleset() throws Exception { "my_rule1", QueryRuleType.PINNED, List.of(new QueryRuleCriteria(EXACT, "query_string", List.of("foo"))), - Map.of("docs", List.of(Map.of("_index", "my_index1", "_id", "id1"), Map.of("_index", "my_index2", "_id", "id2"))) + Map.of("docs", List.of(Map.of("_index", "my_index1", "_id", "id1"), Map.of("_index", "my_index2", "_id", "id2"))), + EnterpriseSearchModuleTestUtils.randomQueryRulePriority() ); final QueryRule myQueryRule2 = new QueryRule( "my_rule2", QueryRuleType.PINNED, List.of(new QueryRuleCriteria(EXACT, "query_string", List.of("bar"))), - Map.of("docs", List.of(Map.of("_index", "my_index1", "_id", "id3"), Map.of("_index", "my_index2", "_id", "id4"))) + Map.of("docs", List.of(Map.of("_index", "my_index1", "_id", "id3"), Map.of("_index", "my_index2", "_id", "id4"))), + EnterpriseSearchModuleTestUtils.randomQueryRulePriority() ); final QueryRuleset myQueryRuleset = new QueryRuleset("my_ruleset", List.of(myQueryRule1, myQueryRule2)); DocWriteResponse newResp = awaitPutQueryRuleset(myQueryRuleset); @@ -116,7 +120,8 @@ public void testListQueryRulesets() throws Exception { new QueryRuleCriteria(EXACT, "query_string", List.of("foo" + i)), new QueryRuleCriteria(GTE, "query_string", List.of(i)) ), - Map.of("ids", List.of("id1", "id2")) + Map.of("ids", List.of("id1", "id2")), + EnterpriseSearchModuleTestUtils.randomQueryRulePriority() ), new QueryRule( "my_rule_" + i + "_" + (i + 1), @@ -125,7 +130,8 @@ public void testListQueryRulesets() throws Exception { new QueryRuleCriteria(FUZZY, "query_string", List.of("bar" + i)), new QueryRuleCriteria(GTE, "user.age", List.of(i)) ), - Map.of("ids", List.of("id3", "id4")) + Map.of("ids", List.of("id3", "id4")), + EnterpriseSearchModuleTestUtils.randomQueryRulePriority() ) ); final QueryRuleset myQueryRuleset = new QueryRuleset("my_ruleset_" + i, rules); @@ -175,13 +181,15 @@ public void testDeleteQueryRuleset() throws Exception { "my_rule1", QueryRuleType.PINNED, List.of(new QueryRuleCriteria(EXACT, "query_string", List.of("foo"))), - Map.of("ids", List.of("id1", "id2")) + Map.of("ids", List.of("id1", "id2")), + EnterpriseSearchModuleTestUtils.randomQueryRulePriority() ); final QueryRule myQueryRule2 = new QueryRule( "my_rule2", QueryRuleType.PINNED, List.of(new QueryRuleCriteria(EXACT, "query_string", List.of("bar"))), - Map.of("ids", List.of("id3", "id4")) + Map.of("ids", List.of("id3", "id4")), + EnterpriseSearchModuleTestUtils.randomQueryRulePriority() ); final QueryRuleset myQueryRuleset = new QueryRuleset("my_ruleset", List.of(myQueryRule1, myQueryRule2)); DocWriteResponse resp = awaitPutQueryRuleset(myQueryRuleset); diff --git a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/QueryRulesetTests.java b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/QueryRulesetTests.java index 4799396ef5223..185e2429cf3c1 100644 --- a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/QueryRulesetTests.java +++ b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/QueryRulesetTests.java @@ -17,7 +17,7 @@ import org.elasticsearch.xcontent.ToXContent; import org.elasticsearch.xcontent.XContentParser; import org.elasticsearch.xcontent.XContentType; -import org.elasticsearch.xpack.application.search.SearchApplicationTestUtils; +import org.elasticsearch.xpack.application.EnterpriseSearchModuleTestUtils; import org.junit.Before; import java.io.IOException; @@ -41,7 +41,7 @@ public void registerNamedObjects() { public final void testRandomSerialization() throws IOException { for (int runs = 0; runs < 10; runs++) { - QueryRuleset testInstance = SearchApplicationTestUtils.randomQueryRuleset(); + QueryRuleset testInstance = EnterpriseSearchModuleTestUtils.randomQueryRuleset(); assertTransportSerialization(testInstance); assertXContent(testInstance, randomBoolean()); } diff --git a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/RuleQueryBuilderTests.java b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/RuleQueryBuilderTests.java index 6979f00476cb2..bedd015406312 100644 --- a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/RuleQueryBuilderTests.java +++ b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/RuleQueryBuilderTests.java @@ -161,7 +161,8 @@ protected Object simulateMethod(Method method, Object[] args) { "my_rule1", QueryRule.QueryRuleType.PINNED, List.of(new QueryRuleCriteria(EXACT, "query_string", List.of("elastic"))), - Map.of("ids", List.of("id1", "id2")) + Map.of("ids", List.of("id1", "id2")), + null ) ); QueryRuleset queryRuleset = new QueryRuleset(rulesetId, rules); diff --git a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/action/GetQueryRulesetActionResponseBWCSerializingTests.java b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/action/GetQueryRulesetActionResponseBWCSerializingTests.java index 4e2ce15c00350..4942f9fb076af 100644 --- a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/action/GetQueryRulesetActionResponseBWCSerializingTests.java +++ b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/action/GetQueryRulesetActionResponseBWCSerializingTests.java @@ -8,6 +8,7 @@ package org.elasticsearch.xpack.application.rules.action; import org.elasticsearch.TransportVersion; +import org.elasticsearch.TransportVersions; import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.xcontent.XContentParser; import org.elasticsearch.xpack.application.rules.QueryRule; @@ -19,8 +20,8 @@ import java.util.ArrayList; import java.util.List; +import static org.elasticsearch.xpack.application.EnterpriseSearchModuleTestUtils.randomQueryRuleset; import static org.elasticsearch.xpack.application.rules.QueryRuleCriteria.CRITERIA_METADATA_VALUES_TRANSPORT_VERSION; -import static org.elasticsearch.xpack.application.search.SearchApplicationTestUtils.randomQueryRuleset; public class GetQueryRulesetActionResponseBWCSerializingTests extends AbstractBWCSerializationTestCase { public QueryRuleset queryRuleset; @@ -57,7 +58,13 @@ protected GetQueryRulesetAction.Response mutateInstanceForVersion(GetQueryRulese new QueryRuleCriteria(criteria.criteriaType(), criteria.criteriaMetadata(), criteria.criteriaValues().subList(0, 1)) ); } - rules.add(new QueryRule(rule.id(), rule.type(), newCriteria, rule.actions())); + rules.add(new QueryRule(rule.id(), rule.type(), newCriteria, rule.actions(), null)); + } + return new GetQueryRulesetAction.Response(new QueryRuleset(instance.queryRuleset().id(), rules)); + } else if (version.before(TransportVersions.QUERY_RULE_CRUD_API_PUT)) { + List rules = new ArrayList<>(); + for (QueryRule rule : instance.queryRuleset().rules()) { + rules.add(new QueryRule(rule.id(), rule.type(), rule.criteria(), rule.actions(), null)); } return new GetQueryRulesetAction.Response(new QueryRuleset(instance.queryRuleset().id(), rules)); } diff --git a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/action/ListQueryRulesetsActionRequestBWCSerializingTests.java b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/action/ListQueryRulesetsActionRequestBWCSerializingTests.java index 92219f5f317d5..dfac7c57e01d3 100644 --- a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/action/ListQueryRulesetsActionRequestBWCSerializingTests.java +++ b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/action/ListQueryRulesetsActionRequestBWCSerializingTests.java @@ -10,7 +10,7 @@ import org.elasticsearch.TransportVersion; import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.xcontent.XContentParser; -import org.elasticsearch.xpack.application.search.SearchApplicationTestUtils; +import org.elasticsearch.xpack.application.EnterpriseSearchModuleTestUtils; import org.elasticsearch.xpack.core.action.util.PageParams; import org.elasticsearch.xpack.core.ml.AbstractBWCSerializationTestCase; @@ -26,7 +26,7 @@ protected Writeable.Reader instanceReader() { @Override protected ListQueryRulesetsAction.Request createTestInstance() { - PageParams pageParams = SearchApplicationTestUtils.randomPageParams(); + PageParams pageParams = EnterpriseSearchModuleTestUtils.randomPageParams(); return new ListQueryRulesetsAction.Request(pageParams); } diff --git a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/action/ListQueryRulesetsActionResponseBWCSerializingTests.java b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/action/ListQueryRulesetsActionResponseBWCSerializingTests.java index 1613e31f94206..5ae0f51cb6112 100644 --- a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/action/ListQueryRulesetsActionResponseBWCSerializingTests.java +++ b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/action/ListQueryRulesetsActionResponseBWCSerializingTests.java @@ -9,10 +9,10 @@ import org.elasticsearch.TransportVersion; import org.elasticsearch.common.io.stream.Writeable; +import org.elasticsearch.xpack.application.EnterpriseSearchModuleTestUtils; import org.elasticsearch.xpack.application.rules.QueryRuleCriteriaType; import org.elasticsearch.xpack.application.rules.QueryRuleset; import org.elasticsearch.xpack.application.rules.QueryRulesetListItem; -import org.elasticsearch.xpack.application.search.SearchApplicationTestUtils; import org.elasticsearch.xpack.core.ml.AbstractBWCWireSerializationTestCase; import java.util.ArrayList; @@ -29,7 +29,7 @@ protected Writeable.Reader instanceReader() { private static ListQueryRulesetsAction.Response randomQueryRulesetListItem() { return new ListQueryRulesetsAction.Response(randomList(10, () -> { - QueryRuleset queryRuleset = SearchApplicationTestUtils.randomQueryRuleset(); + QueryRuleset queryRuleset = EnterpriseSearchModuleTestUtils.randomQueryRuleset(); Map criteriaTypeToCountMap = Map.of( randomFrom(QueryRuleCriteriaType.values()), randomIntBetween(0, 10) diff --git a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/action/PutQueryRuleActionRequestBWCSerializingTests.java b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/action/PutQueryRuleActionRequestBWCSerializingTests.java new file mode 100644 index 0000000000000..a66d0c0aa5895 --- /dev/null +++ b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/action/PutQueryRuleActionRequestBWCSerializingTests.java @@ -0,0 +1,62 @@ +/* + * 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.application.rules.action; + +import org.elasticsearch.TransportVersion; +import org.elasticsearch.TransportVersions; +import org.elasticsearch.common.io.stream.Writeable; +import org.elasticsearch.xcontent.XContentParser; +import org.elasticsearch.xpack.application.EnterpriseSearchModuleTestUtils; +import org.elasticsearch.xpack.application.rules.QueryRule; +import org.elasticsearch.xpack.core.ml.AbstractBWCSerializationTestCase; + +import java.io.IOException; +import java.util.List; +import java.util.stream.Collectors; + +import static org.elasticsearch.xpack.core.ml.AbstractBWCWireSerializationTestCase.getAllBWCVersions; + +public class PutQueryRuleActionRequestBWCSerializingTests extends AbstractBWCSerializationTestCase { + + private String queryRuleId; + + @Override + protected Writeable.Reader instanceReader() { + return PutQueryRuleAction.Request::new; + } + + @Override + protected PutQueryRuleAction.Request createTestInstance() { + String queryRulesetId = randomAlphaOfLengthBetween(5, 10); + QueryRule queryRule = EnterpriseSearchModuleTestUtils.randomQueryRule(); + this.queryRuleId = queryRule.id(); + return new PutQueryRuleAction.Request(queryRulesetId, queryRule); + } + + @Override + protected PutQueryRuleAction.Request mutateInstance(PutQueryRuleAction.Request instance) { + return randomValueOtherThan(instance, this::createTestInstance); + } + + @Override + protected PutQueryRuleAction.Request doParseInstance(XContentParser parser) throws IOException { + return PutQueryRuleAction.Request.parse(parser, this.queryRuleId); + } + + @Override + protected PutQueryRuleAction.Request mutateInstanceForVersion(PutQueryRuleAction.Request instance, TransportVersion version) { + return new PutQueryRuleAction.Request(instance.queryRulesetId(), instance.queryRule()); + } + + @Override + protected List bwcVersions() { + return getAllBWCVersions().stream() + .filter(v -> v.onOrAfter(TransportVersions.QUERY_RULE_CRUD_API_PUT)) + .collect(Collectors.toList()); + } +} diff --git a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/action/PutQueryRuleActionResponseSerializingTests.java b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/action/PutQueryRuleActionResponseSerializingTests.java new file mode 100644 index 0000000000000..47be14761684d --- /dev/null +++ b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/action/PutQueryRuleActionResponseSerializingTests.java @@ -0,0 +1,38 @@ +/* + * 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.application.rules.action; + +import org.elasticsearch.TransportVersion; +import org.elasticsearch.action.DocWriteResponse; +import org.elasticsearch.common.io.stream.Writeable; +import org.elasticsearch.xpack.core.ml.AbstractBWCWireSerializationTestCase; + +import java.io.IOException; + +public class PutQueryRuleActionResponseSerializingTests extends AbstractBWCWireSerializationTestCase { + + @Override + protected Writeable.Reader instanceReader() { + return PutQueryRuleAction.Response::new; + } + + @Override + protected PutQueryRuleAction.Response createTestInstance() { + return new PutQueryRuleAction.Response(randomFrom(DocWriteResponse.Result.values())); + } + + @Override + protected PutQueryRuleAction.Response mutateInstance(PutQueryRuleAction.Response instance) throws IOException { + return randomValueOtherThan(instance, this::createTestInstance); + } + + @Override + protected PutQueryRuleAction.Response mutateInstanceForVersion(PutQueryRuleAction.Response instance, TransportVersion version) { + return instance; + } +} diff --git a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/action/PutQueryRulesetActionRequestBWCSerializingTests.java b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/action/PutQueryRulesetActionRequestBWCSerializingTests.java index c6c463b677afa..83702b0b0672c 100644 --- a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/action/PutQueryRulesetActionRequestBWCSerializingTests.java +++ b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/action/PutQueryRulesetActionRequestBWCSerializingTests.java @@ -8,12 +8,13 @@ package org.elasticsearch.xpack.application.rules.action; import org.elasticsearch.TransportVersion; +import org.elasticsearch.TransportVersions; import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.xcontent.XContentParser; +import org.elasticsearch.xpack.application.EnterpriseSearchModuleTestUtils; import org.elasticsearch.xpack.application.rules.QueryRule; import org.elasticsearch.xpack.application.rules.QueryRuleCriteria; import org.elasticsearch.xpack.application.rules.QueryRuleset; -import org.elasticsearch.xpack.application.search.SearchApplicationTestUtils; import org.elasticsearch.xpack.core.ml.AbstractBWCSerializationTestCase; import java.io.IOException; @@ -33,7 +34,7 @@ protected Writeable.Reader instanceReader() { @Override protected PutQueryRulesetAction.Request createTestInstance() { - this.queryRulesSet = SearchApplicationTestUtils.randomQueryRuleset(); + this.queryRulesSet = EnterpriseSearchModuleTestUtils.randomQueryRuleset(); return new PutQueryRulesetAction.Request(this.queryRulesSet); } @@ -59,7 +60,13 @@ protected PutQueryRulesetAction.Request mutateInstanceForVersion(PutQueryRuleset new QueryRuleCriteria(criteria.criteriaType(), criteria.criteriaMetadata(), criteria.criteriaValues().subList(0, 1)) ); } - rules.add(new QueryRule(rule.id(), rule.type(), newCriteria, rule.actions())); + rules.add(new QueryRule(rule.id(), rule.type(), newCriteria, rule.actions(), null)); + } + return new PutQueryRulesetAction.Request(new QueryRuleset(instance.queryRuleset().id(), rules)); + } else if (version.before(TransportVersions.QUERY_RULE_CRUD_API_PUT)) { + List rules = new ArrayList<>(); + for (QueryRule rule : instance.queryRuleset().rules()) { + rules.add(new QueryRule(rule.id(), rule.type(), rule.criteria(), rule.actions(), null)); } return new PutQueryRulesetAction.Request(new QueryRuleset(instance.queryRuleset().id(), rules)); } diff --git a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/action/RestPutQueryRuleActionTests.java b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/action/RestPutQueryRuleActionTests.java new file mode 100644 index 0000000000000..0aff0b804e538 --- /dev/null +++ b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/rules/action/RestPutQueryRuleActionTests.java @@ -0,0 +1,66 @@ +/* + * 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.application.rules.action; + +import org.elasticsearch.common.bytes.BytesArray; +import org.elasticsearch.license.XPackLicenseState; +import org.elasticsearch.rest.RestRequest; +import org.elasticsearch.test.rest.FakeRestRequest; +import org.elasticsearch.xcontent.NamedXContentRegistry; +import org.elasticsearch.xcontent.XContentType; +import org.elasticsearch.xpack.application.AbstractRestEnterpriseSearchActionTests; +import org.elasticsearch.xpack.application.EnterpriseSearchBaseRestHandler; +import org.elasticsearch.xpack.application.utils.LicenseUtils; + +import java.util.Map; + +public class RestPutQueryRuleActionTests extends AbstractRestEnterpriseSearchActionTests { + public void testWithNonCompliantLicense() throws Exception { + checkLicenseForRequest( + new FakeRestRequest.Builder(NamedXContentRegistry.EMPTY).withMethod(RestRequest.Method.PUT) + .withParams(Map.of("ruleset_id", "ruleset-id", "rule_id", "rule-id")) + .withContent(new BytesArray(""" + { + "rule_id": "rule-id", + "type": "pinned", + "criteria": [ + { + "type": "exact", + "metadata": "query_string", + "values": ["elastic"] + } + ], + "actions": + { + "ids": [ + "id1", + "id2" + ] + } + } + """), XContentType.JSON) + .build(), + LicenseUtils.Product.QUERY_RULES + ); + } + + public void testInvalidRequestWithNonCompliantLicense() throws Exception { + checkLicenseForRequest( + new FakeRestRequest.Builder(NamedXContentRegistry.EMPTY).withMethod(RestRequest.Method.PUT) + .withParams(Map.of("invalid_param_name", "invalid_value")) + .withContent(new BytesArray("{}"), XContentType.JSON) + .build(), + LicenseUtils.Product.QUERY_RULES + ); + } + + @Override + protected EnterpriseSearchBaseRestHandler getRestAction(XPackLicenseState licenseState) { + return new RestPutQueryRuleAction(licenseState); + } +} diff --git a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/search/SearchApplicationIndexServiceTests.java b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/search/SearchApplicationIndexServiceTests.java index 7891f5773d1a8..6e9d33b45041b 100644 --- a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/search/SearchApplicationIndexServiceTests.java +++ b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/search/SearchApplicationIndexServiceTests.java @@ -22,6 +22,7 @@ import org.elasticsearch.plugins.SystemIndexPlugin; import org.elasticsearch.rest.RestStatus; import org.elasticsearch.test.ESSingleNodeTestCase; +import org.elasticsearch.xpack.application.EnterpriseSearchModuleTestUtils; import org.junit.Before; import java.util.ArrayList; @@ -131,7 +132,7 @@ public void testUpdateSearchApplication() throws Exception { new String[] { "index_1", "index_2" }, null, System.currentTimeMillis(), - SearchApplicationTestUtils.getRandomSearchApplicationTemplate() + EnterpriseSearchModuleTestUtils.getRandomSearchApplicationTemplate() ); DocWriteResponse resp = awaitPutSearchApplication(searchApp, false); assertThat(resp.status(), equalTo(RestStatus.CREATED)); @@ -146,7 +147,7 @@ public void testUpdateSearchApplication() throws Exception { new String[] { "index_3", "index_4" }, "my_search_app_analytics_collection", System.currentTimeMillis(), - SearchApplicationTestUtils.getRandomSearchApplicationTemplate() + EnterpriseSearchModuleTestUtils.getRandomSearchApplicationTemplate() ); DocWriteResponse newResp = awaitPutSearchApplication(searchApp, false); assertThat(newResp.status(), equalTo(RestStatus.OK)); diff --git a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/search/SearchApplicationTests.java b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/search/SearchApplicationTests.java index 60b88476285df..67a5bd6800447 100644 --- a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/search/SearchApplicationTests.java +++ b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/search/SearchApplicationTests.java @@ -23,6 +23,7 @@ import org.elasticsearch.xcontent.ToXContent; import org.elasticsearch.xcontent.XContentParser; import org.elasticsearch.xcontent.XContentType; +import org.elasticsearch.xpack.application.EnterpriseSearchModuleTestUtils; import org.junit.Before; import java.io.IOException; @@ -46,7 +47,7 @@ public void registerNamedObjects() { public final void testRandomSerialization() throws IOException { for (int runs = 0; runs < 10; runs++) { - SearchApplication testInstance = SearchApplicationTestUtils.randomSearchApplication(); + SearchApplication testInstance = EnterpriseSearchModuleTestUtils.randomSearchApplication(); assertTransportSerialization(testInstance); assertXContent(testInstance, randomBoolean()); assertIndexSerialization(testInstance); diff --git a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/search/action/GetSearchApplicationActionResponseBWCSerializingTests.java b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/search/action/GetSearchApplicationActionResponseBWCSerializingTests.java index bb3e36c95f0ab..11c28f062d272 100644 --- a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/search/action/GetSearchApplicationActionResponseBWCSerializingTests.java +++ b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/search/action/GetSearchApplicationActionResponseBWCSerializingTests.java @@ -10,8 +10,8 @@ import org.elasticsearch.TransportVersion; import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.xcontent.XContentParser; +import org.elasticsearch.xpack.application.EnterpriseSearchModuleTestUtils; import org.elasticsearch.xpack.application.search.SearchApplication; -import org.elasticsearch.xpack.application.search.SearchApplicationTestUtils; import org.elasticsearch.xpack.core.ml.AbstractBWCSerializationTestCase; import java.io.IOException; @@ -28,7 +28,7 @@ protected Writeable.Reader instanceReader() @Override protected GetSearchApplicationAction.Response createTestInstance() { - SearchApplication searchApp = SearchApplicationTestUtils.randomSearchApplication(); + SearchApplication searchApp = EnterpriseSearchModuleTestUtils.randomSearchApplication(); this.searchApplicationName = searchApp.name(); return new GetSearchApplicationAction.Response(searchApp); } diff --git a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/search/action/ListSearchApplicationActionRequestBWCSerializingTests.java b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/search/action/ListSearchApplicationActionRequestBWCSerializingTests.java index 62678e073a633..ba7b07441d8b1 100644 --- a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/search/action/ListSearchApplicationActionRequestBWCSerializingTests.java +++ b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/search/action/ListSearchApplicationActionRequestBWCSerializingTests.java @@ -10,7 +10,7 @@ import org.elasticsearch.TransportVersion; import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.xcontent.XContentParser; -import org.elasticsearch.xpack.application.search.SearchApplicationTestUtils; +import org.elasticsearch.xpack.application.EnterpriseSearchModuleTestUtils; import org.elasticsearch.xpack.core.action.util.PageParams; import org.elasticsearch.xpack.core.ml.AbstractBWCSerializationTestCase; @@ -27,7 +27,7 @@ protected Writeable.Reader instanceReader() @Override protected ListSearchApplicationAction.Request createTestInstance() { - PageParams pageParams = SearchApplicationTestUtils.randomPageParams(); + PageParams pageParams = EnterpriseSearchModuleTestUtils.randomPageParams(); String query = randomFrom(new String[] { null, randomAlphaOfLengthBetween(1, 10) }); return new ListSearchApplicationAction.Request(query, pageParams); } diff --git a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/search/action/ListSearchApplicationActionResponseBWCSerializingTests.java b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/search/action/ListSearchApplicationActionResponseBWCSerializingTests.java index 38b1b94064b96..2489e14913e72 100644 --- a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/search/action/ListSearchApplicationActionResponseBWCSerializingTests.java +++ b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/search/action/ListSearchApplicationActionResponseBWCSerializingTests.java @@ -9,9 +9,9 @@ import org.elasticsearch.TransportVersion; import org.elasticsearch.common.io.stream.Writeable; +import org.elasticsearch.xpack.application.EnterpriseSearchModuleTestUtils; import org.elasticsearch.xpack.application.search.SearchApplication; import org.elasticsearch.xpack.application.search.SearchApplicationListItem; -import org.elasticsearch.xpack.application.search.SearchApplicationTestUtils; import org.elasticsearch.xpack.core.ml.AbstractBWCWireSerializationTestCase; public class ListSearchApplicationActionResponseBWCSerializingTests extends AbstractBWCWireSerializationTestCase< @@ -24,7 +24,7 @@ protected Writeable.Reader instanceReader( private static ListSearchApplicationAction.Response randomSearchApplicationListItem() { return new ListSearchApplicationAction.Response(randomList(10, () -> { - SearchApplication app = SearchApplicationTestUtils.randomSearchApplication(); + SearchApplication app = EnterpriseSearchModuleTestUtils.randomSearchApplication(); return new SearchApplicationListItem(app.name(), app.analyticsCollectionName(), app.updatedAtMillis()); }), randomLongBetween(0, 1000)); } diff --git a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/search/action/PutSearchApplicationActionRequestBWCSerializingTests.java b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/search/action/PutSearchApplicationActionRequestBWCSerializingTests.java index 0d79950d2081a..88b752c80c26a 100644 --- a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/search/action/PutSearchApplicationActionRequestBWCSerializingTests.java +++ b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/search/action/PutSearchApplicationActionRequestBWCSerializingTests.java @@ -10,8 +10,8 @@ import org.elasticsearch.TransportVersion; import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.xcontent.XContentParser; +import org.elasticsearch.xpack.application.EnterpriseSearchModuleTestUtils; import org.elasticsearch.xpack.application.search.SearchApplication; -import org.elasticsearch.xpack.application.search.SearchApplicationTestUtils; import org.elasticsearch.xpack.core.ml.AbstractBWCSerializationTestCase; import java.io.IOException; @@ -28,7 +28,7 @@ protected Writeable.Reader instanceReader() @Override protected PutSearchApplicationAction.Request createTestInstance() { - SearchApplication searchApp = SearchApplicationTestUtils.randomSearchApplication(); + SearchApplication searchApp = EnterpriseSearchModuleTestUtils.randomSearchApplication(); this.searchApplicationName = searchApp.name(); return new PutSearchApplicationAction.Request(searchApp, randomBoolean()); } diff --git a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/search/action/SearchApplicationSearchRequestBWCSerializingTests.java b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/search/action/SearchApplicationSearchRequestBWCSerializingTests.java index a107d02cc2ab2..7c3b504655bf3 100644 --- a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/search/action/SearchApplicationSearchRequestBWCSerializingTests.java +++ b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/search/action/SearchApplicationSearchRequestBWCSerializingTests.java @@ -10,7 +10,7 @@ import org.elasticsearch.TransportVersion; import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.xcontent.XContentParser; -import org.elasticsearch.xpack.application.search.SearchApplicationTestUtils; +import org.elasticsearch.xpack.application.EnterpriseSearchModuleTestUtils; import org.elasticsearch.xpack.core.ml.AbstractBWCSerializationTestCase; import java.io.IOException; @@ -26,7 +26,7 @@ protected Writeable.Reader instanceReader() { protected SearchApplicationSearchRequest createTestInstance() { return new SearchApplicationSearchRequest( randomAlphaOfLengthBetween(1, 10), - SearchApplicationTestUtils.randomSearchApplicationQueryParams() + EnterpriseSearchModuleTestUtils.randomSearchApplicationQueryParams() ); } diff --git a/x-pack/plugin/security/qa/operator-privileges-tests/src/javaRestTest/java/org/elasticsearch/xpack/security/operator/Constants.java b/x-pack/plugin/security/qa/operator-privileges-tests/src/javaRestTest/java/org/elasticsearch/xpack/security/operator/Constants.java index 33503bc558795..8885c62dad55a 100644 --- a/x-pack/plugin/security/qa/operator-privileges-tests/src/javaRestTest/java/org/elasticsearch/xpack/security/operator/Constants.java +++ b/x-pack/plugin/security/qa/operator-privileges-tests/src/javaRestTest/java/org/elasticsearch/xpack/security/operator/Constants.java @@ -232,6 +232,7 @@ public class Constants { "cluster:admin/xpack/ml/upgrade_mode", "cluster:admin/xpack/monitoring/bulk", "cluster:admin/xpack/monitoring/migrate/alerts", + "cluster:admin/xpack/query_rule/put", "cluster:admin/xpack/query_rules/delete", "cluster:admin/xpack/query_rules/get", "cluster:admin/xpack/query_rules/list",