From 5433ecc953dd248ef980538595f28a7ad8d09276 Mon Sep 17 00:00:00 2001 From: Toshiya Kobayashi Date: Fri, 17 Nov 2023 18:28:17 +0900 Subject: [PATCH] [DROOLS-7590] Handle "action" and "actions" in JSON --- .../rulebook/integration/api/domain/Rule.java | 34 ++- .../integration/api/domain/RulesSet.java | 4 + .../rulebook/integration/api/ActionTest.java | 255 ++++++++++++++++++ .../rulebook/integration/api/JsonTest.java | 11 - 4 files changed, 287 insertions(+), 17 deletions(-) create mode 100644 drools-ansible-rulebook-integration-api/src/test/java/org/drools/ansible/rulebook/integration/api/ActionTest.java diff --git a/drools-ansible-rulebook-integration-api/src/main/java/org/drools/ansible/rulebook/integration/api/domain/Rule.java b/drools-ansible-rulebook-integration-api/src/main/java/org/drools/ansible/rulebook/integration/api/domain/Rule.java index d86ecc8c..fd05d167 100644 --- a/drools-ansible-rulebook-integration-api/src/main/java/org/drools/ansible/rulebook/integration/api/domain/Rule.java +++ b/drools-ansible-rulebook-integration-api/src/main/java/org/drools/ansible/rulebook/integration/api/domain/Rule.java @@ -10,22 +10,26 @@ import org.drools.ansible.rulebook.integration.api.domain.temporal.TimeWindowDefinition; import org.drools.ansible.rulebook.integration.api.rulesengine.RulesExecutionController; +import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; @JsonIgnoreProperties(ignoreUnknown = true) public class Rule { + private boolean enabled = true; private final RuleGenerationContext ruleGenerationContext = new RuleGenerationContext(); - private String name; + private String name; + + private Action action; - private Action action; + private List actions; - private RuleConfigurationOptions options; + private RuleConfigurationOptions options; - private Condition condition; + private Condition condition; public String getName() { return name; @@ -57,13 +61,31 @@ public AstCondition withCondition() { this.condition = condition; return condition; } - + + // If "actions" are used in JSON, then getAction returns the first action in the list public Action getAction() { return action; } public void setAction(MapAction action) { - this.action = action; + this.action = action; + + // If "action" is used in JSON, actions has the single action + this.actions = new ArrayList<>(); + this.actions.add(action); + } + + public void setActions(List actions) { + this.actions = actions; + + // If "actions" are used in JSON, action has the first action in the list + if (actions != null && !actions.isEmpty()) { + this.action = actions.get(0); + } + } + + public List getActions() { + return actions; } public void setGenericAction(Action action) { diff --git a/drools-ansible-rulebook-integration-api/src/main/java/org/drools/ansible/rulebook/integration/api/domain/RulesSet.java b/drools-ansible-rulebook-integration-api/src/main/java/org/drools/ansible/rulebook/integration/api/domain/RulesSet.java index fb57bd6e..4606d6c9 100644 --- a/drools-ansible-rulebook-integration-api/src/main/java/org/drools/ansible/rulebook/integration/api/domain/RulesSet.java +++ b/drools-ansible-rulebook-integration-api/src/main/java/org/drools/ansible/rulebook/integration/api/domain/RulesSet.java @@ -76,6 +76,10 @@ public int getDisabledRulesNumber() { return disabledRulesNumber; } + public List getRules() { + return rules; + } + public void setRules(List rules) { this.rules = rules; } diff --git a/drools-ansible-rulebook-integration-api/src/test/java/org/drools/ansible/rulebook/integration/api/ActionTest.java b/drools-ansible-rulebook-integration-api/src/test/java/org/drools/ansible/rulebook/integration/api/ActionTest.java new file mode 100644 index 00000000..9c406756 --- /dev/null +++ b/drools-ansible-rulebook-integration-api/src/test/java/org/drools/ansible/rulebook/integration/api/ActionTest.java @@ -0,0 +1,255 @@ +package org.drools.ansible.rulebook.integration.api; + +import java.util.LinkedHashMap; +import java.util.List; + +import org.drools.ansible.rulebook.integration.api.domain.Rule; +import org.drools.ansible.rulebook.integration.api.domain.RulesSet; +import org.drools.ansible.rulebook.integration.api.domain.actions.MapAction; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ActionTest { + + @Test + public void singleAction() { + // Generated by rules_with_assignment.yml in drools_jpy + String json = + """ + { + "hosts":[ + "localhost" + ], + "name":"Demo rules with assignment", + "rules":[ + { + "Rule":{ + "action":{ + "Action":{ + "action":"debug", + "action_args":{ + "events_event":"{{events.first}}" + } + } + }, + "condition":{ + "AllCondition":[ + { + "AssignmentExpression":{ + "lhs":{ + "Events":"first" + }, + "rhs":{ + "EqualsExpression":{ + "lhs":{ + "Event":"i" + }, + "rhs":{ + "Integer":67 + } + } + } + } + } + ] + }, + "enabled":true, + "name":"assignment" + } + } + ] + } + """; + + RulesSet rulesSet = RuleNotation.CoreNotation.INSTANCE.toRulesSet(RuleFormat.JSON, json); + Rule rule = rulesSet.getRules().get(0).getRule(); + + // assert getAction + MapAction action = (MapAction) rule.getAction(); + assertThat(action).isNotNull(); + assertThat(action.get("Action")).isNotNull(); + LinkedHashMap valueMap = (LinkedHashMap)action.get("Action"); + assertThat(valueMap.get("action")).isEqualTo("debug"); + assertThat(((LinkedHashMap)valueMap.get("action_args")).get("events_event")).isEqualTo("{{events.first}}"); + + // assert getActions same as getAction + List actions = (List) rule.getActions(); + assertThat(actions).hasSize(1); + MapAction firstAction = actions.get(0); + assertThat(firstAction.get("Action")).isNotNull(); + LinkedHashMap firstActionValueMap = (LinkedHashMap)firstAction.get("Action"); + assertThat(firstActionValueMap.get("action")).isEqualTo("debug"); + assertThat(((LinkedHashMap)firstActionValueMap.get("action_args")).get("events_event")).isEqualTo("{{events.first}}"); + } + + @Test + public void singleActionInActions() { + // Generated by retract_matching_facts.yml in drools_jpy + String json = + """ + { + "hosts":[ + "all" + ], + "name":"example", + "rules":[ + { + "Rule":{ + "actions":[ + { + "Action":{ + "action":"print_event", + "action_args":{ + "pretty":true + } + } + } + ], + "condition":{ + "AllCondition":[ + { + "GreaterThanExpression":{ + "lhs":{ + "Event":"i" + }, + "rhs":{ + "Integer":2 + } + } + }, + { + "GreaterThanExpression":{ + "lhs":{ + "Event":"x" + }, + "rhs":{ + "Integer":34 + } + } + } + ] + }, + "enabled":true, + "name":"r1" + } + } + ] + } + """; + + RulesSet rulesSet = RuleNotation.CoreNotation.INSTANCE.toRulesSet(RuleFormat.JSON, json); + Rule rule = rulesSet.getRules().get(0).getRule(); + + // assert getAction + MapAction action = (MapAction) rule.getAction(); + assertThat(action).isNotNull(); + assertThat(action.get("Action")).isNotNull(); + LinkedHashMap valueMap = (LinkedHashMap)action.get("Action"); + assertThat(valueMap.get("action")).isEqualTo("print_event"); + assertThat(((LinkedHashMap)valueMap.get("action_args")).get("pretty")).isEqualTo(true); + + // assert getActions same as getAction + List actions = (List) rule.getActions(); + assertThat(actions).hasSize(1); + MapAction firstAction = actions.get(0); + assertThat(firstAction.get("Action")).isNotNull(); + LinkedHashMap firstActionValueMap = (LinkedHashMap)firstAction.get("Action"); + assertThat(firstActionValueMap.get("action")).isEqualTo("print_event"); + assertThat(((LinkedHashMap)firstActionValueMap.get("action_args")).get("pretty")).isEqualTo(true); + } + + @Test + public void multipleActions() { + // Generated by 59_multiple_actions.yml in ansible-rulebook + String json = + """ + { + "name":"59 Multiple Actions", + "hosts":[ + "all" + ], + "rules":[ + { + "Rule":{ + "name":"r1", + "condition":{ + "AllCondition":[ + { + "EqualsExpression":{ + "lhs":{ + "Event":"i" + }, + "rhs":{ + "Integer":1 + } + } + } + ] + }, + "actions":[ + { + "Action":{ + "action":"debug", + "action_args":{ + "pretty":false + } + } + }, + { + "Action":{ + "action":"print_event", + "action_args":{ + "pretty":true + } + } + }, + { + "Action":{ + "action":"debug", + "action_args":{ + "msg":"Multiple Action Message1" + } + } + } + ], + "enabled":true + } + } + ] + } + """; + + RulesSet rulesSet = RuleNotation.CoreNotation.INSTANCE.toRulesSet(RuleFormat.JSON, json); + Rule rule = rulesSet.getRules().get(0).getRule(); + + // assert getAction, but only the first action + MapAction action = (MapAction) rule.getAction(); + assertThat(action).isNotNull(); + assertThat(action.get("Action")).isNotNull(); + LinkedHashMap valueMap = (LinkedHashMap) action.get("Action"); + assertThat(valueMap.get("action")).isEqualTo("debug"); + assertThat(((LinkedHashMap) valueMap.get("action_args")).get("pretty")).isEqualTo(false); + + // assert getActions + List actions = (List) rule.getActions(); + assertThat(actions).hasSize(3); + MapAction firstAction = actions.get(0); + assertThat(firstAction.get("Action")).isNotNull(); + LinkedHashMap firstActionValueMap = (LinkedHashMap) firstAction.get("Action"); + assertThat(firstActionValueMap.get("action")).isEqualTo("debug"); + assertThat(((LinkedHashMap) firstActionValueMap.get("action_args")).get("pretty")).isEqualTo(false); + + MapAction secondAction = actions.get(1); + assertThat(secondAction.get("Action")).isNotNull(); + LinkedHashMap secondActionValueMap = (LinkedHashMap) secondAction.get("Action"); + assertThat(secondActionValueMap.get("action")).isEqualTo("print_event"); + assertThat(((LinkedHashMap) secondActionValueMap.get("action_args")).get("pretty")).isEqualTo(true); + + MapAction thirdAction = actions.get(2); + assertThat(thirdAction.get("Action")).isNotNull(); + LinkedHashMap thirdActionValueMap = (LinkedHashMap) thirdAction.get("Action"); + assertThat(thirdActionValueMap.get("action")).isEqualTo("debug"); + assertThat(((LinkedHashMap) thirdActionValueMap.get("action_args")).get("msg")).isEqualTo("Multiple Action Message1"); + } +} diff --git a/drools-ansible-rulebook-integration-api/src/test/java/org/drools/ansible/rulebook/integration/api/JsonTest.java b/drools-ansible-rulebook-integration-api/src/test/java/org/drools/ansible/rulebook/integration/api/JsonTest.java index 4f6e991d..8cf99660 100644 --- a/drools-ansible-rulebook-integration-api/src/test/java/org/drools/ansible/rulebook/integration/api/JsonTest.java +++ b/drools-ansible-rulebook-integration-api/src/test/java/org/drools/ansible/rulebook/integration/api/JsonTest.java @@ -178,17 +178,6 @@ public void testProcessRuleWithUnknownAction() { rulesExecutor.dispose(); } - @Test - public void testProcessRuleIgnoringActionsTag() { - RulesExecutor rulesExecutor = RulesExecutorFactory.createFromJson("{ \"rules\": [ {\"Rule\": { \"name\": \"R1\", \"condition\":{ \"EqualsExpression\":{ \"lhs\":{ \"sensu\":\"data.i\" }, \"rhs\":{ \"Integer\":1 } } }, \"actions\": { \"post_event\": { \"ruleset\": \"Test rules4\", \"fact\": { \"j\": 1 } } } }} ] }\n"); - - List matchedRules = rulesExecutor.processFacts( "{ \"sensu\": { \"data\": { \"i\":1 } } }" ).join(); - assertEquals( 1, matchedRules.size() ); - assertEquals( "R1", matchedRules.get(0).getRule().getName() ); - - rulesExecutor.dispose(); - } - @Test public void testIsDefinedExpression() { RulesExecutor rulesExecutor = RulesExecutorFactory.createFromJson("{ \"rules\": [ {\"Rule\": { \"name\": \"R1\", \"condition\":{ \"IsDefinedExpression\":{ \"sensu\":\"data.i\" } } }} ] }");