From af97aca661e933ad99eb2613bcedd32dab1d0100 Mon Sep 17 00:00:00 2001 From: Tom Page Date: Thu, 4 Aug 2022 16:27:51 +0100 Subject: [PATCH] ACS-3360 GET APIs for rule sets. (#1263) ACS-3360 GET APIs for rule sets. Move RulesImpl and RuleSetsImpl into their own package. Split out node validation into a new class. --- .../java/org/alfresco/rest/api/RuleSets.java | 61 ++ .../NodeValidator.java} | 132 +--- .../rest/api/impl/rules/RuleSetsImpl.java | 80 +++ .../rest/api/impl/rules/RulesImpl.java | 129 ++++ .../rest/api/model/rules/RuleSet.java | 8 - .../rest/api/nodes/NodeRuleSetsRelation.java | 73 +- .../alfresco/public-rest-context.xml | 37 +- .../org/alfresco/rest/api/RulesUnitTests.java | 4 +- .../alfresco/rest/api/impl/RulesImplTest.java | 667 ------------------ .../api/impl/rules/NodeValidatorTest.java | 379 ++++++++++ .../rest/api/impl/rules/RuleSetsImplTest.java | 133 ++++ .../rest/api/impl/rules/RulesImplTest.java | 614 ++++++++++++++++ 12 files changed, 1531 insertions(+), 786 deletions(-) create mode 100644 remote-api/src/main/java/org/alfresco/rest/api/RuleSets.java rename remote-api/src/main/java/org/alfresco/rest/api/impl/{RulesImpl.java => rules/NodeValidator.java} (60%) create mode 100644 remote-api/src/main/java/org/alfresco/rest/api/impl/rules/RuleSetsImpl.java create mode 100644 remote-api/src/main/java/org/alfresco/rest/api/impl/rules/RulesImpl.java delete mode 100644 remote-api/src/test/java/org/alfresco/rest/api/impl/RulesImplTest.java create mode 100644 remote-api/src/test/java/org/alfresco/rest/api/impl/rules/NodeValidatorTest.java create mode 100644 remote-api/src/test/java/org/alfresco/rest/api/impl/rules/RuleSetsImplTest.java create mode 100644 remote-api/src/test/java/org/alfresco/rest/api/impl/rules/RulesImplTest.java diff --git a/remote-api/src/main/java/org/alfresco/rest/api/RuleSets.java b/remote-api/src/main/java/org/alfresco/rest/api/RuleSets.java new file mode 100644 index 0000000000..786ce0be1a --- /dev/null +++ b/remote-api/src/main/java/org/alfresco/rest/api/RuleSets.java @@ -0,0 +1,61 @@ +/* + * #%L + * Alfresco Remote API + * %% + * Copyright (C) 2005 - 2022 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ +package org.alfresco.rest.api; + +import java.util.List; + +import org.alfresco.rest.api.model.rules.Rule; +import org.alfresco.rest.api.model.rules.RuleSet; +import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo; +import org.alfresco.rest.framework.resource.parameters.Paging; +import org.alfresco.service.Experimental; + +/** + * Rule sets API. + */ +@Experimental +public interface RuleSets +{ + /** + * Get rule sets for a folder. + * + * @param folderNodeId Folder node ID + * @param paging {@link Paging} information + * @param includes List of fields to include in the rule set + * @return {@link CollectionWithPagingInfo} containing a list page of rule sets + */ + CollectionWithPagingInfo getRuleSets(String folderNodeId, List includes, Paging paging); + + /** + * Get the rule set with the given ID and check associations with the folder node. + * + * @param folderNodeId Folder node ID + * @param ruleSetId Rule set ID + * @param includes List of fields to include in the rule set + * @return {@link RuleSet} definition + */ + RuleSet getRuleSetById(String folderNodeId, String ruleSetId, List includes); +} diff --git a/remote-api/src/main/java/org/alfresco/rest/api/impl/RulesImpl.java b/remote-api/src/main/java/org/alfresco/rest/api/impl/rules/NodeValidator.java similarity index 60% rename from remote-api/src/main/java/org/alfresco/rest/api/impl/RulesImpl.java rename to remote-api/src/main/java/org/alfresco/rest/api/impl/rules/NodeValidator.java index bf59e496e0..eaa3568f9c 100644 --- a/remote-api/src/main/java/org/alfresco/rest/api/impl/RulesImpl.java +++ b/remote-api/src/main/java/org/alfresco/rest/api/impl/rules/NodeValidator.java @@ -23,123 +23,33 @@ * along with Alfresco. If not, see . * #L% */ - -package org.alfresco.rest.api.impl; +package org.alfresco.rest.api.impl.rules; import static org.alfresco.service.cmr.security.AccessStatus.ALLOWED; import static org.alfresco.service.cmr.security.PermissionService.CHANGE_PERMISSIONS; -import java.util.List; import java.util.Set; -import java.util.stream.Collectors; import org.alfresco.model.ContentModel; import org.alfresco.repo.rule.RuleModel; import org.alfresco.rest.api.Nodes; -import org.alfresco.rest.api.Rules; -import org.alfresco.rest.api.model.rules.Rule; import org.alfresco.rest.api.model.rules.RuleSet; import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException; import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException; import org.alfresco.rest.framework.core.exceptions.RelationshipResourceNotFoundException; -import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo; -import org.alfresco.rest.framework.resource.parameters.ListPage; -import org.alfresco.rest.framework.resource.parameters.Paging; -import org.alfresco.service.Experimental; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.rule.RuleService; import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.namespace.QName; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -@Experimental -public class RulesImpl implements Rules +/** Responsible for validating nodes when working with rules. */ +public class NodeValidator { - private static final Logger LOGGER = LoggerFactory.getLogger(RulesImpl.class); private static final String RULE_SET_EXPECTED_TYPE_NAME = "rule set"; private Nodes nodes; - - private PermissionService permissionService; - private RuleService ruleService; - - @Override - public CollectionWithPagingInfo getRules(final String folderNodeId, final String ruleSetId, final Paging paging) - { - final NodeRef folderNodeRef = validateFolderNode(folderNodeId, false); - final NodeRef ruleSetNodeRef = validateRuleSetNode(ruleSetId, folderNodeRef); - - final boolean isShared = isRuleSetNotNullAndShared(ruleSetNodeRef); - final List rules = ruleService.getRules(folderNodeRef).stream() - .map(ruleModel -> Rule.from(ruleModel, isShared)) - .collect(Collectors.toList()); - - return ListPage.of(rules, paging); - } - - @Override - public Rule getRuleById(final String folderNodeId, final String ruleSetId, final String ruleId) - { - final NodeRef folderNodeRef = validateFolderNode(folderNodeId, false); - final NodeRef ruleSetNodeRef = validateRuleSetNode(ruleSetId, folderNodeRef); - final NodeRef ruleNodeRef = validateRuleNode(ruleId, ruleSetNodeRef); - - return Rule.from(ruleService.getRule(ruleNodeRef), isRuleSetNotNullAndShared(ruleSetNodeRef)); - } - - @Override - public List createRules(final String folderNodeId, final String ruleSetId, final List rules) - { - final NodeRef folderNodeRef = validateFolderNode(folderNodeId, true); - // Don't validate the ruleset node if -default- is passed since we may need to create it. - final NodeRef ruleSetNodeRef = (RuleSet.isNotDefaultId(ruleSetId)) ? validateRuleSetNode(ruleSetId, folderNodeRef) : null; - - return rules.stream() - .map(rule -> rule.toServiceModel(nodes)) - .map(rule -> ruleService.saveRule(folderNodeRef, rule)) - .map(rule -> Rule.from(rule, isRuleSetNotNullAndShared(ruleSetNodeRef, folderNodeRef))) - .collect(Collectors.toList()); - } - - @Override - public Rule updateRuleById(String folderNodeId, String ruleSetId, String ruleId, Rule rule) - { - LOGGER.debug("Updating rule in folder {}, rule set {}, rule {} to {}", folderNodeId, ruleSetId, ruleId, rule); - - NodeRef folderNodeRef = validateFolderNode(folderNodeId, true); - NodeRef ruleSetNodeRef = validateRuleSetNode(ruleSetId, folderNodeRef); - validateRuleNode(ruleId, ruleSetNodeRef); - - boolean shared = isRuleSetNotNullAndShared(ruleSetNodeRef, folderNodeRef); - return Rule.from(ruleService.saveRule(folderNodeRef, rule.toServiceModel(nodes)), shared); - } - - @Override - public void deleteRuleById(String folderNodeId, String ruleSetId, String ruleId) - { - final NodeRef folderNodeRef = validateFolderNode(folderNodeId, true); - final NodeRef ruleSetNodeRef = validateRuleSetNode(ruleSetId, folderNodeRef); - final NodeRef ruleNodeRef = validateRuleNode(ruleId, ruleSetNodeRef); - final org.alfresco.service.cmr.rule.Rule rule = ruleService.getRule(ruleNodeRef); - ruleService.removeRule(folderNodeRef, rule); - } - - public void setNodes(Nodes nodes) - { - this.nodes = nodes; - } - - public void setPermissionService(PermissionService permissionService) - { - this.permissionService = permissionService; - } - - public void setRuleService(RuleService ruleService) - { - this.ruleService = ruleService; - } + private PermissionService permissionService; /** * Validates if folder node exists and the user has permission to use it. @@ -150,7 +60,7 @@ public class RulesImpl implements Rules * @throws InvalidArgumentException if node is not of an expected type * @throws PermissionDeniedException if the user doesn't have the appropriate permission for the folder. */ - private NodeRef validateFolderNode(final String folderNodeId, boolean requireChangePermission) + public NodeRef validateFolderNode(final String folderNodeId, boolean requireChangePermission) { final NodeRef nodeRef = nodes.validateOrLookupNode(folderNodeId, null); if (requireChangePermission) @@ -180,7 +90,7 @@ public class RulesImpl implements Rules * @return rule set node reference * @throws InvalidArgumentException in case of not matching associated folder node */ - private NodeRef validateRuleSetNode(final String ruleSetId, final NodeRef associatedFolderNodeRef) + public NodeRef validateRuleSetNode(final String ruleSetId, final NodeRef associatedFolderNodeRef) { if (RuleSet.isDefaultId(ruleSetId)) { @@ -194,13 +104,15 @@ public class RulesImpl implements Rules } final NodeRef ruleSetNodeRef = validateNode(ruleSetId, ContentModel.TYPE_SYSTEM_FOLDER, RULE_SET_EXPECTED_TYPE_NAME); - if (!ruleService.isRuleSetAssociatedWithFolder(ruleSetNodeRef, associatedFolderNodeRef)) { + if (!ruleService.isRuleSetAssociatedWithFolder(ruleSetNodeRef, associatedFolderNodeRef)) + { throw new InvalidArgumentException("Rule set is not associated with folder node!"); } return ruleSetNodeRef; } + /** * Validates if rule node exists and associated rule set node matches. * @@ -209,7 +121,7 @@ public class RulesImpl implements Rules * @return rule node reference * @throws InvalidArgumentException in case of not matching associated rule set node */ - private NodeRef validateRuleNode(final String ruleId, final NodeRef associatedRuleSetNodeRef) + public NodeRef validateRuleNode(final String ruleId, final NodeRef associatedRuleSetNodeRef) { final NodeRef ruleNodeRef = validateNode(ruleId, RuleModel.TYPE_RULE, null); if (associatedRuleSetNodeRef != null && !ruleService.isRuleAssociatedWithRuleSet(ruleNodeRef, associatedRuleSetNodeRef)) @@ -231,13 +143,14 @@ public class RulesImpl implements Rules private void verifyNodeType(final NodeRef nodeRef, final QName expectedType, final String expectedTypeName) { final Set expectedTypes = Set.of(expectedType); - if (!nodes.nodeMatches(nodeRef, expectedTypes, null)) { - final String expectedTypeLocalName = (expectedTypeName != null)? expectedTypeName : expectedType.getLocalName(); + if (!nodes.nodeMatches(nodeRef, expectedTypes, null)) + { + final String expectedTypeLocalName = (expectedTypeName != null) ? expectedTypeName : expectedType.getLocalName(); throw new InvalidArgumentException(String.format("NodeId of a %s is expected!", expectedTypeLocalName)); } } - private boolean isRuleSetNotNullAndShared(final NodeRef ruleSetNodeRef, final NodeRef folderNodeRef) + public boolean isRuleSetNotNullAndShared(final NodeRef ruleSetNodeRef, final NodeRef folderNodeRef) { if (ruleSetNodeRef == null && folderNodeRef != null) { @@ -250,8 +163,23 @@ public class RulesImpl implements Rules } } - private boolean isRuleSetNotNullAndShared(final NodeRef ruleSetNodeRef) + public boolean isRuleSetNotNullAndShared(final NodeRef ruleSetNodeRef) { return ruleSetNodeRef != null && ruleService.isRuleSetShared(ruleSetNodeRef); } + + public void setPermissionService(PermissionService permissionService) + { + this.permissionService = permissionService; + } + + public void setRuleService(RuleService ruleService) + { + this.ruleService = ruleService; + } + + public void setNodes(Nodes nodes) + { + this.nodes = nodes; + } } diff --git a/remote-api/src/main/java/org/alfresco/rest/api/impl/rules/RuleSetsImpl.java b/remote-api/src/main/java/org/alfresco/rest/api/impl/rules/RuleSetsImpl.java new file mode 100644 index 0000000000..6f05b225ef --- /dev/null +++ b/remote-api/src/main/java/org/alfresco/rest/api/impl/rules/RuleSetsImpl.java @@ -0,0 +1,80 @@ +/* + * #%L + * Alfresco Remote API + * %% + * Copyright (C) 2005 - 2022 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ + +package org.alfresco.rest.api.impl.rules; + +import static java.util.stream.Collectors.toList; + +import java.util.List; +import java.util.Optional; + +import org.alfresco.rest.api.RuleSets; +import org.alfresco.rest.api.model.rules.RuleSet; +import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo; +import org.alfresco.rest.framework.resource.parameters.ListPage; +import org.alfresco.rest.framework.resource.parameters.Paging; +import org.alfresco.service.Experimental; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.rule.RuleService; + +@Experimental +public class RuleSetsImpl implements RuleSets +{ + private RuleService ruleService; + private NodeValidator validator; + + @Override + public CollectionWithPagingInfo getRuleSets(String folderNodeId, List includes, Paging paging) + { + NodeRef folderNode = validator.validateFolderNode(folderNodeId, false); + + NodeRef ruleSetNode = ruleService.getRuleSetNode(folderNode); + List ruleSets = Optional.ofNullable(ruleSetNode) + .map(NodeRef::getId) + .map(RuleSet::of).stream().collect(toList()); + + return ListPage.of(ruleSets, paging); + } + + @Override + public RuleSet getRuleSetById(String folderNodeId, String ruleSetId, List includes) + { + NodeRef folderNode = validator.validateFolderNode(folderNodeId, false); + NodeRef ruleSetNode = validator.validateRuleSetNode(ruleSetId, folderNode); + + return RuleSet.of(ruleSetNode.getId()); + } + + public void setValidator(NodeValidator validator) + { + this.validator = validator; + } + + public void setRuleService(RuleService ruleService) + { + this.ruleService = ruleService; + } +} diff --git a/remote-api/src/main/java/org/alfresco/rest/api/impl/rules/RulesImpl.java b/remote-api/src/main/java/org/alfresco/rest/api/impl/rules/RulesImpl.java new file mode 100644 index 0000000000..929ad97f96 --- /dev/null +++ b/remote-api/src/main/java/org/alfresco/rest/api/impl/rules/RulesImpl.java @@ -0,0 +1,129 @@ +/* + * #%L + * Alfresco Remote API + * %% + * Copyright (C) 2005 - 2022 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ + +package org.alfresco.rest.api.impl.rules; + +import java.util.List; +import java.util.stream.Collectors; + +import org.alfresco.rest.api.Nodes; +import org.alfresco.rest.api.Rules; +import org.alfresco.rest.api.model.rules.Rule; +import org.alfresco.rest.api.model.rules.RuleSet; +import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo; +import org.alfresco.rest.framework.resource.parameters.ListPage; +import org.alfresco.rest.framework.resource.parameters.Paging; +import org.alfresco.service.Experimental; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.rule.RuleService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Experimental +public class RulesImpl implements Rules +{ + private static final Logger LOGGER = LoggerFactory.getLogger(RulesImpl.class); + + private Nodes nodes; + private RuleService ruleService; + private NodeValidator validator; + + @Override + public CollectionWithPagingInfo getRules(final String folderNodeId, final String ruleSetId, final Paging paging) + { + final NodeRef folderNodeRef = validator.validateFolderNode(folderNodeId, false); + final NodeRef ruleSetNodeRef = validator.validateRuleSetNode(ruleSetId, folderNodeRef); + + final boolean isShared = validator.isRuleSetNotNullAndShared(ruleSetNodeRef); + final List rules = ruleService.getRules(folderNodeRef).stream() + .map(ruleModel -> Rule.from(ruleModel, isShared)) + .collect(Collectors.toList()); + + return ListPage.of(rules, paging); + } + + @Override + public Rule getRuleById(final String folderNodeId, final String ruleSetId, final String ruleId) + { + final NodeRef folderNodeRef = validator.validateFolderNode(folderNodeId, false); + final NodeRef ruleSetNodeRef = validator.validateRuleSetNode(ruleSetId, folderNodeRef); + final NodeRef ruleNodeRef = validator.validateRuleNode(ruleId, ruleSetNodeRef); + + return Rule.from(ruleService.getRule(ruleNodeRef), validator.isRuleSetNotNullAndShared(ruleSetNodeRef)); + } + + @Override + public List createRules(final String folderNodeId, final String ruleSetId, final List rules) + { + final NodeRef folderNodeRef = validator.validateFolderNode(folderNodeId, true); + // Don't validate the ruleset node if -default- is passed since we may need to create it. + final NodeRef ruleSetNodeRef = (RuleSet.isNotDefaultId(ruleSetId)) ? validator.validateRuleSetNode(ruleSetId, folderNodeRef) : null; + + return rules.stream() + .map(rule -> rule.toServiceModel(nodes)) + .map(rule -> ruleService.saveRule(folderNodeRef, rule)) + .map(rule -> Rule.from(rule, validator.isRuleSetNotNullAndShared(ruleSetNodeRef, folderNodeRef))) + .collect(Collectors.toList()); + } + + @Override + public Rule updateRuleById(String folderNodeId, String ruleSetId, String ruleId, Rule rule) + { + LOGGER.debug("Updating rule in folder {}, rule set {}, rule {} to {}", folderNodeId, ruleSetId, ruleId, rule); + + NodeRef folderNodeRef = validator.validateFolderNode(folderNodeId, true); + NodeRef ruleSetNodeRef = validator.validateRuleSetNode(ruleSetId, folderNodeRef); + validator.validateRuleNode(ruleId, ruleSetNodeRef); + + boolean shared = validator.isRuleSetNotNullAndShared(ruleSetNodeRef, folderNodeRef); + return Rule.from(ruleService.saveRule(folderNodeRef, rule.toServiceModel(nodes)), shared); + } + + @Override + public void deleteRuleById(String folderNodeId, String ruleSetId, String ruleId) + { + final NodeRef folderNodeRef = validator.validateFolderNode(folderNodeId, true); + final NodeRef ruleSetNodeRef = validator.validateRuleSetNode(ruleSetId, folderNodeRef); + final NodeRef ruleNodeRef = validator.validateRuleNode(ruleId, ruleSetNodeRef); + final org.alfresco.service.cmr.rule.Rule rule = ruleService.getRule(ruleNodeRef); + ruleService.removeRule(folderNodeRef, rule); + } + + public void setNodes(Nodes nodes) + { + this.nodes = nodes; + } + + public void setRuleService(RuleService ruleService) + { + this.ruleService = ruleService; + } + + public void setValidator(NodeValidator validator) + { + this.validator = validator; + } +} diff --git a/remote-api/src/main/java/org/alfresco/rest/api/model/rules/RuleSet.java b/remote-api/src/main/java/org/alfresco/rest/api/model/rules/RuleSet.java index 076e0b9c81..de1fbab8cd 100644 --- a/remote-api/src/main/java/org/alfresco/rest/api/model/rules/RuleSet.java +++ b/remote-api/src/main/java/org/alfresco/rest/api/model/rules/RuleSet.java @@ -44,14 +44,6 @@ public class RuleSet .create(); } - public boolean isNotDefaultId() { - return isNotDefaultId(this.id); - } - - public boolean isDefaultId() { - return isDefaultId(this.id); - } - public static boolean isNotDefaultId(final String id) { return !isDefaultId(id); } diff --git a/remote-api/src/main/java/org/alfresco/rest/api/nodes/NodeRuleSetsRelation.java b/remote-api/src/main/java/org/alfresco/rest/api/nodes/NodeRuleSetsRelation.java index 4a3d3163f9..ac6963a45c 100644 --- a/remote-api/src/main/java/org/alfresco/rest/api/nodes/NodeRuleSetsRelation.java +++ b/remote-api/src/main/java/org/alfresco/rest/api/nodes/NodeRuleSetsRelation.java @@ -26,15 +26,84 @@ package org.alfresco.rest.api.nodes; +import javax.servlet.http.HttpServletResponse; + +import java.util.List; + +import org.alfresco.rest.api.RuleSets; +import org.alfresco.rest.api.model.rules.RuleSet; +import org.alfresco.rest.framework.WebApiDescription; +import org.alfresco.rest.framework.core.exceptions.RelationshipResourceNotFoundException; import org.alfresco.rest.framework.resource.RelationshipResource; +import org.alfresco.rest.framework.resource.actions.interfaces.RelationshipResourceAction; +import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo; +import org.alfresco.rest.framework.resource.parameters.Paging; +import org.alfresco.rest.framework.resource.parameters.Parameters; import org.alfresco.service.Experimental; +import org.alfresco.util.PropertyCheck; +import org.springframework.beans.factory.InitializingBean; /** * Folder node rule sets. - * */ @Experimental @RelationshipResource(name = "rule-sets", entityResource = NodesEntityResource.class, title = "Folder node rule sets") -public class NodeRuleSetsRelation +public class NodeRuleSetsRelation implements RelationshipResourceAction.Read, + RelationshipResourceAction.ReadById, + InitializingBean { + private RuleSets ruleSets; + + @Override + public void afterPropertiesSet() throws Exception + { + PropertyCheck.mandatory(this, "ruleSets", ruleSets); + } + + /** + * List rule sets for given folder. + *

+ * - GET /nodes/{folderNodeId}/rule-sets + * + * @param folderNodeId The id of the folder node. + * @param parameters Contains paging information and information about which fields to include + * @return {@link CollectionWithPagingInfo} containing a page of rule sets + */ + @WebApiDescription ( + title = "Get rule sets for a folder", + description = "Returns a paged list of rule sets for given node", + successStatus = HttpServletResponse.SC_OK + ) + @Override + public CollectionWithPagingInfo readAll(String folderNodeId, Parameters parameters) + { + return ruleSets.getRuleSets(folderNodeId, parameters.getInclude(), parameters.getPaging()); + } + + /** + * Get single folder rule for given node's, rule set's and rule's IDs. + *

+ * - GET /nodes/{folderNodeId}/rule-sets/{ruleSetId} + * + * @param folderNodeId - entity resource context for this relationship + * @param ruleSetId - rule set node ID (associated with folder node) + * @param parameters Contains information about which fields to include + * @return {@link RuleSet} definition + * @throws RelationshipResourceNotFoundException in case resource was not found + */ + @WebApiDescription ( + title = "Get rule set", + description = "Returns a single rule set for the given node", + successStatus = HttpServletResponse.SC_OK + ) + @Override + public RuleSet readById(String folderNodeId, String ruleSetId, Parameters parameters) throws RelationshipResourceNotFoundException + { + return ruleSets.getRuleSetById(folderNodeId, ruleSetId, parameters.getInclude()); + } + + public void setRuleSets(RuleSets ruleSets) + { + this.ruleSets = ruleSets; + } } diff --git a/remote-api/src/main/resources/alfresco/public-rest-context.xml b/remote-api/src/main/resources/alfresco/public-rest-context.xml index a8a1efd97a..ec123dbef4 100644 --- a/remote-api/src/main/resources/alfresco/public-rest-context.xml +++ b/remote-api/src/main/resources/alfresco/public-rest-context.xml @@ -850,9 +850,38 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -866,10 +895,6 @@ - - - - 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 cccc62de9b..3a87bc3f4c 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 @@ -26,9 +26,10 @@ package org.alfresco.rest.api; -import org.alfresco.rest.api.impl.RulesImplTest; +import org.alfresco.rest.api.impl.rules.NodeValidatorTest; import org.alfresco.rest.api.model.rules.ActionTest; import org.alfresco.rest.api.model.rules.CompositeConditionTest; +import org.alfresco.rest.api.impl.rules.RulesImplTest; import org.alfresco.rest.api.model.rules.RuleTest; import org.alfresco.rest.api.model.rules.SimpleConditionTest; import org.alfresco.rest.api.nodes.NodeRulesRelationTest; @@ -41,6 +42,7 @@ import org.junit.runners.Suite; @Suite.SuiteClasses({ NodeRulesRelationTest.class, RulesImplTest.class, + NodeValidatorTest.class, RuleTest.class, ActionTest.class, SimpleConditionTest.class, diff --git a/remote-api/src/test/java/org/alfresco/rest/api/impl/RulesImplTest.java b/remote-api/src/test/java/org/alfresco/rest/api/impl/RulesImplTest.java deleted file mode 100644 index a2fd5308eb..0000000000 --- a/remote-api/src/test/java/org/alfresco/rest/api/impl/RulesImplTest.java +++ /dev/null @@ -1,667 +0,0 @@ -/* - * #%L - * Alfresco Remote API - * %% - * Copyright (C) 2005 - 2022 Alfresco Software Limited - * %% - * This file is part of the Alfresco software. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - * #L% - */ - -package org.alfresco.rest.api.impl; - -import static java.util.Collections.emptyList; - -import static org.alfresco.rest.api.model.rules.RuleSet.DEFAULT_ID; -import static org.alfresco.service.cmr.security.AccessStatus.ALLOWED; -import static org.alfresco.service.cmr.security.AccessStatus.DENIED; -import static org.alfresco.service.cmr.security.PermissionService.CHANGE_PERMISSIONS; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.isNull; -import static org.mockito.BDDMockito.given; -import static org.mockito.BDDMockito.then; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import junit.framework.TestCase; -import org.alfresco.repo.action.ActionImpl; -import org.alfresco.rest.api.Nodes; -import org.alfresco.rest.api.model.rules.CompositeCondition; -import org.alfresco.rest.api.model.rules.Rule; -import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException; -import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException; -import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException; -import org.alfresco.rest.framework.core.exceptions.RelationshipResourceNotFoundException; -import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo; -import org.alfresco.rest.framework.resource.parameters.Paging; -import org.alfresco.service.Experimental; -import org.alfresco.service.cmr.action.Action; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.StoreRef; -import org.alfresco.service.cmr.rule.RuleService; -import org.alfresco.service.cmr.security.PermissionService; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.mockito.junit.MockitoJUnitRunner; - -@Experimental -@RunWith(MockitoJUnitRunner.class) -public class RulesImplTest extends TestCase -{ - private static final String FOLDER_NODE_ID = "dummy-folder-node-id"; - private static final String RULE_SET_ID = "dummy-rule-set-id"; - private static final String RULE_ID = "dummy-rule-id"; - private static final NodeRef folderNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, FOLDER_NODE_ID); - private static final NodeRef ruleSetNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, RULE_SET_ID); - private static final NodeRef ruleNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, RULE_ID); - private static final Paging paging = Paging.DEFAULT; - private static final Action action = new ActionImpl(folderNodeRef, "actionId", "actionDefinitionName"); - private static final String RULE_NAME = "Rule name"; - - @Mock - private Nodes nodesMock; - - @Mock - private PermissionService permissionServiceMock; - - @Mock - private RuleService ruleServiceMock; - - @InjectMocks - private RulesImpl rules; - - @Before - @Override - public void setUp() throws Exception - { - MockitoAnnotations.openMocks(this); - - given(nodesMock.validateOrLookupNode(eq(FOLDER_NODE_ID), any())).willReturn(folderNodeRef); - given(nodesMock.validateNode(RULE_SET_ID)).willReturn(ruleSetNodeRef); - given(nodesMock.validateNode(RULE_ID)).willReturn(ruleNodeRef); - given(nodesMock.nodeMatches(any(), any(), any())).willReturn(true); - given(permissionServiceMock.hasReadPermission(any())).willReturn(ALLOWED); - given(permissionServiceMock.hasPermission(any(), any())).willReturn(ALLOWED); - } - - @Test - public void testGetRules() - { - given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(true); - given(ruleServiceMock.getRules(any())).willReturn(List.of(createRule(RULE_ID))); - - // when - final CollectionWithPagingInfo rulesPage = rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, paging); - - then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null); - then(nodesMock).should().validateNode(RULE_SET_ID); - then(nodesMock).should().nodeMatches(eq(folderNodeRef), any(), isNull()); - then(nodesMock).should().nodeMatches(eq(ruleSetNodeRef), any(), isNull()); - then(nodesMock).shouldHaveNoMoreInteractions(); - then(permissionServiceMock).should().hasReadPermission(folderNodeRef); - then(permissionServiceMock).shouldHaveNoMoreInteractions(); - then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef); - then(ruleServiceMock).should().isRuleSetShared(ruleSetNodeRef); - then(ruleServiceMock).should().getRules(folderNodeRef); - then(ruleServiceMock).shouldHaveNoMoreInteractions(); - assertThat(rulesPage) - .isNotNull() - .extracting(CollectionWithPagingInfo::getCollection) - .isNotNull() - .extracting(Collection::size) - .isEqualTo(1); - assertThat(rulesPage.getCollection().stream().findFirst().orElse(null)) - .isNotNull() - .extracting(Rule::getId) - .isEqualTo(RULE_ID); - } - - @Test - public void testGetRulesForDefaultRuleSet() - { - given(ruleServiceMock.getRuleSetNode(any())).willReturn(ruleSetNodeRef); - given(ruleServiceMock.getRules(any())).willReturn(List.of(createRule(RULE_ID))); - - // when - final CollectionWithPagingInfo rulesPage = rules.getRules(FOLDER_NODE_ID, DEFAULT_ID, paging); - - then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null); - then(nodesMock).should().nodeMatches(eq(folderNodeRef), any(), isNull()); - then(nodesMock).shouldHaveNoMoreInteractions(); - then(permissionServiceMock).should().hasReadPermission(folderNodeRef); - then(permissionServiceMock).shouldHaveNoMoreInteractions(); - then(ruleServiceMock).should().getRuleSetNode(folderNodeRef); - then(ruleServiceMock).should().isRuleSetShared(ruleSetNodeRef); - then(ruleServiceMock).should().getRules(folderNodeRef); - then(ruleServiceMock).shouldHaveNoMoreInteractions(); - assertThat(rulesPage) - .isNotNull() - .extracting(CollectionWithPagingInfo::getCollection) - .isNotNull() - .extracting(Collection::size) - .isEqualTo(1); - assertThat(rulesPage.getCollection().stream().findFirst().orElse(null)) - .isNotNull() - .extracting(Rule::getId) - .isEqualTo(RULE_ID); - } - - @Test - public void testGetRulesForNotExistingFolderNode() - { - given(nodesMock.nodeMatches(eq(folderNodeRef), any(), any())).willReturn(false); - - // when - assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy( - () -> rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, paging)); - - then(ruleServiceMock).shouldHaveNoInteractions(); - } - - @Test - public void testGetRulesForNotExistingRuleSetNode() - { - given(nodesMock.nodeMatches(eq(folderNodeRef), any(), any())).willReturn(true); - given(nodesMock.nodeMatches(eq(ruleSetNodeRef), any(), any())).willReturn(false); - - // when - assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy( - () -> rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, paging)); - - then(ruleServiceMock).shouldHaveNoInteractions(); - } - - @Test - public void testGetRulesForNotExistingDefaultRuleSetNode() - { - given(nodesMock.nodeMatches(eq(folderNodeRef), any(), any())).willReturn(true); - given(ruleServiceMock.getRuleSetNode(folderNodeRef)).willReturn(null); - - // when - assertThatExceptionOfType(RelationshipResourceNotFoundException.class).isThrownBy( - () -> rules.getRules(FOLDER_NODE_ID, DEFAULT_ID, paging)); - - then(ruleServiceMock).should().getRuleSetNode(folderNodeRef); - then(ruleServiceMock).shouldHaveNoMoreInteractions(); - } - - @Test - public void testGetRulesForNotAssociatedRuleSetToFolder() - { - given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(false); - - // when - assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy( - () -> rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, paging)); - - then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef); - then(ruleServiceMock).shouldHaveNoMoreInteractions(); - } - - @Test - public void testGetRulesWithoutReadPermission() - { - given(permissionServiceMock.hasReadPermission(any())).willReturn(DENIED); - - // when - assertThatExceptionOfType(PermissionDeniedException.class).isThrownBy( - () -> rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, paging)); - - then(ruleServiceMock).shouldHaveNoInteractions(); - } - - @Test - public void testGetRuleById() - { - given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(true); - given(ruleServiceMock.isRuleAssociatedWithRuleSet(any(), any())).willReturn(true); - given(ruleServiceMock.getRule(any())).willReturn(createRule(RULE_ID)); - - // when - final Rule rule = rules.getRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID); - - then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null); - then(nodesMock).should().validateNode(RULE_SET_ID); - then(nodesMock).should().validateNode(RULE_ID); - then(nodesMock).should().nodeMatches(eq(folderNodeRef), any(), isNull()); - then(nodesMock).should().nodeMatches(eq(ruleSetNodeRef), any(), isNull()); - then(nodesMock).should().nodeMatches(eq(ruleNodeRef), any(), isNull()); - then(nodesMock).shouldHaveNoMoreInteractions(); - then(permissionServiceMock).should().hasReadPermission(folderNodeRef); - then(permissionServiceMock).shouldHaveNoMoreInteractions(); - then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef); - then(ruleServiceMock).should().isRuleAssociatedWithRuleSet(ruleNodeRef, ruleSetNodeRef); - then(ruleServiceMock).should().isRuleSetShared(ruleSetNodeRef); - then(ruleServiceMock).should().getRule(ruleNodeRef); - then(ruleServiceMock).shouldHaveNoMoreInteractions(); - assertThat(rule) - .isNotNull() - .extracting(Rule::getId) - .isEqualTo(RULE_ID); - } - - @Test - public void testGetRuleByIdForDefaultRuleSet() - { - final String defaultRuleSetId = "-default-"; - given(ruleServiceMock.getRuleSetNode(any())).willReturn(ruleSetNodeRef); - given(ruleServiceMock.isRuleAssociatedWithRuleSet(any(), any())).willReturn(true); - given(ruleServiceMock.getRule(any())).willReturn(createRule(RULE_ID)); - - // when - final Rule rule = rules.getRuleById(FOLDER_NODE_ID, defaultRuleSetId, RULE_ID); - - then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null); - then(nodesMock).should().validateNode(RULE_ID); - then(nodesMock).should().nodeMatches(eq(folderNodeRef), any(), isNull()); - then(nodesMock).should().nodeMatches(eq(ruleNodeRef), any(), isNull()); - then(nodesMock).shouldHaveNoMoreInteractions(); - then(permissionServiceMock).should().hasReadPermission(folderNodeRef); - then(permissionServiceMock).shouldHaveNoMoreInteractions(); - then(ruleServiceMock).should().getRuleSetNode(folderNodeRef); - then(ruleServiceMock).should().isRuleAssociatedWithRuleSet(ruleNodeRef, ruleSetNodeRef); - then(ruleServiceMock).should().isRuleSetShared(ruleSetNodeRef); - then(ruleServiceMock).should().getRule(ruleNodeRef); - then(ruleServiceMock).shouldHaveNoMoreInteractions(); - assertThat(rule) - .isNotNull() - .extracting(Rule::getId) - .isEqualTo(RULE_ID); - } - - @Test - public void testGetRuleByIdForNotAssociatedRuleToRuleSet() - { - given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(true); - given(ruleServiceMock.isRuleAssociatedWithRuleSet(any(), any())).willReturn(false); - - // when - assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy( - () -> rules.getRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID)); - - then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef); - then(ruleServiceMock).should().isRuleAssociatedWithRuleSet(ruleNodeRef, ruleSetNodeRef); - then(ruleServiceMock).shouldHaveNoMoreInteractions(); - } - - /** Create a single rule. */ - @Test - public void testSaveRules() - { - Rule ruleBody = mock(Rule.class); - List ruleList = List.of(ruleBody); - given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(true); - org.alfresco.service.cmr.rule.Rule serviceRuleBody = mock(org.alfresco.service.cmr.rule.Rule.class); - given(ruleBody.toServiceModel(nodesMock)).willReturn(serviceRuleBody); - org.alfresco.service.cmr.rule.Rule serviceRule = mock(org.alfresco.service.cmr.rule.Rule.class); - given(ruleServiceMock.saveRule(folderNodeRef, serviceRuleBody)).willReturn(serviceRule); - given(serviceRule.getNodeRef()).willReturn(ruleNodeRef); - given(serviceRule.getAction()).willReturn(action); - - // when - List actual = rules.createRules(folderNodeRef.getId(), ruleSetNodeRef.getId(), ruleList); - - then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef); - then(ruleServiceMock).should().isRuleSetShared(ruleSetNodeRef); - then(ruleServiceMock).should().saveRule(folderNodeRef, ruleBody.toServiceModel(nodesMock)); - then(ruleServiceMock).shouldHaveNoMoreInteractions(); - List expected = List.of(Rule.from(serviceRule, false)); - assertThat(actual).isEqualTo(expected); - } - - /** Check that when passing the default rule set then we don't perform any validation around the rule set node. */ - @Test - public void testSaveRules_defaultRuleSet() - { - Rule ruleBody = mock(Rule.class); - List ruleList = List.of(ruleBody); - org.alfresco.service.cmr.rule.Rule serviceRuleBody = mock(org.alfresco.service.cmr.rule.Rule.class); - given(ruleBody.toServiceModel(nodesMock)).willReturn(serviceRuleBody); - given(ruleServiceMock.getRuleSetNode(any())).willReturn(ruleSetNodeRef); - org.alfresco.service.cmr.rule.Rule serviceRule = mock(org.alfresco.service.cmr.rule.Rule.class); - given(ruleServiceMock.saveRule(folderNodeRef, serviceRuleBody)).willReturn(serviceRule); - given(serviceRule.getNodeRef()).willReturn(ruleNodeRef); - given(serviceRule.getAction()).willReturn(action); - - // when - List actual = rules.createRules(folderNodeRef.getId(), DEFAULT_ID, ruleList); - - then(ruleServiceMock).should().getRuleSetNode(folderNodeRef); - then(ruleServiceMock).should().isRuleSetShared(ruleSetNodeRef); - then(ruleServiceMock).should().saveRule(folderNodeRef, ruleBody.toServiceModel(nodesMock)); - then(ruleServiceMock).shouldHaveNoMoreInteractions(); - List expected = List.of(Rule.from(serviceRule, false)); - assertThat(actual).isEqualTo(expected); - } - - @Test - public void testSaveRules_ruleSetNotAssociatedWithFolder() - { - Rule rule = Rule.builder().name(RULE_NAME).create(); - List ruleList = List.of(rule); - given(ruleServiceMock.isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef)).willReturn(false); - - // when - assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy( - () -> rules.createRules(folderNodeRef.getId(), ruleSetNodeRef.getId(), ruleList)); - - then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef); - then(ruleServiceMock).shouldHaveNoMoreInteractions(); - } - - @Test - public void testSaveRules_emptyRuleList() - { - given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(true); - List ruleList = emptyList(); - - // when - List actual = this.rules.createRules(folderNodeRef.getId(), ruleSetNodeRef.getId(), ruleList); - - then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef); - then(ruleServiceMock).shouldHaveNoMoreInteractions(); - assertThat(actual).isEqualTo(emptyList()); - } - - /** Create three rules in a single call and check they are all passed to the RuleService. */ - @Test - public void testSaveRules_createMultipleRules() - { - given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(true); - List ruleBodyList = new ArrayList<>(); - List expected = new ArrayList<>(); - for (String ruleId : List.of("A", "B", "C")) - { - Rule ruleBody = mock(Rule.class); - ruleBodyList.add(ruleBody); - org.alfresco.service.cmr.rule.Rule serviceRuleBody = mock(org.alfresco.service.cmr.rule.Rule.class); - given(ruleBody.toServiceModel(nodesMock)).willReturn(serviceRuleBody); - org.alfresco.service.cmr.rule.Rule serviceRule = mock(org.alfresco.service.cmr.rule.Rule.class); - given(ruleServiceMock.saveRule(folderNodeRef, serviceRuleBody)).willReturn(serviceRule); - NodeRef ruleNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, ruleId); - given(serviceRule.getNodeRef()).willReturn(ruleNodeRef); - given(serviceRule.getAction()).willReturn(action); - expected.add(Rule.from(serviceRule, false)); - } - - // when - List actual = rules.createRules(folderNodeRef.getId(), ruleSetNodeRef.getId(), ruleBodyList); - - then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef); - for (Rule ruleBody : ruleBodyList) - { - then(ruleServiceMock).should().saveRule(folderNodeRef, ruleBody.toServiceModel(nodesMock)); - } - then(ruleServiceMock).should(times(ruleBodyList.size())).isRuleSetShared(ruleSetNodeRef); - then(ruleServiceMock).shouldHaveNoMoreInteractions(); - assertThat(actual).isEqualTo(expected); - } - - /** Try to create a rule without CHANGE permission and check an exception is thrown. */ - @Test - public void testSaveRules_noChangePermission() - { - given(permissionServiceMock.hasPermission(folderNodeRef, CHANGE_PERMISSIONS)).willReturn(DENIED); - - Rule ruleBody = mock(Rule.class); - List ruleList = List.of(ruleBody); - - // when - assertThatExceptionOfType(PermissionDeniedException.class).isThrownBy(() -> - rules.createRules(folderNodeRef.getId(), ruleSetNodeRef.getId(), ruleList)); - - then(ruleServiceMock).shouldHaveNoMoreInteractions(); - } - - /** Check that we can update a rule. */ - @Test - public void testUpdateRules() - { - Rule ruleBody = mock(Rule.class); - given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(true); - given(ruleServiceMock.isRuleAssociatedWithRuleSet(ruleNodeRef, ruleSetNodeRef)).willReturn(true); - given(ruleServiceMock.isRuleSetShared(ruleSetNodeRef)).willReturn(true); - org.alfresco.service.cmr.rule.Rule serviceRuleBody = mock(org.alfresco.service.cmr.rule.Rule.class); - given(ruleBody.toServiceModel(nodesMock)).willReturn(serviceRuleBody); - org.alfresco.service.cmr.rule.Rule serviceRule = mock(org.alfresco.service.cmr.rule.Rule.class); - given(ruleServiceMock.saveRule(folderNodeRef, serviceRuleBody)).willReturn(serviceRule); - given(serviceRule.getNodeRef()).willReturn(ruleNodeRef); - given(serviceRule.getAction()).willReturn(action); - - // when - Rule updatedRule = rules.updateRuleById(folderNodeRef.getId(), ruleSetNodeRef.getId(), RULE_ID, ruleBody); - - then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef); - then(ruleServiceMock).should().isRuleAssociatedWithRuleSet(ruleNodeRef, ruleSetNodeRef); - then(ruleServiceMock).should().isRuleSetShared(ruleSetNodeRef); - then(ruleServiceMock).should().saveRule(folderNodeRef, serviceRuleBody); - then(ruleServiceMock).shouldHaveNoMoreInteractions(); - - - Rule expected = Rule.builder().id(RULE_ID) - .enabled(true) - .shared(true) - .triggers(emptyList()) - .conditions(CompositeCondition.builder().inverted(false).create()) - .create(); - assertThat(updatedRule).isEqualTo(expected); - } - - /** Check that we get an error if the rule set is not a child of the folder. */ - @Test - public void testUpdateRules_ruleSetNotInFolder() - { - Rule ruleBody = mock(Rule.class); - given(ruleServiceMock.isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef)).willReturn(false); - - // when - assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(() -> - rules.updateRuleById(folderNodeRef.getId(), ruleSetNodeRef.getId(), RULE_ID, ruleBody)); - - then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef); - then(ruleServiceMock).shouldHaveNoMoreInteractions(); - } - - /** Check that we get an error if the rule is not a child of the rule set. */ - @Test - public void testUpdateRules_ruleNotInRuleSet() - { - Rule ruleBody = mock(Rule.class); - given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(true); - given(ruleServiceMock.isRuleAssociatedWithRuleSet(ruleNodeRef, ruleSetNodeRef)).willReturn(false); - - // when - assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(() -> - rules.updateRuleById(folderNodeRef.getId(), ruleSetNodeRef.getId(), RULE_ID, ruleBody)); - - then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef); - then(ruleServiceMock).should().isRuleAssociatedWithRuleSet(ruleNodeRef, ruleSetNodeRef); - then(ruleServiceMock).shouldHaveNoMoreInteractions(); - } - - /** Try to update a rule without CHANGE permission and check an exception is thrown. */ - @Test - public void testUpdateRules_noChangePermission() - { - given(permissionServiceMock.hasPermission(folderNodeRef, CHANGE_PERMISSIONS)).willReturn(DENIED); - - Rule ruleBody = mock(Rule.class); - - // when - assertThatExceptionOfType(PermissionDeniedException.class).isThrownBy(() -> - rules.updateRuleById(folderNodeRef.getId(), ruleSetNodeRef.getId(), RULE_ID, ruleBody)); - - then(ruleServiceMock).shouldHaveNoMoreInteractions(); - } - - @Test - public void testDeleteRuleById() { - given(ruleServiceMock.isRuleAssociatedWithRuleSet(any(), any())).willReturn(true); - given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(true); - org.alfresco.service.cmr.rule.Rule rule = createRule(RULE_ID); - given(ruleServiceMock.getRule(any())).willReturn(rule); - - //when - rules.deleteRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID); - - then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null); - then(nodesMock).should().validateNode(RULE_SET_ID); - then(nodesMock).should().validateNode(RULE_ID); - then(nodesMock).should().nodeMatches(eq(folderNodeRef), any(), isNull()); - then(nodesMock).should().nodeMatches(eq(ruleSetNodeRef), any(), isNull()); - then(nodesMock).should().nodeMatches(eq(ruleNodeRef), any(), isNull()); - then(nodesMock).shouldHaveNoMoreInteractions(); - then(permissionServiceMock).should().hasPermission(folderNodeRef, CHANGE_PERMISSIONS); - then(permissionServiceMock).shouldHaveNoMoreInteractions(); - then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef); - then(ruleServiceMock).should().isRuleAssociatedWithRuleSet(ruleNodeRef, ruleSetNodeRef); - then(ruleServiceMock).should().getRule(ruleNodeRef); - then(ruleServiceMock).should().removeRule(folderNodeRef, rule); - then(ruleServiceMock).shouldHaveNoMoreInteractions(); - } - - @Test - public void testDeleteRuleById_NonExistingRuleId() { - given(nodesMock.validateNode(RULE_ID)).willThrow(new EntityNotFoundException(RULE_ID)); - given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(true); - - //when - assertThatExceptionOfType(EntityNotFoundException.class).isThrownBy( - () -> rules.deleteRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID)); - - then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null); - then(nodesMock).should().validateNode(RULE_SET_ID); - then(nodesMock).should().validateNode(RULE_ID); - then(nodesMock).should().nodeMatches(eq(folderNodeRef), any(), isNull()); - then(nodesMock).should().nodeMatches(eq(ruleSetNodeRef), any(), isNull()); - then(nodesMock).shouldHaveNoMoreInteractions(); - then(permissionServiceMock).should().hasPermission(folderNodeRef, CHANGE_PERMISSIONS); - then(permissionServiceMock).shouldHaveNoMoreInteractions(); - then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef); - then(ruleServiceMock).shouldHaveNoMoreInteractions(); - } - - @Test - public void testDeleteRuleById_RuleIdNotInRuleSet() { - given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(true); - given(ruleServiceMock.isRuleAssociatedWithRuleSet(any(), any())).willReturn(false); - - //when - assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy( - () -> rules.deleteRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID)); - - then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null); - then(nodesMock).should().validateNode(RULE_SET_ID); - then(nodesMock).should().validateNode(RULE_ID); - then(nodesMock).should().nodeMatches(eq(folderNodeRef), any(), isNull()); - then(nodesMock).should().nodeMatches(eq(ruleSetNodeRef), any(), isNull()); - then(nodesMock).should().nodeMatches(eq(ruleNodeRef), any(), isNull()); - then(nodesMock).shouldHaveNoMoreInteractions(); - then(permissionServiceMock).should().hasPermission(folderNodeRef, CHANGE_PERMISSIONS); - then(permissionServiceMock).shouldHaveNoMoreInteractions(); - then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef); - then(ruleServiceMock).should().isRuleAssociatedWithRuleSet(ruleNodeRef, ruleSetNodeRef); - then(ruleServiceMock).shouldHaveNoMoreInteractions(); - } - - @Test - public void testDeleteRuleById_NonExistingRuleSetId() { - given(nodesMock.validateNode(RULE_SET_ID)).willThrow(new EntityNotFoundException(RULE_SET_ID)); - - //when - assertThatExceptionOfType(EntityNotFoundException.class).isThrownBy( - () -> rules.deleteRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID)); - - then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null); - then(nodesMock).should().validateNode(RULE_SET_ID); - then(nodesMock).should().nodeMatches(eq(folderNodeRef), any(), isNull()); - then(nodesMock).shouldHaveNoMoreInteractions(); - then(permissionServiceMock).should().hasPermission(folderNodeRef, CHANGE_PERMISSIONS); - then(permissionServiceMock).shouldHaveNoMoreInteractions(); - then(ruleServiceMock).shouldHaveNoMoreInteractions(); - } - - @Test - public void testDeleteRuleById_RuleSetNotInFolder() { - given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(false); - - //when - assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy( - () -> rules.deleteRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID)); - - then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null); - then(nodesMock).should().validateNode(RULE_SET_ID); - then(nodesMock).should().nodeMatches(eq(folderNodeRef), any(), isNull()); - then(nodesMock).should().nodeMatches(eq(ruleSetNodeRef), any(), isNull()); - then(nodesMock).shouldHaveNoMoreInteractions(); - then(permissionServiceMock).should().hasPermission(folderNodeRef, CHANGE_PERMISSIONS); - then(permissionServiceMock).shouldHaveNoMoreInteractions(); - then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef); - then(ruleServiceMock).shouldHaveNoMoreInteractions(); - } - - @Test - public void testDeleteRuleById_NonExistingFolderId() { - given(nodesMock.validateOrLookupNode(FOLDER_NODE_ID, null)).willThrow(new EntityNotFoundException(RULE_ID)); - - //when - assertThatExceptionOfType(EntityNotFoundException.class).isThrownBy( - () -> rules.deleteRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID)); - - then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null); - then(nodesMock).shouldHaveNoMoreInteractions(); - then(permissionServiceMock).shouldHaveNoMoreInteractions(); - then(ruleServiceMock).shouldHaveNoMoreInteractions(); - } - - /** Try to delete a rule without CHANGE permission and check an exception is thrown. */ - @Test - public void testDeleteRuleById_noChangePermission() - { - given(permissionServiceMock.hasPermission(folderNodeRef, CHANGE_PERMISSIONS)).willReturn(DENIED); - - // when - assertThatExceptionOfType(PermissionDeniedException.class).isThrownBy(() -> - rules.deleteRuleById(folderNodeRef.getId(), ruleSetNodeRef.getId(), RULE_ID)); - - then(ruleServiceMock).shouldHaveNoMoreInteractions(); - } - - - private static org.alfresco.service.cmr.rule.Rule createRule(final String id) { - final NodeRef nodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, id); - final org.alfresco.service.cmr.rule.Rule rule = new org.alfresco.service.cmr.rule.Rule(); - rule.setNodeRef(nodeRef); - rule.setRuleType("ruleType"); - rule.setAction(action); - - return rule; - } -} diff --git a/remote-api/src/test/java/org/alfresco/rest/api/impl/rules/NodeValidatorTest.java b/remote-api/src/test/java/org/alfresco/rest/api/impl/rules/NodeValidatorTest.java new file mode 100644 index 0000000000..770c9840f6 --- /dev/null +++ b/remote-api/src/test/java/org/alfresco/rest/api/impl/rules/NodeValidatorTest.java @@ -0,0 +1,379 @@ +/* + * #%L + * Alfresco Remote API + * %% + * Copyright (C) 2005 - 2022 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ + +package org.alfresco.rest.api.impl.rules; + +import static org.alfresco.model.ContentModel.TYPE_FOLDER; +import static org.alfresco.model.ContentModel.TYPE_SYSTEM_FOLDER; +import static org.alfresco.repo.rule.RuleModel.TYPE_RULE; +import static org.alfresco.rest.api.model.rules.RuleSet.DEFAULT_ID; +import static org.alfresco.service.cmr.security.AccessStatus.ALLOWED; +import static org.alfresco.service.cmr.security.AccessStatus.DENIED; +import static org.alfresco.service.cmr.security.PermissionService.CHANGE_PERMISSIONS; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.then; + +import java.util.Set; + +import org.alfresco.rest.api.Nodes; +import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException; +import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException; +import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException; +import org.alfresco.rest.framework.core.exceptions.RelationshipResourceNotFoundException; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.cmr.rule.RuleService; +import org.alfresco.service.cmr.security.PermissionService; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +public class NodeValidatorTest +{ + + private static final String FOLDER_NODE_ID = "dummy-folder-node-id"; + private static final String RULE_SET_ID = "dummy-rule-set-id"; + private static final String RULE_ID = "dummy-rule-id"; + private static final NodeRef folderNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, FOLDER_NODE_ID); + private static final NodeRef ruleSetNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, RULE_SET_ID); + private static final NodeRef ruleNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, RULE_ID); + + @Mock + private Nodes nodesMock; + + @Mock + private PermissionService permissionServiceMock; + + @Mock + private RuleService ruleServiceMock; + + @InjectMocks + private NodeValidator nodeValidator; + + @Before + public void setUp() throws Exception + { + MockitoAnnotations.openMocks(this); + given(nodesMock.validateOrLookupNode(eq(FOLDER_NODE_ID), any())).willReturn(folderNodeRef); + given(nodesMock.validateNode(RULE_SET_ID)).willReturn(ruleSetNodeRef); + given(nodesMock.validateNode(RULE_ID)).willReturn(ruleNodeRef); + given(nodesMock.nodeMatches(any(), any(), any())).willReturn(true); + given(permissionServiceMock.hasReadPermission(any())).willReturn(ALLOWED); + given(permissionServiceMock.hasPermission(any(), any())).willReturn(ALLOWED); + } + + @Test + public void testValidateFolderNode() + { + // when + final NodeRef nodeRef = nodeValidator.validateFolderNode(FOLDER_NODE_ID, false); + + then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null); + then(nodesMock).should().nodeMatches(folderNodeRef, Set.of(TYPE_FOLDER), null); + then(nodesMock).shouldHaveNoMoreInteractions(); + then(permissionServiceMock).should().hasReadPermission(folderNodeRef); + then(permissionServiceMock).shouldHaveNoMoreInteractions(); + then(ruleServiceMock).shouldHaveNoInteractions(); + + assertThat(nodeRef).isNotNull().isEqualTo(folderNodeRef); + } + + @Test + public void testValidateFolderNode_notExistingFolder() + { + given(nodesMock.validateOrLookupNode(any(), any())).willThrow(new EntityNotFoundException(FOLDER_NODE_ID)); + + //when + assertThatExceptionOfType(EntityNotFoundException.class).isThrownBy( + () -> nodeValidator.validateFolderNode(FOLDER_NODE_ID, false)); + + then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null); + then(nodesMock).shouldHaveNoMoreInteractions(); + then(ruleServiceMock).shouldHaveNoInteractions(); + } + + @Test + public void testValidateFolderNode_notMatchingTypeFolder() + { + given(nodesMock.nodeMatches(any(), eq(Set.of(TYPE_FOLDER)), any())).willReturn(false); + + // when + assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy( + () -> nodeValidator.validateFolderNode(FOLDER_NODE_ID, false)); + + then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null); + then(nodesMock).should().nodeMatches(folderNodeRef, Set.of(TYPE_FOLDER), null); + then(nodesMock).shouldHaveNoMoreInteractions(); + then(ruleServiceMock).shouldHaveNoInteractions(); + } + + @Test + public void testValidateFolderNode_noReadPermission() + { + given(permissionServiceMock.hasReadPermission(any())).willReturn(DENIED); + + // when + assertThatExceptionOfType(PermissionDeniedException.class).isThrownBy( + () -> nodeValidator.validateFolderNode(FOLDER_NODE_ID, false)); + + then(permissionServiceMock).should().hasReadPermission(folderNodeRef); + then(permissionServiceMock).shouldHaveNoMoreInteractions(); + then(ruleServiceMock).shouldHaveNoInteractions(); + } + + @Test + public void testValidateFolderNode_noChangePermission() + { + given(permissionServiceMock.hasPermission(any(), any())).willReturn(DENIED); + + // when + assertThatExceptionOfType(PermissionDeniedException.class).isThrownBy(() -> + nodeValidator.validateFolderNode(folderNodeRef.getId(), true)); + + then(permissionServiceMock).should().hasPermission(folderNodeRef, CHANGE_PERMISSIONS); + then(permissionServiceMock).shouldHaveNoMoreInteractions(); + then(ruleServiceMock).shouldHaveNoMoreInteractions(); + } + + @Test + public void validateRuleSetNode() + { + given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(true); + + // when + final NodeRef nodeRef = nodeValidator.validateRuleSetNode(RULE_SET_ID, folderNodeRef); + + then(nodesMock).should().validateNode(RULE_SET_ID); + then(nodesMock).should().nodeMatches(ruleSetNodeRef, Set.of(TYPE_SYSTEM_FOLDER), null); + then(nodesMock).shouldHaveNoMoreInteractions(); + then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef); + then(ruleServiceMock).shouldHaveNoMoreInteractions(); + then(permissionServiceMock).shouldHaveNoInteractions(); + + assertThat(nodeRef).isNotNull().isEqualTo(ruleSetNodeRef); + } + + @Test + public void validateRuleSetNode_defaultId() + { + given(ruleServiceMock.getRuleSetNode(any())).willReturn(ruleSetNodeRef); + + // when + final NodeRef nodeRef = nodeValidator.validateRuleSetNode(DEFAULT_ID, folderNodeRef); + + then(ruleServiceMock).should().getRuleSetNode(folderNodeRef); + then(ruleServiceMock).shouldHaveNoMoreInteractions(); + then(nodesMock).shouldHaveNoInteractions(); + then(permissionServiceMock).shouldHaveNoInteractions(); + + assertThat(nodeRef).isNotNull().isEqualTo(ruleSetNodeRef); + } + + @Test + public void testValidateRuleSetNode_notExistingRuleSet() + { + given(nodesMock.validateNode(RULE_SET_ID)).willThrow(new EntityNotFoundException(RULE_SET_ID)); + + //when + assertThatExceptionOfType(EntityNotFoundException.class).isThrownBy( + () -> nodeValidator.validateRuleSetNode(RULE_SET_ID, folderNodeRef)); + + then(nodesMock).should().validateNode(RULE_SET_ID); + then(nodesMock).shouldHaveNoMoreInteractions(); + then(ruleServiceMock).shouldHaveNoInteractions(); + } + + @Test + public void testValidateRuleSetNode_notMatchingTypeSystemFolder() + { + given(nodesMock.nodeMatches(any(), eq(Set.of(TYPE_SYSTEM_FOLDER)), any())).willReturn(false); + + // when + assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy( + () -> nodeValidator.validateRuleSetNode(RULE_SET_ID, folderNodeRef)); + + then(nodesMock).should().validateNode(RULE_SET_ID); + then(nodesMock).should().nodeMatches(ruleSetNodeRef, Set.of(TYPE_SYSTEM_FOLDER), null); + then(nodesMock).shouldHaveNoMoreInteractions(); + then(ruleServiceMock).shouldHaveNoInteractions(); + } + + @Test + public void testValidateRuleSetNode_notExistingDefaultRuleSet() + { + given(ruleServiceMock.getRuleSetNode(folderNodeRef)).willReturn(null); + + // when + assertThatExceptionOfType(RelationshipResourceNotFoundException.class).isThrownBy( + () -> nodeValidator.validateRuleSetNode(DEFAULT_ID, folderNodeRef)); + + then(ruleServiceMock).should().getRuleSetNode(folderNodeRef); + then(ruleServiceMock).shouldHaveNoMoreInteractions(); + then(nodesMock).shouldHaveNoInteractions(); + } + + @Test + public void testValidateRuleSetNode_notAssociatedRuleSetToFolder() + { + given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(false); + + // when + assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy( + () -> nodeValidator.validateRuleSetNode(RULE_SET_ID, folderNodeRef)); + + then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef); + then(ruleServiceMock).shouldHaveNoMoreInteractions(); + } + + @Test + public void validateRuleNode() + { + given(ruleServiceMock.isRuleAssociatedWithRuleSet(any(), any())).willReturn(true); + + // when + final NodeRef nodeRef = nodeValidator.validateRuleNode(RULE_ID, ruleSetNodeRef); + + then(nodesMock).should().validateNode(RULE_ID); + then(nodesMock).should().nodeMatches(ruleNodeRef, Set.of(TYPE_RULE), null); + then(nodesMock).shouldHaveNoMoreInteractions(); + then(ruleServiceMock).should().isRuleAssociatedWithRuleSet(ruleNodeRef, ruleSetNodeRef); + then(ruleServiceMock).shouldHaveNoMoreInteractions(); + then(permissionServiceMock).shouldHaveNoInteractions(); + + assertThat(nodeRef).isNotNull().isEqualTo(ruleNodeRef); + } + + @Test + public void validateRuleNode_nullRuleSet() + { + // when + final NodeRef nodeRef = nodeValidator.validateRuleNode(RULE_ID, null); + + then(nodesMock).should().validateNode(RULE_ID); + then(nodesMock).should().nodeMatches(ruleNodeRef, Set.of(TYPE_RULE), null); + then(nodesMock).shouldHaveNoMoreInteractions(); + then(ruleServiceMock).shouldHaveNoInteractions(); + then(permissionServiceMock).shouldHaveNoInteractions(); + + assertThat(nodeRef).isNotNull().isEqualTo(ruleNodeRef); + } + + @Test + public void testValidateRuleNode_notExistingRule() + { + given(nodesMock.validateNode(RULE_ID)).willThrow(new EntityNotFoundException(RULE_ID)); + + //when + assertThatExceptionOfType(EntityNotFoundException.class).isThrownBy( + () -> nodeValidator.validateRuleNode(RULE_ID, ruleSetNodeRef)); + + then(nodesMock).should().validateNode(RULE_ID); + then(nodesMock).shouldHaveNoMoreInteractions(); + then(ruleServiceMock).shouldHaveNoInteractions(); + } + + @Test + public void testValidateRuleNode_notMatchingTypeRule() + { + given(nodesMock.nodeMatches(any(), eq(Set.of(TYPE_RULE)), any())).willReturn(false); + + // when + assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy( + () -> nodeValidator.validateRuleNode(RULE_ID, ruleSetNodeRef)); + + then(nodesMock).should().validateNode(RULE_ID); + then(nodesMock).should().nodeMatches(ruleNodeRef, Set.of(TYPE_RULE), null); + then(nodesMock).shouldHaveNoMoreInteractions(); + then(ruleServiceMock).shouldHaveNoInteractions(); + } + + @Test + public void testValidateRuleNode_notAssociatedRuleToRuleSet() + { + given(ruleServiceMock.isRuleAssociatedWithRuleSet(any(), any())).willReturn(false); + + // when + assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy( + () -> nodeValidator.validateRuleNode(RULE_ID, ruleSetNodeRef)); + + then(ruleServiceMock).should().isRuleAssociatedWithRuleSet(ruleNodeRef, ruleSetNodeRef); + then(ruleServiceMock).shouldHaveNoMoreInteractions(); + } + + @Test + public void testIsRuleSetNotNullAndShared() + { + given(ruleServiceMock.isRuleSetShared(any())).willReturn(true); + + // when + final boolean shared = nodeValidator.isRuleSetNotNullAndShared(ruleSetNodeRef); + + then(ruleServiceMock).should().isRuleSetShared(ruleSetNodeRef); + then(ruleServiceMock).shouldHaveNoMoreInteractions(); + + assertThat(shared).isTrue(); + } + + @Test + public void testIsRuleSetNotNullAndShared_nullRuleSetNode() + { + // when + final boolean shared = nodeValidator.isRuleSetNotNullAndShared(null); + + then(ruleServiceMock).shouldHaveNoInteractions(); + + assertThat(shared).isFalse(); + } + + @Test + public void testIsRuleSetNotNullAndShared_withoutRuleSetAndWithFolder() + { + given(ruleServiceMock.getRuleSetNode(any())).willReturn(ruleSetNodeRef); + + // when + nodeValidator.isRuleSetNotNullAndShared(null, folderNodeRef); + + then(ruleServiceMock).should().getRuleSetNode(folderNodeRef); + then(ruleServiceMock).should().isRuleSetShared(ruleSetNodeRef); + then(ruleServiceMock).shouldHaveNoMoreInteractions(); + } + + @Test + public void testIsRuleSetNotNullAndShared_withRuleSetAndWithFolder() + { + // when + nodeValidator.isRuleSetNotNullAndShared(ruleSetNodeRef, folderNodeRef); + + then(ruleServiceMock).should().isRuleSetShared(ruleSetNodeRef); + then(ruleServiceMock).shouldHaveNoMoreInteractions(); + } +} \ No newline at end of file diff --git a/remote-api/src/test/java/org/alfresco/rest/api/impl/rules/RuleSetsImplTest.java b/remote-api/src/test/java/org/alfresco/rest/api/impl/rules/RuleSetsImplTest.java new file mode 100644 index 0000000000..d504af258a --- /dev/null +++ b/remote-api/src/test/java/org/alfresco/rest/api/impl/rules/RuleSetsImplTest.java @@ -0,0 +1,133 @@ +/* + * #%L + * Alfresco Remote API + * %% + * Copyright (C) 2005 - 2022 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ +package org.alfresco.rest.api.impl.rules; + +import static java.util.Collections.emptyList; + +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.then; + +import java.util.Collection; +import java.util.List; + +import junit.framework.TestCase; +import org.alfresco.rest.api.model.rules.RuleSet; +import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo; +import org.alfresco.rest.framework.resource.parameters.Paging; +import org.alfresco.service.Experimental; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.cmr.rule.RuleService; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.junit.MockitoJUnitRunner; + +/** Unit tests for {@link RuleSetsImpl}. */ +@Experimental +@RunWith (MockitoJUnitRunner.class) +public class RuleSetsImplTest extends TestCase +{ + private static final String FOLDER_ID = "dummy-folder-id"; + private static final String RULE_SET_ID = "dummy-rule-set-id"; + private static final NodeRef FOLDER_NODE = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, FOLDER_ID); + private static final NodeRef RULE_SET_NODE = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, RULE_SET_ID); + private static final Paging PAGING = Paging.DEFAULT; + + @InjectMocks + private RuleSetsImpl ruleSets; + @Mock + private NodeValidator nodeValidatorMock; + @Mock + private RuleService ruleServiceMock; + + @Before + @Override + public void setUp() + { + MockitoAnnotations.openMocks(this); + + given(nodeValidatorMock.validateFolderNode(eq(FOLDER_ID), anyBoolean())).willReturn(FOLDER_NODE); + //given(nodeValidatorMock.validateFolderNode(eq(RULE_SET_ID), anyBoolean())).willReturn(RULE_SET_NODE); + given(nodeValidatorMock.validateRuleSetNode(RULE_SET_ID, FOLDER_NODE)).willReturn(RULE_SET_NODE); + + given(ruleServiceMock.getRuleSetNode(FOLDER_NODE)).willReturn(RULE_SET_NODE); + } + + @Test + public void testGetRuleSets() + { + // Call the method under test. + CollectionWithPagingInfo actual = ruleSets.getRuleSets(FOLDER_ID, null, PAGING); + + then(nodeValidatorMock).should().validateFolderNode(FOLDER_ID, false); + then(nodeValidatorMock).shouldHaveNoMoreInteractions(); + + then(ruleServiceMock).should().getRuleSetNode(FOLDER_NODE); + then(ruleServiceMock).shouldHaveNoMoreInteractions(); + + Collection expected = List.of(RuleSet.of(RULE_SET_ID)); + assertEquals(expected, actual.getCollection()); + assertEquals(PAGING, actual.getPaging()); + } + + @Test + public void testGetZeroRuleSets() + { + // Simulate no rule sets for the folder. + given(ruleServiceMock.getRuleSetNode(FOLDER_NODE)).willReturn(null); + + // Call the method under test. + CollectionWithPagingInfo actual = ruleSets.getRuleSets(FOLDER_ID, null, PAGING); + + then(nodeValidatorMock).should().validateFolderNode(FOLDER_ID, false); + then(nodeValidatorMock).shouldHaveNoMoreInteractions(); + + then(ruleServiceMock).should().getRuleSetNode(FOLDER_NODE); + then(ruleServiceMock).shouldHaveNoMoreInteractions(); + + assertEquals(emptyList(), actual.getCollection()); + assertEquals(PAGING, actual.getPaging()); + } + + @Test + public void testGetRuleSetById() + { + // Call the method under test. + RuleSet actual = ruleSets.getRuleSetById(FOLDER_ID, RULE_SET_ID, null); + + then(nodeValidatorMock).should().validateFolderNode(FOLDER_ID, false); + then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, FOLDER_NODE); + then(nodeValidatorMock).shouldHaveNoMoreInteractions(); + + assertEquals(RuleSet.of(RULE_SET_ID), actual); + } +} diff --git a/remote-api/src/test/java/org/alfresco/rest/api/impl/rules/RulesImplTest.java b/remote-api/src/test/java/org/alfresco/rest/api/impl/rules/RulesImplTest.java new file mode 100644 index 0000000000..6d228767df --- /dev/null +++ b/remote-api/src/test/java/org/alfresco/rest/api/impl/rules/RulesImplTest.java @@ -0,0 +1,614 @@ +/* + * #%L + * Alfresco Remote API + * %% + * Copyright (C) 2005 - 2022 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ + +package org.alfresco.rest.api.impl.rules; + +import static java.util.Collections.emptyList; + +import static org.alfresco.rest.api.model.rules.RuleSet.DEFAULT_ID; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.then; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import junit.framework.TestCase; +import org.alfresco.repo.action.ActionImpl; +import org.alfresco.rest.api.Nodes; +import org.alfresco.rest.api.model.rules.CompositeCondition; +import org.alfresco.rest.api.model.rules.Rule; +import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException; +import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException; +import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException; +import org.alfresco.rest.framework.core.exceptions.RelationshipResourceNotFoundException; +import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo; +import org.alfresco.rest.framework.resource.parameters.Paging; +import org.alfresco.service.Experimental; +import org.alfresco.service.cmr.action.Action; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.cmr.rule.RuleService; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.mockito.junit.MockitoJUnitRunner; + +@Experimental +@RunWith(MockitoJUnitRunner.class) +public class RulesImplTest extends TestCase +{ + private static final String FOLDER_NODE_ID = "dummy-folder-node-id"; + private static final String RULE_SET_ID = "dummy-rule-set-id"; + private static final String RULE_ID = "dummy-rule-id"; + private static final NodeRef folderNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, FOLDER_NODE_ID); + private static final NodeRef ruleSetNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, RULE_SET_ID); + private static final NodeRef ruleNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, RULE_ID); + private static final Paging paging = Paging.DEFAULT; + private static final Action action = new ActionImpl(folderNodeRef, "actionId", "actionDefinitionName"); + + @Mock + private Nodes nodesMock; + + @Mock + private NodeValidator nodeValidatorMock; + + @Mock + private RuleService ruleServiceMock; + + @InjectMocks + private RulesImpl rules; + + @Before + @Override + public void setUp() throws Exception + { + MockitoAnnotations.openMocks(this); + given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willReturn(folderNodeRef); + given(nodeValidatorMock.validateRuleSetNode(any(), any())).willReturn(ruleSetNodeRef); + given(nodeValidatorMock.validateRuleNode(any(), any())).willReturn(ruleNodeRef); + } + + @Test + public void testGetRules() + { + given(ruleServiceMock.getRules(any())).willReturn(List.of(createRule(RULE_ID))); + + // when + final CollectionWithPagingInfo rulesPage = rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, paging); + + then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, false); + then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, folderNodeRef); + then(nodeValidatorMock).should().isRuleSetNotNullAndShared(ruleSetNodeRef); + then(nodeValidatorMock).shouldHaveNoMoreInteractions(); + then(ruleServiceMock).should().getRules(folderNodeRef); + then(ruleServiceMock).shouldHaveNoMoreInteractions(); + assertThat(rulesPage) + .isNotNull() + .extracting(CollectionWithPagingInfo::getCollection) + .isNotNull() + .extracting(Collection::size) + .isEqualTo(1); + assertThat(rulesPage.getCollection().stream().findFirst().orElse(null)) + .isNotNull() + .extracting(Rule::getId) + .isEqualTo(RULE_ID); + } + + @Test + public void testGetRules_emptyResult() + { + given(ruleServiceMock.getRules(any())).willReturn(emptyList()); + + // when + final CollectionWithPagingInfo rulesPage = rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, paging); + + then(ruleServiceMock).should().getRules(folderNodeRef); + then(ruleServiceMock).shouldHaveNoMoreInteractions(); + assertThat(rulesPage) + .isNotNull() + .extracting(CollectionWithPagingInfo::getCollection) + .isNotNull() + .extracting(Collection::isEmpty) + .isEqualTo(true); + } + + @Test + public void testGetRules_invalidFolder() + { + for (Exception exception : folderValidationExceptions()) + { + Mockito.reset(nodeValidatorMock); + given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willThrow(exception); + + // when + assertThatExceptionOfType(exception.getClass()).isThrownBy( + () -> rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, paging)); + + then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, false); + then(nodeValidatorMock).shouldHaveNoMoreInteractions(); + then(ruleServiceMock).shouldHaveNoInteractions(); + } + } + + @Test + public void testGetRules_invalidRuleSet() + { + for (Exception exception : ruleSetValidationExceptions()) + { + Mockito.reset(nodeValidatorMock); + given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willReturn(folderNodeRef); + given(nodeValidatorMock.validateRuleSetNode(any(), any())).willThrow(exception); + + // when + assertThatExceptionOfType(exception.getClass()).isThrownBy( + () -> rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, paging)); + + then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, false); + then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, folderNodeRef); + then(nodeValidatorMock).shouldHaveNoMoreInteractions(); + then(ruleServiceMock).shouldHaveNoInteractions(); + } + } + + @Test + public void testGetRuleById() + { + given(ruleServiceMock.getRule(any())).willReturn(createRule(RULE_ID)); + + // when + final Rule rule = rules.getRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID); + + then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, false); + then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, folderNodeRef); + then(nodeValidatorMock).should().validateRuleNode(RULE_ID, ruleSetNodeRef); + then(nodeValidatorMock).should().isRuleSetNotNullAndShared(ruleSetNodeRef); + then(nodeValidatorMock).shouldHaveNoMoreInteractions(); + then(nodesMock).shouldHaveNoInteractions(); + then(ruleServiceMock).should().getRule(ruleNodeRef); + then(ruleServiceMock).shouldHaveNoMoreInteractions(); + assertThat(rule) + .isNotNull() + .extracting(Rule::getId) + .isEqualTo(RULE_ID); + } + + @Test + public void testGetRuleById_invalidFolder() + { + for (Exception exception : folderValidationExceptions()) + { + Mockito.reset(nodeValidatorMock); + given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willThrow(exception); + + // when + assertThatExceptionOfType(exception.getClass()).isThrownBy( + () -> rules.getRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID)); + + then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, false); + then(nodeValidatorMock).shouldHaveNoMoreInteractions(); + then(ruleServiceMock).shouldHaveNoInteractions(); + } + } + + @Test + public void testGetRuleById_invalidRuleSet() + { + for (Exception exception : ruleSetValidationExceptions()) + { + Mockito.reset(nodeValidatorMock); + given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willReturn(folderNodeRef); + given(nodeValidatorMock.validateRuleSetNode(any(), any())).willThrow(exception); + + // when + assertThatExceptionOfType(exception.getClass()).isThrownBy( + () -> rules.getRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID)); + + then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, false); + then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, folderNodeRef); + then(nodeValidatorMock).shouldHaveNoMoreInteractions(); + then(ruleServiceMock).shouldHaveNoInteractions(); + } + } + + @Test + public void testGetRuleById_invalidRule() + { + for (Exception exception : ruleValidationExceptions()) + { + Mockito.reset(nodeValidatorMock); + given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willReturn(folderNodeRef); + given(nodeValidatorMock.validateRuleSetNode(any(), any())).willReturn(ruleSetNodeRef); + given(nodeValidatorMock.validateRuleNode(any(), any())).willThrow(exception); + + // when + assertThatExceptionOfType(exception.getClass()).isThrownBy( + () -> rules.getRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID)); + + then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, false); + then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, folderNodeRef); + then(nodeValidatorMock).should().validateRuleNode(RULE_ID, ruleSetNodeRef); + then(nodeValidatorMock).shouldHaveNoMoreInteractions(); + then(ruleServiceMock).shouldHaveNoInteractions(); + } + } + + /** Create a single rule. */ + @Test + public void testCreateRules() + { + Rule ruleBody = mock(Rule.class); + List ruleList = List.of(ruleBody); + org.alfresco.service.cmr.rule.Rule serviceRuleBody = mock(org.alfresco.service.cmr.rule.Rule.class); + given(ruleBody.toServiceModel(nodesMock)).willReturn(serviceRuleBody); + org.alfresco.service.cmr.rule.Rule serviceRule = mock(org.alfresco.service.cmr.rule.Rule.class); + given(ruleServiceMock.saveRule(folderNodeRef, serviceRuleBody)).willReturn(serviceRule); + given(serviceRule.getNodeRef()).willReturn(ruleNodeRef); + given(serviceRule.getAction()).willReturn(action); + + // when + List actual = rules.createRules(folderNodeRef.getId(), ruleSetNodeRef.getId(), ruleList); + + then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true); + then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, folderNodeRef); + then(nodeValidatorMock).should().isRuleSetNotNullAndShared(ruleSetNodeRef, folderNodeRef); + then(nodeValidatorMock).shouldHaveNoMoreInteractions(); + then(nodeValidatorMock).should().isRuleSetNotNullAndShared(ruleSetNodeRef, folderNodeRef); + then(ruleServiceMock).should().saveRule(folderNodeRef, ruleBody.toServiceModel(nodesMock)); + then(ruleServiceMock).shouldHaveNoMoreInteractions(); + List expected = List.of(Rule.from(serviceRule, false)); + assertThat(actual).isEqualTo(expected); + } + + /** Check that when passing the default rule set then we don't perform any validation around the rule set node. */ + @Test + public void testCreateRules_defaultRuleSet() + { + Rule ruleBody = mock(Rule.class); + List ruleList = List.of(ruleBody); + org.alfresco.service.cmr.rule.Rule serviceRuleBody = mock(org.alfresco.service.cmr.rule.Rule.class); + given(ruleBody.toServiceModel(nodesMock)).willReturn(serviceRuleBody); + org.alfresco.service.cmr.rule.Rule serviceRule = mock(org.alfresco.service.cmr.rule.Rule.class); + given(ruleServiceMock.saveRule(folderNodeRef, serviceRuleBody)).willReturn(serviceRule); + given(serviceRule.getNodeRef()).willReturn(ruleNodeRef); + given(serviceRule.getAction()).willReturn(action); + + // when + List actual = rules.createRules(folderNodeRef.getId(), DEFAULT_ID, ruleList); + + then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true); + then(nodeValidatorMock).should().isRuleSetNotNullAndShared(null, folderNodeRef); + then(nodeValidatorMock).shouldHaveNoMoreInteractions(); + then(ruleServiceMock).should().saveRule(folderNodeRef, ruleBody.toServiceModel(nodesMock)); + then(ruleServiceMock).shouldHaveNoMoreInteractions(); + List expected = List.of(Rule.from(serviceRule, false)); + assertThat(actual).isEqualTo(expected); + } + + @Test + public void testCreateRules_emptyRuleList() + { + List ruleList = emptyList(); + + // when + List actual = rules.createRules(folderNodeRef.getId(), ruleSetNodeRef.getId(), ruleList); + + then(ruleServiceMock).shouldHaveNoInteractions(); + assertThat(actual).isEqualTo(emptyList()); + } + + /** Create three rules in a single call and check they are all passed to the RuleService. */ + @Test + public void testCreateRules_createMultipleRules() + { + List ruleBodyList = new ArrayList<>(); + List expected = new ArrayList<>(); + for (String ruleId : List.of("A", "B", "C")) + { + Rule ruleBody = mock(Rule.class); + ruleBodyList.add(ruleBody); + org.alfresco.service.cmr.rule.Rule serviceRuleBody = mock(org.alfresco.service.cmr.rule.Rule.class); + given(ruleBody.toServiceModel(nodesMock)).willReturn(serviceRuleBody); + org.alfresco.service.cmr.rule.Rule serviceRule = mock(org.alfresco.service.cmr.rule.Rule.class); + given(ruleServiceMock.saveRule(folderNodeRef, serviceRuleBody)).willReturn(serviceRule); + NodeRef ruleNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, ruleId); + given(serviceRule.getNodeRef()).willReturn(ruleNodeRef); + given(serviceRule.getAction()).willReturn(action); + expected.add(Rule.from(serviceRule, false)); + } + + // when + List actual = rules.createRules(folderNodeRef.getId(), ruleSetNodeRef.getId(), ruleBodyList); + + then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true); + then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, folderNodeRef); + then(nodeValidatorMock).should(times(ruleBodyList.size())).isRuleSetNotNullAndShared(ruleSetNodeRef, folderNodeRef); + then(nodeValidatorMock).shouldHaveNoMoreInteractions(); + for (Rule ruleBody : ruleBodyList) + { + then(ruleServiceMock).should().saveRule(folderNodeRef, ruleBody.toServiceModel(nodesMock)); + } + then(ruleServiceMock).shouldHaveNoMoreInteractions(); + assertThat(actual).isEqualTo(expected); + } + + @Test + public void testCreateRules_invalidFolder() + { + for (Exception exception : folderValidationExceptions()) + { + Mockito.reset(nodeValidatorMock); + given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willThrow(exception); + + // when + assertThatExceptionOfType(exception.getClass()).isThrownBy( + () -> rules.createRules(folderNodeRef.getId(), ruleSetNodeRef.getId(), emptyList())); + + then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true); + then(nodeValidatorMock).shouldHaveNoMoreInteractions(); + then(ruleServiceMock).shouldHaveNoInteractions(); + } + } + + @Test + public void testCreateRules_invalidRuleSet() + { + for (Exception exception : ruleSetValidationExceptions()) + { + Mockito.reset(nodeValidatorMock); + given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willReturn(folderNodeRef); + given(nodeValidatorMock.validateRuleSetNode(any(), any())).willThrow(exception); + + // when + assertThatExceptionOfType(exception.getClass()).isThrownBy( + () -> rules.createRules(folderNodeRef.getId(), ruleSetNodeRef.getId(), emptyList())); + + then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true); + then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, folderNodeRef); + then(nodeValidatorMock).shouldHaveNoMoreInteractions(); + then(ruleServiceMock).shouldHaveNoInteractions(); + } + } + + /** Check that we can update a rule. */ + @Test + public void testUpdateRuleById() + { + Rule ruleBody = mock(Rule.class); + given(nodeValidatorMock.isRuleSetNotNullAndShared(any(), any())).willReturn(true); + org.alfresco.service.cmr.rule.Rule serviceRuleBody = mock(org.alfresco.service.cmr.rule.Rule.class); + given(ruleBody.toServiceModel(nodesMock)).willReturn(serviceRuleBody); + org.alfresco.service.cmr.rule.Rule serviceRule = mock(org.alfresco.service.cmr.rule.Rule.class); + given(ruleServiceMock.saveRule(folderNodeRef, serviceRuleBody)).willReturn(serviceRule); + given(serviceRule.getNodeRef()).willReturn(ruleNodeRef); + given(serviceRule.getAction()).willReturn(action); + + // when + Rule updatedRule = rules.updateRuleById(folderNodeRef.getId(), ruleSetNodeRef.getId(), RULE_ID, ruleBody); + + then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true); + then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, folderNodeRef); + then(nodeValidatorMock).should().validateRuleNode(RULE_ID, ruleSetNodeRef); + then(nodeValidatorMock).should().isRuleSetNotNullAndShared(ruleSetNodeRef, folderNodeRef); + then(nodeValidatorMock).shouldHaveNoMoreInteractions(); + then(ruleServiceMock).should().saveRule(folderNodeRef, serviceRuleBody); + then(ruleServiceMock).shouldHaveNoMoreInteractions(); + + + Rule expected = Rule.builder().id(RULE_ID) + .enabled(true) + .shared(true) + .triggers(emptyList()) + .conditions(CompositeCondition.builder().inverted(false).create()) + .create(); + assertThat(updatedRule).isEqualTo(expected); + } + + @Test + public void testUpdateRuleById_invalidFolder() + { + for (Exception exception : folderValidationExceptions()) + { + Mockito.reset(nodeValidatorMock); + given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willThrow(exception); + + // when + assertThatExceptionOfType(exception.getClass()).isThrownBy( + () -> rules.updateRuleById(folderNodeRef.getId(), ruleSetNodeRef.getId(), RULE_ID, mock(Rule.class))); + + then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true); + then(nodeValidatorMock).shouldHaveNoMoreInteractions(); + then(ruleServiceMock).shouldHaveNoInteractions(); + } + } + + @Test + public void testUpdateRuleById_invalidRuleSet() + { + for (Exception exception : ruleSetValidationExceptions()) + { + Mockito.reset(nodeValidatorMock); + given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willReturn(folderNodeRef); + given(nodeValidatorMock.validateRuleSetNode(any(), any())).willThrow(exception); + + // when + assertThatExceptionOfType(exception.getClass()).isThrownBy( + () -> rules.updateRuleById(folderNodeRef.getId(), ruleSetNodeRef.getId(), RULE_ID, mock(Rule.class))); + + then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true); + then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, folderNodeRef); + then(nodeValidatorMock).shouldHaveNoMoreInteractions(); + then(ruleServiceMock).shouldHaveNoInteractions(); + } + } + + @Test + public void testUpdateRuleById_invalidRule() + { + for (Exception exception : ruleValidationExceptions()) + { + Mockito.reset(nodeValidatorMock); + given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willReturn(folderNodeRef); + given(nodeValidatorMock.validateRuleSetNode(any(), any())).willReturn(ruleSetNodeRef); + given(nodeValidatorMock.validateRuleNode(any(), any())).willThrow(exception); + + // when + assertThatExceptionOfType(exception.getClass()).isThrownBy( + () -> rules.updateRuleById(folderNodeRef.getId(), ruleSetNodeRef.getId(), RULE_ID, mock(Rule.class))); + + then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true); + then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, folderNodeRef); + then(nodeValidatorMock).should().validateRuleNode(RULE_ID, ruleSetNodeRef); + then(nodeValidatorMock).shouldHaveNoMoreInteractions(); + then(ruleServiceMock).shouldHaveNoInteractions(); + } + } + + @Test + public void testDeleteRuleById() { + org.alfresco.service.cmr.rule.Rule rule = createRule(RULE_ID); + given(ruleServiceMock.getRule(any())).willReturn(rule); + + //when + rules.deleteRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID); + + then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true); + then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, folderNodeRef); + then(nodeValidatorMock).should().validateRuleNode(RULE_ID, ruleSetNodeRef); + then(nodeValidatorMock).shouldHaveNoMoreInteractions(); + then(nodesMock).shouldHaveNoInteractions(); + then(ruleServiceMock).should().getRule(ruleNodeRef); + then(ruleServiceMock).should().removeRule(folderNodeRef, rule); + then(ruleServiceMock).shouldHaveNoMoreInteractions(); + } + + @Test + public void testDeleteRuleById_invalidFolder() + { + for (Exception exception : folderValidationExceptions()) + { + Mockito.reset(nodeValidatorMock); + given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willThrow(exception); + + // when + assertThatExceptionOfType(exception.getClass()).isThrownBy( + () -> rules.deleteRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID)); + + then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true); + then(nodeValidatorMock).shouldHaveNoMoreInteractions(); + then(ruleServiceMock).shouldHaveNoInteractions(); + } + } + + @Test + public void testDeleteRuleById_invalidRuleSet() + { + for (Exception exception : ruleSetValidationExceptions()) + { + Mockito.reset(nodeValidatorMock); + given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willReturn(folderNodeRef); + given(nodeValidatorMock.validateRuleSetNode(any(), any())).willThrow(exception); + + // when + assertThatExceptionOfType(exception.getClass()).isThrownBy( + () -> rules.deleteRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID)); + + then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true); + then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, folderNodeRef); + then(nodeValidatorMock).shouldHaveNoMoreInteractions(); + then(ruleServiceMock).shouldHaveNoInteractions(); + } + } + + @Test + public void testDeleteRuleById_invalidRule() + { + for (Exception exception : ruleValidationExceptions()) + { + Mockito.reset(nodeValidatorMock); + given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willReturn(folderNodeRef); + given(nodeValidatorMock.validateRuleSetNode(any(), any())).willReturn(ruleSetNodeRef); + given(nodeValidatorMock.validateRuleNode(any(), any())).willThrow(exception); + + // when + assertThatExceptionOfType(exception.getClass()).isThrownBy( + () -> rules.deleteRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID)); + + then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true); + then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, folderNodeRef); + then(nodeValidatorMock).should().validateRuleNode(RULE_ID, ruleSetNodeRef); + then(nodeValidatorMock).shouldHaveNoMoreInteractions(); + then(ruleServiceMock).shouldHaveNoInteractions(); + } + } + + private static org.alfresco.service.cmr.rule.Rule createRule(final String id) { + final NodeRef nodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, id); + final org.alfresco.service.cmr.rule.Rule rule = new org.alfresco.service.cmr.rule.Rule(); + rule.setNodeRef(nodeRef); + rule.setRuleType("ruleType"); + rule.setAction(action); + + return rule; + } + + private static List folderValidationExceptions() + { + return List.of( + new EntityNotFoundException(FOLDER_NODE_ID), + new InvalidArgumentException(), + new PermissionDeniedException() + ); + } + + private static List ruleSetValidationExceptions() + { + return List.of( + new EntityNotFoundException(RULE_SET_ID), + new InvalidArgumentException(), + new RelationshipResourceNotFoundException(RULE_SET_ID, "fake-relationship-id") + ); + } + + private static List ruleValidationExceptions() + { + return List.of( + new EntityNotFoundException(RULE_ID), + new InvalidArgumentException(), + new RelationshipResourceNotFoundException(RULE_ID, "fake-relationship-id") + ); + } +}