diff --git a/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/rules/CreateRulesTests.java b/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/rules/CreateRulesTests.java index f8a80614e0..2e0cba0710 100644 --- a/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/rules/CreateRulesTests.java +++ b/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/rules/CreateRulesTests.java @@ -27,9 +27,16 @@ package org.alfresco.rest.rules; import static java.util.stream.Collectors.toList; -import static org.alfresco.rest.rules.RulesTestsUtils.createActionModel; +import static org.alfresco.rest.rules.RulesTestsUtils.RULE_NAME_DEFAULT; +import static org.alfresco.rest.rules.RulesTestsUtils.createDefaultActionModel; +import static org.alfresco.rest.rules.RulesTestsUtils.createEmptyConditionModel; import static org.alfresco.rest.rules.RulesTestsUtils.createRuleModel; -import static org.alfresco.utility.constants.UserRole.*; +import static org.alfresco.rest.rules.RulesTestsUtils.createRuleModelWithDefaultName; +import static org.alfresco.rest.rules.RulesTestsUtils.createRuleModelWithDefaultValues; +import static org.alfresco.utility.constants.UserRole.SiteCollaborator; +import static org.alfresco.utility.constants.UserRole.SiteConsumer; +import static org.alfresco.utility.constants.UserRole.SiteContributor; +import static org.alfresco.utility.constants.UserRole.SiteManager; import static org.alfresco.utility.model.FileModel.getRandomFileModel; import static org.alfresco.utility.model.FileType.TEXT_PLAIN; import static org.alfresco.utility.report.log.Step.STEP; @@ -60,6 +67,8 @@ import org.testng.annotations.Test; @Test(groups = {TestGroup.RULES}) public class CreateRulesTests extends RestTest { + private static final String IGNORE_ID = "id"; + private static final String IGNORE_IS_SHARED = "isShared"; private UserModel user; private SiteModel site; private FolderModel ruleFolder; @@ -80,14 +89,19 @@ public class CreateRulesTests extends RestTest @Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY }) public void createRule() { - RestRuleModel ruleModel = createRuleModel("ruleName"); + RestRuleModel ruleModel = createRuleModelWithDefaultValues(); RestRuleModel rule = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet() .createSingleRule(ruleModel); + RestRuleModel expectedRuleModel = createRuleModelWithDefaultValues(); + expectedRuleModel.setConditions(createEmptyConditionModel()); restClient.assertStatusCodeIs(CREATED); - rule.assertThat().field("id").isNotNull() - .assertThat().field("name").is("ruleName") + // TODO fix actions mapping and remove it from ignored fields, actual issue - difference: + // actual: actions=[RestActionBodyExecTemplateModel{actionDefinitionId='add-features', params={actionContext=rule, aspect-name={http://www.alfresco.org/model/audio/1.0}audio}}] + // expected: actions=[RestActionBodyExecTemplateModel{actionDefinitionId='set-property-value', params={aspect-name={http://www.alfresco.org/model/audio/1.0}audio, actionContext=rule}}] + rule.assertThat().isEqualTo(expectedRuleModel, IGNORE_ID, IGNORE_IS_SHARED, "actions") + .assertThat().field("id").isNotNull() .assertThat().field("isShared").isNull(); } @@ -257,6 +271,71 @@ public class CreateRulesTests extends RestTest restClient.assertLastError().containsSummary("Rule name is a mandatory parameter"); } + /** Check we can create a rule without description. */ + @Test (groups = { TestGroup.REST_API, TestGroup.RULES }) + public void createRuleWithoutDescription() + { + RestRuleModel ruleModel = createRuleModelWithDefaultName(); + UserModel admin = dataUser.getAdminUser(); + + RestRuleModel rule = restClient.authenticateUser(admin).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet() + .createSingleRule(ruleModel); + + restClient.assertStatusCodeIs(CREATED); + rule.assertThat().field("id").isNotNull() + .assertThat().field("name").is(RULE_NAME_DEFAULT) + .assertThat().field("description").isNull(); + } + + /** Check we can create a rule without specifying triggers but with the default "inbound" value. */ + @Test (groups = { TestGroup.REST_API, TestGroup.RULES }) + public void createRuleWithoutTriggers() + { + RestRuleModel ruleModel = createRuleModelWithDefaultName(); + UserModel admin = dataUser.getAdminUser(); + + RestRuleModel rule = restClient.authenticateUser(admin).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet() + .createSingleRule(ruleModel); + + restClient.assertStatusCodeIs(CREATED); + rule.assertThat().field("id").isNotNull() + .assertThat().field("name").is(RULE_NAME_DEFAULT) + .assertThat().field("triggers").is(List.of("inbound")); + } + + /** Check we can create a rule without error script. */ + @Test (groups = { TestGroup.REST_API, TestGroup.RULES }) + public void createRuleWithoutErrorScript() + { + RestRuleModel ruleModel = createRuleModelWithDefaultName(); + UserModel admin = dataUser.getAdminUser(); + + RestRuleModel rule = restClient.authenticateUser(admin).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet() + .createSingleRule(ruleModel); + + restClient.assertStatusCodeIs(CREATED); + rule.assertThat().field("id").isNotNull() + .assertThat().field("name").is(RULE_NAME_DEFAULT) + .assertThat().field("errorScript").isNull(); + } + + /** Check we can create a rule with irrelevant isShared flag, and it doesn't have impact to the process. */ + @Test (groups = { TestGroup.REST_API, TestGroup.RULES }) + public void createRuleWithSharedFlag() + { + RestRuleModel ruleModel = createRuleModelWithDefaultName(); + ruleModel.setIsShared(true); + UserModel admin = dataUser.getAdminUser(); + + RestRuleModel rule = restClient.authenticateUser(admin).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet() + .createSingleRule(ruleModel); + + restClient.assertStatusCodeIs(CREATED); + rule.assertThat().field("id").isNotNull() + .assertThat().field("name").is(RULE_NAME_DEFAULT) + .assertThat().field("isShared").isNull(); + } + /** Check we can create a rule. */ @Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY }) public void createRuleAndIncludeFieldsInResponse() @@ -280,7 +359,7 @@ public class CreateRulesTests extends RestTest STEP(String.format("Add a user with '%s' role in the private site's folder", userRole.toString())); UserModel userWithRole = dataUser.createRandomTestUser(); dataUser.addUserToSite(userWithRole, privateSite, userRole); - RestRuleModel ruleModel = createRuleModel("testRule", List.of(createActionModel())); + RestRuleModel ruleModel = createRuleModel("testRule", List.of(createDefaultActionModel())); return restClient.authenticateUser(userWithRole).withCoreAPI().usingNode(privateFolder).usingDefaultRuleSet().createSingleRule(ruleModel); } diff --git a/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/rules/RulesTestsUtils.java b/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/rules/RulesTestsUtils.java index a4ed08c0d6..87b8cd7f08 100644 --- a/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/rules/RulesTestsUtils.java +++ b/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/rules/RulesTestsUtils.java @@ -29,13 +29,47 @@ import java.util.List; import java.util.Map; import org.alfresco.rest.model.RestActionBodyExecTemplateModel; +import org.alfresco.rest.model.RestCompositeConditionDefinitionModel; import org.alfresco.rest.model.RestRuleModel; public class RulesTestsUtils { + static final String RULE_NAME_DEFAULT = "ruleName"; + static final String RULE_DESCRIPTION_DEFAULT = "rule description"; + static final boolean RULE_ENABLED_DEFAULT = true; + static final boolean RULE_CASCADE_DEFAULT = true; + static final boolean RULE_ASYNC_DEFAULT = true; + static final boolean RULE_SHARED_DEFAULT = false; + static final String RULE_ERROR_SCRIPT_DEFAULT = "error-script"; + static final List ruleTriggersDefault = List.of("inbound", "update", "outbound"); - public static RestRuleModel createRuleModel(String name) { - return createRuleModel(name, List.of(createActionModel())); + /** + * Create a rule model filled with default values. + * + * @return The created rule model. + */ + public static RestRuleModel createRuleModelWithDefaultValues() + { + RestRuleModel ruleModel = createRuleModelWithDefaultName(); + ruleModel.setDescription(RULE_DESCRIPTION_DEFAULT); + ruleModel.setEnabled(RULE_ENABLED_DEFAULT); + ruleModel.setCascade(RULE_CASCADE_DEFAULT); + ruleModel.setAsynchronous(RULE_ASYNC_DEFAULT); + ruleModel.setIsShared(RULE_SHARED_DEFAULT); + ruleModel.setTriggers(ruleTriggersDefault); + ruleModel.setErrorScript(RULE_ERROR_SCRIPT_DEFAULT); + + return ruleModel; + } + + public static RestRuleModel createRuleModelWithDefaultName() + { + return createRuleModel(RULE_NAME_DEFAULT, List.of(createDefaultActionModel())); + } + + public static RestRuleModel createRuleModel(String name) + { + return createRuleModel(name, List.of(createDefaultActionModel())); } /** @@ -58,11 +92,19 @@ public class RulesTestsUtils * * @return The created action model. */ - public static RestActionBodyExecTemplateModel createActionModel() + public static RestActionBodyExecTemplateModel createDefaultActionModel() { RestActionBodyExecTemplateModel restActionModel = new RestActionBodyExecTemplateModel(); restActionModel.setActionDefinitionId("add-features"); restActionModel.setParams(Map.of("aspect-name", "{http://www.alfresco.org/model/audio/1.0}audio", "actionContext", "rule")); return restActionModel; } + + public static RestCompositeConditionDefinitionModel createEmptyConditionModel() + { + RestCompositeConditionDefinitionModel conditions = new RestCompositeConditionDefinitionModel(); + conditions.setInverted(false); + conditions.setBooleanMode("and"); + return conditions; + } } diff --git a/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/rules/UpdateRulesTests.java b/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/rules/UpdateRulesTests.java index 036f420316..de4629a138 100644 --- a/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/rules/UpdateRulesTests.java +++ b/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/rules/UpdateRulesTests.java @@ -25,7 +25,7 @@ */ package org.alfresco.rest.rules; -import static org.alfresco.rest.rules.RulesTestsUtils.createActionModel; +import static org.alfresco.rest.rules.RulesTestsUtils.createDefaultActionModel; import static org.alfresco.rest.rules.RulesTestsUtils.createRuleModel; import static org.alfresco.utility.constants.UserRole.SiteCollaborator; import static org.alfresco.utility.report.log.Step.STEP; @@ -201,7 +201,7 @@ public class UpdateRulesTests extends RestTest private RestRuleModel createAndSaveRule(String name) { - return createAndSaveRule(name, List.of(createActionModel())); + return createAndSaveRule(name, List.of(createDefaultActionModel())); } /** diff --git a/remote-api/src/main/java/org/alfresco/rest/api/model/rules/Rule.java b/remote-api/src/main/java/org/alfresco/rest/api/model/rules/Rule.java index 8642c1493a..5e55c6d9b3 100644 --- a/remote-api/src/main/java/org/alfresco/rest/api/model/rules/Rule.java +++ b/remote-api/src/main/java/org/alfresco/rest/api/model/rules/Rule.java @@ -30,12 +30,14 @@ import java.util.List; import java.util.Objects; import java.util.stream.Collectors; +import org.alfresco.repo.action.ActionImpl; import org.alfresco.repo.action.executer.ScriptActionExecuter; import org.alfresco.rest.api.Nodes; import org.alfresco.rest.framework.resource.UniqueId; import org.alfresco.service.Experimental; import org.alfresco.service.cmr.action.CompositeAction; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.util.GUID; @Experimental public class Rule @@ -48,7 +50,7 @@ public class Rule private boolean asynchronous; private Boolean isShared; private String errorScript; - private List triggers; + private List triggers = List.of(RuleTrigger.INBOUND); private CompositeCondition conditions; private List actions; @@ -107,8 +109,21 @@ public class Rule final NodeRef nodeRef = (id != null) ? nodes.validateOrLookupNode(id, null) : null; ruleModel.setNodeRef(nodeRef); ruleModel.setTitle(name); - + ruleModel.setDescription(description); + ruleModel.setRuleDisabled(!enabled); + ruleModel.applyToChildren(cascade); + ruleModel.setExecuteAsynchronously(asynchronous); + if (triggers != null) + { + ruleModel.setRuleTypes(triggers.stream().map(RuleTrigger::getValue).collect(Collectors.toList())); + } ruleModel.setAction(Action.toCompositeAction(actions)); + if (errorScript != null) + { + final org.alfresco.service.cmr.action.Action compensatingAction = new ActionImpl(null, GUID.generate(), ScriptActionExecuter.NAME); + compensatingAction.setParameterValue(ScriptActionExecuter.PARAM_SCRIPTREF, errorScript); + ruleModel.getAction().setCompensatingAction(compensatingAction); + } return ruleModel; } @@ -203,7 +218,15 @@ public class Rule return triggers.stream().map(RuleTrigger::getValue).collect(Collectors.toList()); } - public void setTriggers(List triggers) + public void setTriggers(List triggers) + { + if (triggers != null) + { + this.triggers = triggers.stream().map(RuleTrigger::of).collect(Collectors.toList()); + } + } + + public void setRuleTriggers(List triggers) { this.triggers = triggers; } @@ -279,7 +302,7 @@ public class Rule private boolean asynchronous; private Boolean isShared; private String errorScript; - private List triggers; + private List triggers = List.of(RuleTrigger.INBOUND); private CompositeCondition conditions; private List actions; @@ -360,7 +383,7 @@ public class Rule rule.setAsynchronous(asynchronous); rule.setIsShared(isShared); rule.setErrorScript(errorScript); - rule.setTriggers(triggers); + rule.setRuleTriggers(triggers); rule.setConditions(conditions); rule.setActions(actions); return rule; diff --git a/remote-api/src/main/java/org/alfresco/rest/api/model/rules/RuleTrigger.java b/remote-api/src/main/java/org/alfresco/rest/api/model/rules/RuleTrigger.java index eab17ba0e5..a2b370329c 100644 --- a/remote-api/src/main/java/org/alfresco/rest/api/model/rules/RuleTrigger.java +++ b/remote-api/src/main/java/org/alfresco/rest/api/model/rules/RuleTrigger.java @@ -31,31 +31,15 @@ import org.alfresco.service.Experimental; @Experimental public enum RuleTrigger { - INBOUND("inbound"), - UPDATE("update"), - OUTBOUND("outbound"); - - RuleTrigger(String value) - { - this.value = value; - } - - private final String value; + INBOUND, UPDATE, OUTBOUND; public String getValue() { - return value; + return this.name().toLowerCase(); } public static RuleTrigger of(final String value) { - for (RuleTrigger ruleTrigger : values()) - { - if (ruleTrigger.value.equals(value)) { - return ruleTrigger; - } - } - - return null; + return RuleTrigger.valueOf(value.toUpperCase()); } } diff --git a/remote-api/src/test/java/org/alfresco/rest/api/RulesUnitTests.java b/remote-api/src/test/java/org/alfresco/rest/api/RulesUnitTests.java index 3a87bc3f4c..6718c031aa 100644 --- a/remote-api/src/test/java/org/alfresco/rest/api/RulesUnitTests.java +++ b/remote-api/src/test/java/org/alfresco/rest/api/RulesUnitTests.java @@ -27,6 +27,7 @@ package org.alfresco.rest.api; import org.alfresco.rest.api.impl.rules.NodeValidatorTest; +import org.alfresco.rest.api.impl.rules.RuleSetsImplTest; import org.alfresco.rest.api.model.rules.ActionTest; import org.alfresco.rest.api.model.rules.CompositeConditionTest; import org.alfresco.rest.api.impl.rules.RulesImplTest; @@ -42,6 +43,7 @@ import org.junit.runners.Suite; @Suite.SuiteClasses({ NodeRulesRelationTest.class, RulesImplTest.class, + RuleSetsImplTest.class, NodeValidatorTest.class, RuleTest.class, ActionTest.class, diff --git a/remote-api/src/test/java/org/alfresco/rest/api/model/rules/RuleTest.java b/remote-api/src/test/java/org/alfresco/rest/api/model/rules/RuleTest.java index ed0dd4186f..771e576f26 100644 --- a/remote-api/src/test/java/org/alfresco/rest/api/model/rules/RuleTest.java +++ b/remote-api/src/test/java/org/alfresco/rest/api/model/rules/RuleTest.java @@ -27,6 +27,8 @@ package org.alfresco.rest.api.model.rules; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.then; +import static org.mockito.Mockito.mock; import java.util.Collections; import java.util.List; @@ -34,15 +36,18 @@ import java.util.List; import org.alfresco.repo.action.ActionConditionImpl; import org.alfresco.repo.action.ActionImpl; import org.alfresco.repo.action.executer.ScriptActionExecuter; +import org.alfresco.rest.api.Nodes; import org.alfresco.service.Experimental; -import org.alfresco.service.cmr.action.Action; import org.alfresco.service.cmr.action.ActionCondition; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.rule.RuleType; import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; @Experimental +@RunWith(MockitoJUnitRunner.class) public class RuleTest { private static final String RULE_ID = "fake-rule-id"; @@ -51,6 +56,8 @@ public class RuleTest private static final boolean RULE_ENABLED = true; private static final boolean RULE_CASCADE = true; private static final boolean RULE_ASYNC = true; + private static final boolean RULE_SHARED = true; + private static final String ACTION_DEFINITION_NAME = "action-def-name"; private static final String ERROR_SCRIPT = "error-script-ref"; @Test @@ -79,6 +86,51 @@ public class RuleTest } + @Test + public void testToServiceModel() + { + final Nodes nodesMock = mock(Nodes.class); + final Rule rule = createRuleWithDefaultValues(); + rule.setActions(List.of(Action.builder().actionDefinitionId(ACTION_DEFINITION_NAME).create())); + final org.alfresco.service.cmr.rule.Rule expectedRuleModel = createRuleModel(); + final org.alfresco.service.cmr.action.Action expectedCompensatingActionModel = createCompensatingActionModel(); + + // when + final org.alfresco.service.cmr.rule.Rule actualRuleModel = rule.toServiceModel(nodesMock); + + then(nodesMock).should().validateOrLookupNode(RULE_ID, null); + then(nodesMock).shouldHaveNoMoreInteractions(); + assertThat(actualRuleModel) + .isNotNull() + .usingRecursiveComparison().ignoringFields("nodeRef", "action") + .isEqualTo(expectedRuleModel); + assertThat(actualRuleModel.getAction()) + .isNotNull(); + assertThat(actualRuleModel.getAction().getCompensatingAction()) + .isNotNull() + .usingRecursiveComparison().ignoringFields("id") + .isEqualTo(expectedCompensatingActionModel); + } + + @Test + public void testToServiceModel_withNullValues() + { + final Nodes nodesMock = mock(Nodes.class); + final Rule rule = new Rule(); + final org.alfresco.service.cmr.rule.Rule expectedRuleModel = new org.alfresco.service.cmr.rule.Rule(); + expectedRuleModel.setRuleDisabled(true); + + // when + final org.alfresco.service.cmr.rule.Rule actualRuleModel = rule.toServiceModel(nodesMock); + + then(nodesMock).shouldHaveNoInteractions(); + assertThat(actualRuleModel) + .isNotNull() + .usingRecursiveComparison() + .ignoringFields("ruleTypes") + .isEqualTo(expectedRuleModel); + } + private static org.alfresco.service.cmr.rule.Rule createRuleModel() { final NodeRef nodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, RULE_ID); final org.alfresco.service.cmr.rule.Rule ruleModel = new org.alfresco.service.cmr.rule.Rule(nodeRef); @@ -88,17 +140,27 @@ public class RuleTest ruleModel.applyToChildren(RULE_CASCADE); ruleModel.setExecuteAsynchronously(RULE_ASYNC); ruleModel.setRuleTypes(List.of(RuleType.INBOUND, RuleType.UPDATE)); - final Action compensatingAction = new ActionImpl(nodeRef, "compensatingActionId", "compensatingActionDefName"); - compensatingAction.setParameterValue(ScriptActionExecuter.PARAM_SCRIPTREF, ERROR_SCRIPT); - final ActionCondition actionCondition = new ActionConditionImpl("actionConditionId", "actionConditionDefName"); - final Action action = new ActionImpl(nodeRef, "actionId", "actionDefName"); - action.setCompensatingAction(compensatingAction); - action.addActionCondition(actionCondition); - ruleModel.setAction(action); + ruleModel.setAction(createActionModel()); return ruleModel; } + private static org.alfresco.service.cmr.action.Action createActionModel() { + final ActionCondition actionCondition = new ActionConditionImpl("action-condition-id", "action-condition-def-name"); + final org.alfresco.service.cmr.action.Action actionModel = new ActionImpl(null, "action-id", ACTION_DEFINITION_NAME); + actionModel.setCompensatingAction(createCompensatingActionModel()); + actionModel.addActionCondition(actionCondition); + + return actionModel; + } + + private static org.alfresco.service.cmr.action.Action createCompensatingActionModel() { + final org.alfresco.service.cmr.action.Action compensatingActionModel = new ActionImpl(null, "compensating-action-id", ScriptActionExecuter.NAME); + compensatingActionModel.setParameterValue(ScriptActionExecuter.PARAM_SCRIPTREF, ERROR_SCRIPT); + + return compensatingActionModel; + } + private static Rule createRuleWithDefaultValues() { return Rule.builder() .id(RULE_ID)