ACS-3489 Use specified rule set. (#1373)

* ACS-3280 Get inherited rule sets. [tas]

This needs to work the exact same way as get inherited rules.

* ACS-3280 Replace LinkedList with ArrayList.

* ACS-3280 Don't return duplicated rule sets when there are links.

* ACS-3489 E2E test for getting rules with inheritance.

* ACS-3489 Inherited rule sets are also associated with folders.

* ACS-3489 Fix test to contain expected values.

* ACS-3489 Ensure only rules from specified rule set are returned.

Add E2E test case for inherited links and fix unit tests.

* ACS-3489 Fix audit reference in RuleService.
This commit is contained in:
Tom Page
2022-09-13 10:23:16 +01:00
committed by GitHub
parent bc9c23503b
commit 400b33c7eb
6 changed files with 221 additions and 13 deletions

View File

@@ -0,0 +1,142 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2016 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 <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.rules;
import static org.alfresco.rest.rules.RulesTestsUtils.createRuleModelWithModifiedValues;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.testng.Assert.assertEquals;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.alfresco.rest.RestTest;
import org.alfresco.rest.model.RestRuleModel;
import org.alfresco.rest.model.RestRuleModelsCollection;
import org.alfresco.rest.model.RestRuleSetLinkModel;
import org.alfresco.rest.model.RestRuleSetModel;
import org.alfresco.rest.model.RestRuleSetModelsCollection;
import org.alfresco.utility.model.FolderModel;
import org.alfresco.utility.model.SiteModel;
import org.alfresco.utility.model.TestGroup;
import org.alfresco.utility.model.UserModel;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
/**
* Tests for GET /nodes/{nodeId}/rule-sets/{ruleSetId}/rules with rule inheritance.
*/
@Test(groups = {TestGroup.RULES})
public class GetInheritedRulesTests extends RestTest
{
private UserModel user;
private SiteModel site;
@BeforeClass(alwaysRun = true)
public void dataPreparation()
{
STEP("Create a user and site");
user = dataUser.createRandomTestUser();
site = dataSite.usingUser(user).createPublicRandomSite();
}
/**
* Check we can get all the rules for the folder by providing the different rule set ids.
*/
@Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
public void getInheritedRules()
{
STEP("Create a parent and child folder, each with inheriting rules");
FolderModel parent = dataContent.usingUser(user).usingSite(site).createFolder();
FolderModel child = dataContent.usingUser(user).usingResource(parent).createFolder();
RestRuleModel parentRule = createRuleModelWithModifiedValues();
parentRule = restClient.authenticateUser(user).withCoreAPI().usingNode(parent).usingDefaultRuleSet().createSingleRule(parentRule);
RestRuleModel childRule = createRuleModelWithModifiedValues();
childRule = restClient.authenticateUser(user).withCoreAPI().usingNode(child).usingDefaultRuleSet().createSingleRule(childRule);
STEP("Get the rules in the default rule set for the child folder");
RestRuleModelsCollection rules = restClient.authenticateUser(user).withCoreAPI().usingNode(child).usingDefaultRuleSet().getListOfRules();
rules.assertThat().entriesListContains("id", childRule.getId())
.and().entriesListCountIs(1);
STEP("Get the rules in the inherited rule set for the child folder");
RestRuleSetModelsCollection ruleSets = restClient.authenticateUser(user).withCoreAPI().usingNode(child).include("inclusionType").getListOfRuleSets();
String inheritedRuleSetId = ruleSets.getEntries().stream()
.filter(ruleSet -> ruleSet.onModel().getInclusionType().equals("inherited"))
.findFirst().get().onModel().getId();
RestRuleModelsCollection inheritedRules = restClient.authenticateUser(user).withCoreAPI().usingNode(child).usingRuleSet(inheritedRuleSetId).getListOfRules();
inheritedRules.assertThat().entriesListContains("id", parentRule.getId())
.and().entriesListCountIs(1);
}
/**
* Check that we only get each rule once with linking and inheritance, and the order is correct.
* <p>
* The folder structure for this test is as follows:
* <pre>
* A --[links]-> DRuleSet
* +-B --[owns]-> BRuleSet
* +-C --[owns]-> CRuleSet
* +-D --[owns]--> DRuleSet
* </pre>
*/
@Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
public void rulesReturnedAreUnique()
{
STEP("Create four folders with rules");
FolderModel folderA = dataContent.usingUser(user).usingSite(site).createFolder();
FolderModel folderB = dataContent.usingUser(user).usingResource(folderA).createFolder();
FolderModel folderC = dataContent.usingUser(user).usingResource(folderB).createFolder();
FolderModel folderD = dataContent.usingUser(user).usingResource(folderC).createFolder();
RestRuleModel ruleB = restClient.authenticateUser(user).withCoreAPI().usingNode(folderB).usingDefaultRuleSet().createSingleRule(createRuleModelWithModifiedValues());
RestRuleModel ruleC = restClient.authenticateUser(user).withCoreAPI().usingNode(folderC).usingDefaultRuleSet().createSingleRule(createRuleModelWithModifiedValues());
RestRuleModel ruleD = restClient.authenticateUser(user).withCoreAPI().usingNode(folderD).usingDefaultRuleSet().createSingleRule(createRuleModelWithModifiedValues());
STEP("Link folderA to ruleSetD");
RestRuleSetLinkModel linkModel = new RestRuleSetLinkModel();
linkModel.setId(folderD.getNodeRef());
restClient.authenticateUser(user).withCoreAPI().usingNode(folderA).createRuleLink(linkModel);
STEP("Get the rule sets for the folderD");
List<RestRuleSetModel> ruleSets = restClient.authenticateUser(user).withCoreAPI().usingNode(folderD).getListOfRuleSets().getEntries();
STEP("Check the rules for each rule set are as expected");
List<RestRuleModel> expectedRuleIds = List.of(ruleD, ruleB, ruleC);
IntStream.range(0, 2).forEach(index -> {
String ruleSetId = ruleSets.get(index).onModel().getId();
List<RestRuleModel> rules = restClient.authenticateUser(user)
.withCoreAPI()
.usingNode(folderD)
.usingRuleSet(ruleSetId)
.getListOfRules()
.getEntries()
.stream()
.map(RestRuleModel::onModel)
.collect(Collectors.toList());
assertEquals(rules, List.of(expectedRuleIds.get(index)), "Unexpected rules found for rule set " + ruleSetId);
});
assertEquals(ruleSets.size(), 3, "Expected three unique rule sets to be returned but got " + ruleSets);
}
}

View File

@@ -63,9 +63,10 @@ public class RulesImpl implements Rules
final Paging paging) final Paging paging)
{ {
final NodeRef folderNodeRef = validator.validateFolderNode(folderNodeId, false); final NodeRef folderNodeRef = validator.validateFolderNode(folderNodeId, false);
validator.validateRuleSetNode(ruleSetId, folderNodeRef); NodeRef ruleSetNode = validator.validateRuleSetNode(ruleSetId, folderNodeRef);
NodeRef owningFolder = ruleService.getOwningNodeRef(ruleSetNode);
final List<Rule> rules = ruleService.getRules(folderNodeRef).stream() final List<Rule> rules = ruleService.getRules(owningFolder, false).stream()
.map(ruleModel -> loadRuleAndConvertActionParams(ruleModel, includes)) .map(ruleModel -> loadRuleAndConvertActionParams(ruleModel, includes))
.collect(Collectors.toList()); .collect(Collectors.toList());

View File

@@ -115,7 +115,8 @@ public class RulesImplTest extends TestCase
given(nodeValidatorMock.validateRuleNode(any(), any())).willReturn(RULE_NODE_REF); given(nodeValidatorMock.validateRuleNode(any(), any())).willReturn(RULE_NODE_REF);
given(ruleServiceMock.getRule(RULE_NODE_REF)).willReturn(ruleModel); given(ruleServiceMock.getRule(RULE_NODE_REF)).willReturn(ruleModel);
given(ruleServiceMock.getRules(FOLDER_NODE_REF)).willReturn(List.of(ruleModel)); given(ruleServiceMock.getRules(FOLDER_NODE_REF, false)).willReturn(List.of(ruleModel));
given(ruleServiceMock.getOwningNodeRef(RULE_SET_NODE_REF)).willReturn(FOLDER_NODE_REF);
given(ruleLoaderMock.loadRule(ruleModel, INCLUDE)).willReturn(ruleMock); given(ruleLoaderMock.loadRule(ruleModel, INCLUDE)).willReturn(ruleMock);
@@ -126,13 +127,15 @@ public class RulesImplTest extends TestCase
public void testGetRules() public void testGetRules()
{ {
given(ruleLoaderMock.loadRule(ruleModel, emptyList())).willReturn(ruleMock); given(ruleLoaderMock.loadRule(ruleModel, emptyList())).willReturn(ruleMock);
// when // when
final CollectionWithPagingInfo<Rule> rulesPage = rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, INCLUDE, PAGING); final CollectionWithPagingInfo<Rule> rulesPage = rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, INCLUDE, PAGING);
then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, false); then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, false);
then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, FOLDER_NODE_REF); then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, FOLDER_NODE_REF);
then(nodeValidatorMock).shouldHaveNoMoreInteractions(); then(nodeValidatorMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).should().getRules(FOLDER_NODE_REF); then(ruleServiceMock).should().getOwningNodeRef(RULE_SET_NODE_REF);
then(ruleServiceMock).should().getRules(FOLDER_NODE_REF, false);
then(ruleServiceMock).shouldHaveNoMoreInteractions(); then(ruleServiceMock).shouldHaveNoMoreInteractions();
then(ruleLoaderMock).should().loadRule(ruleModel, emptyList()); then(ruleLoaderMock).should().loadRule(ruleModel, emptyList());
then(ruleLoaderMock).shouldHaveNoMoreInteractions(); then(ruleLoaderMock).shouldHaveNoMoreInteractions();
@@ -148,12 +151,13 @@ public class RulesImplTest extends TestCase
@Test @Test
public void testGetRules_emptyResult() public void testGetRules_emptyResult()
{ {
given(ruleServiceMock.getRules(any())).willReturn(emptyList()); given(ruleServiceMock.getRules(FOLDER_NODE_REF, false)).willReturn(emptyList());
// when // when
final CollectionWithPagingInfo<Rule> rulesPage = rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, INCLUDE, PAGING); final CollectionWithPagingInfo<Rule> rulesPage = rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, INCLUDE, PAGING);
then(ruleServiceMock).should().getRules(FOLDER_NODE_REF); then(ruleServiceMock).should().getOwningNodeRef(RULE_SET_NODE_REF);
then(ruleServiceMock).should().getRules(FOLDER_NODE_REF, false);
then(ruleServiceMock).shouldHaveNoMoreInteractions(); then(ruleServiceMock).shouldHaveNoMoreInteractions();
assertThat(rulesPage) assertThat(rulesPage)
.isNotNull() .isNotNull()

View File

@@ -26,6 +26,7 @@
package org.alfresco.repo.rule; package org.alfresco.repo.rule;
import static org.alfresco.repo.rule.RuleModel.ASPECT_IGNORE_INHERITED_RULES; import static org.alfresco.repo.rule.RuleModel.ASPECT_IGNORE_INHERITED_RULES;
import static org.alfresco.repo.rule.RuleModel.ASSOC_RULE_FOLDER;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
@@ -35,6 +36,9 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
import com.google.common.collect.Sets;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.action.ActionImpl; import org.alfresco.repo.action.ActionImpl;
@@ -257,7 +261,7 @@ public class RuleServiceImpl
policyComponent.bindAssociationBehaviour( policyComponent.bindAssociationBehaviour(
NodeServicePolicies.OnCreateChildAssociationPolicy.QNAME, NodeServicePolicies.OnCreateChildAssociationPolicy.QNAME,
RuleModel.ASPECT_RULES, RuleModel.ASPECT_RULES,
RuleModel.ASSOC_RULE_FOLDER, ASSOC_RULE_FOLDER,
new JavaBehaviour(this, "onCreateChildAssociation")); new JavaBehaviour(this, "onCreateChildAssociation"));
policyComponent.bindClassBehaviour( policyComponent.bindClassBehaviour(
NodeServicePolicies.OnAddAspectPolicy.QNAME, NodeServicePolicies.OnAddAspectPolicy.QNAME,
@@ -349,8 +353,8 @@ public class RuleServiceImpl
List<ChildAssociationRef> assocs = this.runtimeNodeService.getChildAssocs( List<ChildAssociationRef> assocs = this.runtimeNodeService.getChildAssocs(
nodeRef, nodeRef,
RuleModel.ASSOC_RULE_FOLDER, ASSOC_RULE_FOLDER,
RuleModel.ASSOC_RULE_FOLDER); ASSOC_RULE_FOLDER);
if (assocs.size() > 1) if (assocs.size() > 1)
{ {
throw new ActionServiceException("There is more than one rule folder, which is invalid."); throw new ActionServiceException("There is more than one rule folder, which is invalid.");
@@ -1568,6 +1572,12 @@ public class RuleServiceImpl
return this.nodeService.getPrimaryParent(systemFolder).getParentRef(); return this.nodeService.getPrimaryParent(systemFolder).getParentRef();
} }
@Override
public NodeRef getOwningNodeRef(NodeRef ruleSet)
{
return nodeService.getPrimaryParent(ruleSet).getParentRef();
}
@Override @Override
public NodeRef getOwningNodeRef(final Action action) public NodeRef getOwningNodeRef(final Action action)
{ {
@@ -1660,7 +1670,7 @@ public class RuleServiceImpl
@Experimental @Experimental
public NodeRef getRuleSetNode(final NodeRef folderNodeRef) public NodeRef getRuleSetNode(final NodeRef folderNodeRef)
{ {
return runtimeNodeService.getChildAssocs(folderNodeRef, RuleModel.ASSOC_RULE_FOLDER, RuleModel.ASSOC_RULE_FOLDER).stream() return runtimeNodeService.getChildAssocs(folderNodeRef, ASSOC_RULE_FOLDER, ASSOC_RULE_FOLDER).stream()
.map(ChildAssociationRef::getChildRef) .map(ChildAssociationRef::getChildRef)
.findFirst() .findFirst()
.orElse(null); .orElse(null);
@@ -1670,7 +1680,10 @@ public class RuleServiceImpl
@Experimental @Experimental
public boolean isRuleSetAssociatedWithFolder(final NodeRef ruleSetNodeRef, final NodeRef folderNodeRef) public boolean isRuleSetAssociatedWithFolder(final NodeRef ruleSetNodeRef, final NodeRef folderNodeRef)
{ {
return isChildOf(ruleSetNodeRef, RuleModel.ASSOC_RULE_FOLDER, folderNodeRef); List<ChildAssociationRef> associations = runtimeNodeService.getParentAssocs(ruleSetNodeRef, ASSOC_RULE_FOLDER, ASSOC_RULE_FOLDER);
Set<NodeRef> associatedFolders = associations.stream().map(ChildAssociationRef::getParentRef).collect(Collectors.toSet());
Set<NodeRef> supplyingFolders = new HashSet<>(getNodesSupplyingRuleSets(folderNodeRef));
return !Sets.intersection(associatedFolders, supplyingFolders).isEmpty();
} }
@Override @Override

View File

@@ -312,6 +312,16 @@ public interface RuleService
@Auditable(parameters = {"action"}) @Auditable(parameters = {"action"})
public NodeRef getOwningNodeRef(Action action); public NodeRef getOwningNodeRef(Action action);
/**
* Returns the owning node reference for a rule.
*
* @param ruleSet The rule set node.
* @return the owning node reference
*/
@Auditable (parameters = { "ruleSet" })
@Experimental
NodeRef getOwningNodeRef(NodeRef ruleSet);
/** /**
* Indicates whether the passed rule node reference is linked to another * Indicates whether the passed rule node reference is linked to another
* rule node. * rule node.
@@ -353,7 +363,7 @@ public interface RuleService
NodeRef getRuleSetNode(final NodeRef folderNodeRef); NodeRef getRuleSetNode(final NodeRef folderNodeRef);
/** /**
* Check if rule set's associated parent matches folder node. * Check if rule set is associated (owned/linked/inherited) with the given folder node.
* *
* @param ruleSetNodeRef - node reference of a rule set * @param ruleSetNodeRef - node reference of a rule set
* @param folderNodeRef - node reference of a folder * @param folderNodeRef - node reference of a folder

View File

@@ -254,6 +254,8 @@ public class RuleServiceImplUnitTest
boolean associated = ruleService.isRuleSetAssociatedWithFolder(RULE_SET_NODE, FOLDER_NODE); boolean associated = ruleService.isRuleSetAssociatedWithFolder(RULE_SET_NODE, FOLDER_NODE);
then(runtimeNodeService).should().getParentAssocs(RULE_SET_NODE, ASSOC_RULE_FOLDER, ASSOC_RULE_FOLDER); then(runtimeNodeService).should().getParentAssocs(RULE_SET_NODE, ASSOC_RULE_FOLDER, ASSOC_RULE_FOLDER);
then(runtimeNodeService).should().hasAspect(FOLDER_NODE, ASPECT_IGNORE_INHERITED_RULES);
then(runtimeNodeService).should().getParentAssocs(FOLDER_NODE);
then(runtimeNodeService).shouldHaveNoMoreInteractions(); then(runtimeNodeService).shouldHaveNoMoreInteractions();
then(nodeService).shouldHaveNoInteractions(); then(nodeService).shouldHaveNoInteractions();
assertThat(associated).isTrue(); assertThat(associated).isTrue();
@@ -268,6 +270,8 @@ public class RuleServiceImplUnitTest
boolean associated = ruleService.isRuleSetAssociatedWithFolder(RULE_SET_NODE, FOLDER_NODE); boolean associated = ruleService.isRuleSetAssociatedWithFolder(RULE_SET_NODE, FOLDER_NODE);
then(runtimeNodeService).should().getParentAssocs(RULE_SET_NODE, ASSOC_RULE_FOLDER, ASSOC_RULE_FOLDER); then(runtimeNodeService).should().getParentAssocs(RULE_SET_NODE, ASSOC_RULE_FOLDER, ASSOC_RULE_FOLDER);
then(runtimeNodeService).should().hasAspect(FOLDER_NODE, ASPECT_IGNORE_INHERITED_RULES);
then(runtimeNodeService).should().getParentAssocs(FOLDER_NODE);
then(runtimeNodeService).shouldHaveNoMoreInteractions(); then(runtimeNodeService).shouldHaveNoMoreInteractions();
then(nodeService).shouldHaveNoInteractions(); then(nodeService).shouldHaveNoInteractions();
assertThat(associated).isFalse(); assertThat(associated).isFalse();
@@ -283,11 +287,45 @@ public class RuleServiceImplUnitTest
boolean associated = ruleService.isRuleSetAssociatedWithFolder(RULE_SET_NODE, FOLDER_NODE); boolean associated = ruleService.isRuleSetAssociatedWithFolder(RULE_SET_NODE, FOLDER_NODE);
then(runtimeNodeService).should().getParentAssocs(RULE_SET_NODE, ASSOC_RULE_FOLDER, ASSOC_RULE_FOLDER); then(runtimeNodeService).should().getParentAssocs(RULE_SET_NODE, ASSOC_RULE_FOLDER, ASSOC_RULE_FOLDER);
then(runtimeNodeService).should().hasAspect(FOLDER_NODE, ASPECT_IGNORE_INHERITED_RULES);
then(runtimeNodeService).should().getParentAssocs(FOLDER_NODE);
then(runtimeNodeService).shouldHaveNoMoreInteractions(); then(runtimeNodeService).shouldHaveNoMoreInteractions();
then(nodeService).shouldHaveNoInteractions(); then(nodeService).shouldHaveNoInteractions();
assertThat(associated).isFalse(); assertThat(associated).isFalse();
} }
/**
* Check that a rule set is associated with the folder in the following case:
* <pre>
* parent --[link]-> rule set <-[owned]-- owningFolder
* +- child
* </pre>
*/
@Test
public void testIsRuleSetAssociatedWithFolder_inheritedLinkedAssociation()
{
// The rule is owned by one node.
NodeRef owningFolder = new NodeRef("owning://node/");
// The rule is linked to by the parent node.
NodeRef parent = new NodeRef("parent://node/");
List<ChildAssociationRef> ruleAssociations = List.of(createAssociation(owningFolder, RULE_SET_NODE), createAssociation(parent, RULE_SET_NODE));
given(runtimeNodeService.getParentAssocs(RULE_SET_NODE, ASSOC_RULE_FOLDER, ASSOC_RULE_FOLDER)).willReturn(ruleAssociations);
// The parent and the child both supply rule sets.
given(runtimeNodeService.getParentAssocs(FOLDER_NODE)).willReturn(List.of(createAssociation(parent, FOLDER_NODE)));
// when
boolean associated = ruleService.isRuleSetAssociatedWithFolder(RULE_SET_NODE, FOLDER_NODE);
then(runtimeNodeService).should().getParentAssocs(RULE_SET_NODE, ASSOC_RULE_FOLDER, ASSOC_RULE_FOLDER);
then(runtimeNodeService).should().hasAspect(FOLDER_NODE, ASPECT_IGNORE_INHERITED_RULES);
then(runtimeNodeService).should().getParentAssocs(FOLDER_NODE);
then(runtimeNodeService).should().hasAspect(parent, ASPECT_IGNORE_INHERITED_RULES);
then(runtimeNodeService).should().getParentAssocs(parent);
then(runtimeNodeService).shouldHaveNoMoreInteractions();
then(nodeService).shouldHaveNoInteractions();
assertThat(associated).isTrue();
}
@Test @Test
public void testIsRuleAssociatedWithRuleSet() public void testIsRuleAssociatedWithRuleSet()
{ {