mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
ACS-3649, ACS-3650 Action validation mechanism + validations against Action Definitions (#1481)
* ACS-3572: Action constraints endpoint + logic + unit tests. * ACS-3572: Action constraints endpoint + logic + unit tests. * ACS-3572: Action constraints endpoint fixes. * ACS-3572: Cleanup after removal of GET all Action constraints. * ACS-3572: Fixing formatting in tests. * ACS-3572: Loosening V1 constraints restrictions for aspects, types and properties. * ACS-3649: Action validators - constraints. * ACS-3649: Action validators - constraints. * ACS-3649: Action validators - constraints. * ACS-3572: Adding validation for extra paramater. * ACS-3649: Small refactors and fixes. * ACS-3649: Validations against action definition. * ACS-3649: Adding @Experimental annotation. * ACS-3649: Fixes/refactoring after code review. * ACS-3649: Removing ignored test
This commit is contained in:
@@ -26,7 +26,6 @@
|
|||||||
package org.alfresco.rest.rules;
|
package org.alfresco.rest.rules;
|
||||||
|
|
||||||
import static java.util.stream.Collectors.toList;
|
import static java.util.stream.Collectors.toList;
|
||||||
|
|
||||||
import static org.alfresco.rest.actions.access.AccessRestrictionUtil.ERROR_MESSAGE_ACCESS_RESTRICTED;
|
import static org.alfresco.rest.actions.access.AccessRestrictionUtil.ERROR_MESSAGE_ACCESS_RESTRICTED;
|
||||||
import static org.alfresco.rest.rules.RulesTestsUtils.ID;
|
import static org.alfresco.rest.rules.RulesTestsUtils.ID;
|
||||||
import static org.alfresco.rest.rules.RulesTestsUtils.INVERTED;
|
import static org.alfresco.rest.rules.RulesTestsUtils.INVERTED;
|
||||||
@@ -34,6 +33,7 @@ import static org.alfresco.rest.rules.RulesTestsUtils.IS_SHARED;
|
|||||||
import static org.alfresco.rest.rules.RulesTestsUtils.RULE_NAME_DEFAULT;
|
import static org.alfresco.rest.rules.RulesTestsUtils.RULE_NAME_DEFAULT;
|
||||||
import static org.alfresco.rest.rules.RulesTestsUtils.createAddAudioAspectAction;
|
import static org.alfresco.rest.rules.RulesTestsUtils.createAddAudioAspectAction;
|
||||||
import static org.alfresco.rest.rules.RulesTestsUtils.createCompositeCondition;
|
import static org.alfresco.rest.rules.RulesTestsUtils.createCompositeCondition;
|
||||||
|
import static org.alfresco.rest.rules.RulesTestsUtils.createCustomActionModel;
|
||||||
import static org.alfresco.rest.rules.RulesTestsUtils.createRuleModel;
|
import static org.alfresco.rest.rules.RulesTestsUtils.createRuleModel;
|
||||||
import static org.alfresco.rest.rules.RulesTestsUtils.createRuleModelWithDefaultValues;
|
import static org.alfresco.rest.rules.RulesTestsUtils.createRuleModelWithDefaultValues;
|
||||||
import static org.alfresco.rest.rules.RulesTestsUtils.createRuleModelWithModifiedValues;
|
import static org.alfresco.rest.rules.RulesTestsUtils.createRuleModelWithModifiedValues;
|
||||||
@@ -441,8 +441,94 @@ public class CreateRulesTests extends RestTest
|
|||||||
restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
|
restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
|
||||||
.createSingleRule(ruleModel);
|
.createSingleRule(ruleModel);
|
||||||
|
|
||||||
restClient.assertStatusCodeIs(NOT_FOUND);
|
restClient.assertStatusCodeIs(BAD_REQUEST);
|
||||||
restClient.assertLastError().containsSummary(actionDefinitionId);
|
restClient.assertLastError().containsSummary(String.format("Invalid action definition requested %s", actionDefinitionId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check we get error when attempt to create a rule with missing action parameters.
|
||||||
|
*/
|
||||||
|
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
|
||||||
|
public void createRuleWithMissingActionParametersShouldFail()
|
||||||
|
{
|
||||||
|
final RestRuleModel ruleModel = createRuleModelWithDefaultValues();
|
||||||
|
final RestActionBodyExecTemplateModel invalidAction = new RestActionBodyExecTemplateModel();
|
||||||
|
final String actionDefinitionId = "copy";
|
||||||
|
invalidAction.setActionDefinitionId(actionDefinitionId);
|
||||||
|
ruleModel.setActions(List.of(invalidAction));
|
||||||
|
|
||||||
|
restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
|
||||||
|
.createSingleRule(ruleModel);
|
||||||
|
|
||||||
|
restClient.assertStatusCodeIs(BAD_REQUEST);
|
||||||
|
restClient.assertLastError().containsSummary(
|
||||||
|
String.format("Action parameters should not be null or empty for this action. See Action Definition for action of: %s",
|
||||||
|
actionDefinitionId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check we get error when attempt to create a rule with parameter not fulfilling constraint.
|
||||||
|
*/
|
||||||
|
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
|
||||||
|
public void createRuleWithActionParameterNotFulfillingConstraint()
|
||||||
|
{
|
||||||
|
final RestRuleModel ruleModel = createRuleModelWithDefaultValues();
|
||||||
|
final String actionDefinitionId = "script";
|
||||||
|
final String scriptRef = "script-ref";
|
||||||
|
final String scriptNodeId = "dummy-script-node-id";
|
||||||
|
final RestActionBodyExecTemplateModel scriptAction = createCustomActionModel(actionDefinitionId, Map.of(scriptRef, scriptNodeId));
|
||||||
|
ruleModel.setActions(List.of(scriptAction));
|
||||||
|
|
||||||
|
restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
|
||||||
|
.createSingleRule(ruleModel);
|
||||||
|
|
||||||
|
restClient.assertStatusCodeIs(BAD_REQUEST);
|
||||||
|
final String acScriptsConstraint = "ac-scripts";
|
||||||
|
restClient.assertLastError().containsSummary(
|
||||||
|
String.format("Action parameter: %s has invalid value (%s). Look up possible values for constraint name %s",
|
||||||
|
scriptRef, scriptNodeId, acScriptsConstraint));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check we get error when attempt to create a rule with action parameter that should not be passed.
|
||||||
|
*/
|
||||||
|
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
|
||||||
|
public void createRuleWithoutInvalidActionParameterShouldFail()
|
||||||
|
{
|
||||||
|
final RestRuleModel ruleModel = createRuleModelWithDefaultValues();
|
||||||
|
final RestActionBodyExecTemplateModel invalidAction = new RestActionBodyExecTemplateModel();
|
||||||
|
final String actionDefinitionId = "add-features";
|
||||||
|
invalidAction.setActionDefinitionId(actionDefinitionId);
|
||||||
|
final String invalidParameterKey = "invalidParameterKey";
|
||||||
|
invalidAction.setParams(Map.of(invalidParameterKey,"dummyValue"));
|
||||||
|
ruleModel.setActions(List.of(invalidAction));
|
||||||
|
|
||||||
|
restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
|
||||||
|
.createSingleRule(ruleModel);
|
||||||
|
|
||||||
|
restClient.assertStatusCodeIs(BAD_REQUEST);
|
||||||
|
restClient.assertLastError().containsSummary(
|
||||||
|
String.format("Action of definition id: %s must not contain parameter of name: %s", actionDefinitionId, invalidParameterKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check we get error when attempt to create a rule with missing mandatory action parameter.
|
||||||
|
*/
|
||||||
|
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
|
||||||
|
public void createRuleWithoutMandatoryActionParametersShouldFail()
|
||||||
|
{
|
||||||
|
final RestRuleModel ruleModel = createRuleModelWithDefaultValues();
|
||||||
|
final RestActionBodyExecTemplateModel invalidAction = new RestActionBodyExecTemplateModel();
|
||||||
|
final String actionDefinitionId = "copy";
|
||||||
|
invalidAction.setActionDefinitionId(actionDefinitionId);
|
||||||
|
invalidAction.setParams(Map.of("deep-copy",false));
|
||||||
|
ruleModel.setActions(List.of(invalidAction));
|
||||||
|
|
||||||
|
restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
|
||||||
|
.createSingleRule(ruleModel);
|
||||||
|
|
||||||
|
restClient.assertStatusCodeIs(BAD_REQUEST);
|
||||||
|
restClient.assertLastError().containsSummary("Missing action's mandatory parameter: destination-folder");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -54,6 +54,7 @@ import org.alfresco.utility.model.UserModel;
|
|||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.testng.annotations.BeforeClass;
|
import org.testng.annotations.BeforeClass;
|
||||||
import org.testng.annotations.BeforeMethod;
|
import org.testng.annotations.BeforeMethod;
|
||||||
|
import org.testng.annotations.Ignore;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -301,20 +302,5 @@ public class ExecuteRulesTests extends RestTest
|
|||||||
assertThat(fileNode).containsAspects(AUDIO_ASPECT);
|
assertThat(fileNode).containsAspects(AUDIO_ASPECT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
//TODO: add test(s) that would cover handling executing broken rule and/or broken rule execution (ACS-3699)
|
||||||
* Try to execute rule with broken action and receive 500.
|
|
||||||
*/
|
|
||||||
@Test(groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.ACTIONS })
|
|
||||||
public void executeRules_brokenActionResultsWith500()
|
|
||||||
{
|
|
||||||
STEP("Update folder rule with broken action");
|
|
||||||
RestActionBodyExecTemplateModel brokenAction = createCustomActionModel("set-property-value", Map.of("aspect-name", AUDIO_ASPECT));
|
|
||||||
childFolderRule.setActions(List.of(brokenAction));
|
|
||||||
restClient.authenticateUser(user).withCoreAPI().usingNode(childFolder).usingDefaultRuleSet().updateRule(childFolderRule.getId(), childFolderRule);
|
|
||||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
|
||||||
|
|
||||||
STEP("Try to execute rule with broken action");
|
|
||||||
restClient.authenticateUser(user).withCoreAPI().usingNode(childFolder).executeRules(createRuleExecutionRequest());
|
|
||||||
restClient.assertStatusCodeIs(HttpStatus.INTERNAL_SERVER_ERROR);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -171,12 +171,10 @@ public class RulesTestsUtils
|
|||||||
Map.of("destination-folder", "fake-folder-node", "assoc-name", "cm:checkout", "assoc-type",
|
Map.of("destination-folder", "fake-folder-node", "assoc-name", "cm:checkout", "assoc-type",
|
||||||
"cm:contains");
|
"cm:contains");
|
||||||
final RestActionBodyExecTemplateModel checkOutAction = createCustomActionModel("check-out", checkOutParams);
|
final RestActionBodyExecTemplateModel checkOutAction = createCustomActionModel("check-out", checkOutParams);
|
||||||
final Map<String, Serializable> scriptParams = Map.of("script-ref", "dummy-script-node-id");
|
|
||||||
final RestActionBodyExecTemplateModel scriptAction = createCustomActionModel("script", scriptParams);
|
|
||||||
// The counter action takes no parameters, so check we can omit the "params" entry.
|
// The counter action takes no parameters, so check we can omit the "params" entry.
|
||||||
final RestActionBodyExecTemplateModel counterAction = createCustomActionModel("counter", null);
|
final RestActionBodyExecTemplateModel counterAction = createCustomActionModel("counter", null);
|
||||||
final RestRuleModel ruleModel = createRuleModelWithDefaultValues();
|
final RestRuleModel ruleModel = createRuleModelWithDefaultValues();
|
||||||
ruleModel.setActions(Arrays.asList(copyAction, checkOutAction, scriptAction, counterAction));
|
ruleModel.setActions(Arrays.asList(copyAction, checkOutAction, counterAction));
|
||||||
|
|
||||||
return ruleModel;
|
return ruleModel;
|
||||||
}
|
}
|
||||||
|
@@ -255,8 +255,8 @@ public class UpdateRulesTests extends RestTest
|
|||||||
.include(IS_SHARED)
|
.include(IS_SHARED)
|
||||||
.updateRule(rule.getId(), rule);
|
.updateRule(rule.getId(), rule);
|
||||||
|
|
||||||
restClient.assertStatusCodeIs(NOT_FOUND);
|
restClient.assertStatusCodeIs(BAD_REQUEST);
|
||||||
restClient.assertLastError().containsSummary(actionDefinitionId);
|
restClient.assertLastError().containsSummary(String.format("Invalid action definition requested %s", actionDefinitionId));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Check we can use the POST response to create the new rule. */
|
/** Check we can use the POST response to create the new rule. */
|
||||||
@@ -472,9 +472,9 @@ public class UpdateRulesTests extends RestTest
|
|||||||
final Map<String, Serializable> copyParams =
|
final Map<String, Serializable> copyParams =
|
||||||
Map.of("destination-folder", "dummy-folder-node", "deep-copy", true);
|
Map.of("destination-folder", "dummy-folder-node", "deep-copy", true);
|
||||||
final RestActionBodyExecTemplateModel copyAction = createCustomActionModel("copy", copyParams);
|
final RestActionBodyExecTemplateModel copyAction = createCustomActionModel("copy", copyParams);
|
||||||
final Map<String, Serializable> scriptParams = Map.of("script-ref", "dummy-script-node-id");
|
final Map<String, Serializable> addAspectParams = Map.of("aspect-name", "cm:taggable");
|
||||||
final RestActionBodyExecTemplateModel scriptAction = createCustomActionModel("script", scriptParams);
|
final RestActionBodyExecTemplateModel addAspectAction = createCustomActionModel("add-features", addAspectParams);
|
||||||
rule.setActions(Arrays.asList(copyAction, scriptAction));
|
rule.setActions(Arrays.asList(copyAction, addAspectAction));
|
||||||
|
|
||||||
final RestRuleModel updatedRule = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
|
final RestRuleModel updatedRule = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
|
||||||
.updateRule(rule.getId(), rule);
|
.updateRule(rule.getId(), rule);
|
||||||
@@ -519,14 +519,18 @@ public class UpdateRulesTests extends RestTest
|
|||||||
STEP("Try to update the rule by adding action with invalid parameter (non-existing namespace in value)");
|
STEP("Try to update the rule by adding action with invalid parameter (non-existing namespace in value)");
|
||||||
final RestActionBodyExecTemplateModel action = new RestActionBodyExecTemplateModel();
|
final RestActionBodyExecTemplateModel action = new RestActionBodyExecTemplateModel();
|
||||||
action.setActionDefinitionId("add-features");
|
action.setActionDefinitionId("add-features");
|
||||||
action.setParams(Map.of("aspect-name", "dummy:dummy"));
|
final String aspectNameParam = "aspect-name";
|
||||||
|
final String paramValue = "dummy:dummy";
|
||||||
|
action.setParams(Map.of(aspectNameParam, paramValue));
|
||||||
rule.setActions(List.of(action));
|
rule.setActions(List.of(action));
|
||||||
|
|
||||||
restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
|
restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
|
||||||
.updateRule(rule.getId(), rule);
|
.updateRule(rule.getId(), rule);
|
||||||
|
|
||||||
restClient.assertStatusCodeIs(INTERNAL_SERVER_ERROR);
|
restClient.assertStatusCodeIs(BAD_REQUEST);
|
||||||
restClient.assertLastError().containsSummary("Namespace prefix dummy is not mapped to a namespace URI");
|
restClient.assertLastError().containsSummary(
|
||||||
|
String.format("Action parameter: %s has invalid value (%s). Look up possible values for constraint name %s",
|
||||||
|
aspectNameParam, paramValue, "ac-aspects"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Check that a normal user cannot create rules that use private actions. */
|
/** Check that a normal user cannot create rules that use private actions. */
|
||||||
|
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* Alfresco Remote API
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2005 - 2017 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.api.actions;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.alfresco.rest.api.Actions;
|
||||||
|
import org.alfresco.rest.api.model.ActionParameterConstraint;
|
||||||
|
import org.alfresco.rest.framework.WebApiDescription;
|
||||||
|
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
|
||||||
|
import org.alfresco.rest.framework.resource.EntityResource;
|
||||||
|
import org.alfresco.rest.framework.resource.actions.interfaces.EntityResourceAction;
|
||||||
|
import org.alfresco.rest.framework.resource.parameters.Parameters;
|
||||||
|
import org.alfresco.service.Experimental;
|
||||||
|
|
||||||
|
@EntityResource(name="action-constraints", title = "Action parameter constraints")
|
||||||
|
@Experimental
|
||||||
|
public class ActionConstraintsEntityResource implements EntityResourceAction.ReadById<ActionParameterConstraint>
|
||||||
|
{
|
||||||
|
private final Actions actions;
|
||||||
|
|
||||||
|
public ActionConstraintsEntityResource(Actions actions)
|
||||||
|
{
|
||||||
|
this.actions = actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
@WebApiDescription(title = "Get single action parameters constraint",
|
||||||
|
description = "Retrieves a single action parameters constraint by constraint name",
|
||||||
|
successStatus = HttpServletResponse.SC_OK)
|
||||||
|
@Experimental
|
||||||
|
@Override
|
||||||
|
public ActionParameterConstraint readById(String constraintName, Parameters parameters) throws EntityNotFoundException
|
||||||
|
{
|
||||||
|
return actions.getActionConstraint(constraintName);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* #%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 <http://www.gnu.org/licenses/>.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.alfresco.rest.api.actions;
|
||||||
|
|
||||||
|
import org.alfresco.rest.api.model.rules.Action;
|
||||||
|
import org.alfresco.service.Experimental;
|
||||||
|
|
||||||
|
@Experimental
|
||||||
|
public interface ActionValidator
|
||||||
|
{
|
||||||
|
void validate(Action action);
|
||||||
|
|
||||||
|
boolean isEnabled();
|
||||||
|
}
|
@@ -453,7 +453,7 @@ public class ActionsImpl implements Actions
|
|||||||
map(this::toShortQName).
|
map(this::toShortQName).
|
||||||
collect(Collectors.toList());
|
collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
private String toShortQName(QName type)
|
private String toShortQName(QName type)
|
||||||
{
|
{
|
||||||
return type.toPrefixString(prefixResolver);
|
return type.toPrefixString(prefixResolver);
|
||||||
|
@@ -32,12 +32,14 @@ import static org.alfresco.repo.action.access.ActionAccessRestriction.ACTION_CON
|
|||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.alfresco.repo.action.ActionImpl;
|
import org.alfresco.repo.action.ActionImpl;
|
||||||
import org.alfresco.repo.action.CompositeActionImpl;
|
import org.alfresco.repo.action.CompositeActionImpl;
|
||||||
|
import org.alfresco.rest.api.actions.ActionValidator;
|
||||||
import org.alfresco.rest.api.impl.rules.ActionParameterConverter;
|
import org.alfresco.rest.api.impl.rules.ActionParameterConverter;
|
||||||
import org.alfresco.rest.api.model.mapper.RestModelMapper;
|
import org.alfresco.rest.api.model.mapper.RestModelMapper;
|
||||||
import org.alfresco.rest.api.model.rules.Action;
|
import org.alfresco.rest.api.model.rules.Action;
|
||||||
@@ -49,10 +51,13 @@ import org.apache.commons.collections.CollectionUtils;
|
|||||||
public class RestRuleActionModelMapper implements RestModelMapper<Action, org.alfresco.service.cmr.action.Action>
|
public class RestRuleActionModelMapper implements RestModelMapper<Action, org.alfresco.service.cmr.action.Action>
|
||||||
{
|
{
|
||||||
private final ActionParameterConverter parameterConverter;
|
private final ActionParameterConverter parameterConverter;
|
||||||
|
private final List<ActionValidator> actionValidators;
|
||||||
|
|
||||||
public RestRuleActionModelMapper(ActionParameterConverter parameterConverter)
|
public RestRuleActionModelMapper(ActionParameterConverter parameterConverter,
|
||||||
|
List<ActionValidator> actionValidators)
|
||||||
{
|
{
|
||||||
this.parameterConverter = parameterConverter;
|
this.parameterConverter = parameterConverter;
|
||||||
|
this.actionValidators = actionValidators;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -104,8 +109,14 @@ public class RestRuleActionModelMapper implements RestModelMapper<Action, org.al
|
|||||||
private org.alfresco.service.cmr.action.Action toServiceAction(Action action)
|
private org.alfresco.service.cmr.action.Action toServiceAction(Action action)
|
||||||
{
|
{
|
||||||
final Map<String, Serializable> params = Optional.ofNullable(action.getParams()).orElse(emptyMap());
|
final Map<String, Serializable> params = Optional.ofNullable(action.getParams()).orElse(emptyMap());
|
||||||
|
validateAction(action);
|
||||||
final Map<String, Serializable> convertedParams =
|
final Map<String, Serializable> convertedParams =
|
||||||
parameterConverter.getConvertedParams(params, action.getActionDefinitionId());
|
parameterConverter.getConvertedParams(params, action.getActionDefinitionId());
|
||||||
return new ActionImpl(null, GUID.generate(), action.getActionDefinitionId(), convertedParams);
|
return new ActionImpl(null, GUID.generate(), action.getActionDefinitionId(), convertedParams);
|
||||||
}
|
}
|
||||||
|
private void validateAction(Action action) {
|
||||||
|
actionValidators.stream()
|
||||||
|
.filter(ActionValidator::isEnabled)
|
||||||
|
.forEach(v -> v.validate(action));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.alfresco.rest.api.impl.validator.actions;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.alfresco.rest.api.Actions;
|
||||||
|
import org.alfresco.rest.api.actions.ActionValidator;
|
||||||
|
import org.alfresco.rest.api.model.ActionDefinition;
|
||||||
|
import org.alfresco.rest.api.model.ActionParameterConstraint;
|
||||||
|
import org.alfresco.rest.api.model.rules.Action;
|
||||||
|
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
|
||||||
|
import org.alfresco.rest.framework.core.exceptions.NotFoundException;
|
||||||
|
import org.alfresco.service.Experimental;
|
||||||
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
import org.apache.commons.collections.MapUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class will validate all action types against action parameters definitions (mandatory parameters, parameter constraints)
|
||||||
|
*/
|
||||||
|
@Experimental
|
||||||
|
public class ActionParameterDefinitionValidator implements ActionValidator
|
||||||
|
{
|
||||||
|
private static final boolean IS_ENABLED = true;
|
||||||
|
static final String INVALID_PARAMETER_VALUE =
|
||||||
|
"Action parameter: %s has invalid value (%s). Look up possible values for constraint name %s";
|
||||||
|
static final String MISSING_PARAMETER = "Missing action's mandatory parameter: %s";
|
||||||
|
static final String MUST_NOT_CONTAIN_PARAMETER = "Action of definition id: %s must not contain parameter of name: %s";
|
||||||
|
static final String PARAMS_SHOULD_NOT_BE_EMPTY =
|
||||||
|
"Action parameters should not be null or empty for this action. See Action Definition for action of: %s";
|
||||||
|
static final String INVALID_ACTION_DEFINITION = "Invalid action definition requested %s";
|
||||||
|
|
||||||
|
private final Actions actions;
|
||||||
|
|
||||||
|
public ActionParameterDefinitionValidator(Actions actions)
|
||||||
|
{
|
||||||
|
this.actions = actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates action against its parameters definitions (mandatory parameters, parameter constraints)
|
||||||
|
*
|
||||||
|
* @param action Action to be validated
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void validate(Action action)
|
||||||
|
{
|
||||||
|
ActionDefinition actionDefinition;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
actionDefinition = actions.getActionDefinitionById(action.getActionDefinitionId());
|
||||||
|
} catch (NotFoundException e) {
|
||||||
|
throw new InvalidArgumentException(String.format(INVALID_ACTION_DEFINITION, action.getActionDefinitionId()));
|
||||||
|
}
|
||||||
|
validateParametersSize(action.getParams(), actionDefinition);
|
||||||
|
final Map<String, Serializable> params = action.getParams();
|
||||||
|
if (MapUtils.isNotEmpty(params))
|
||||||
|
{
|
||||||
|
params.forEach((key, value) -> checkParameterShouldExist(key, actionDefinition));
|
||||||
|
actionDefinition.getParameterDefinitions().forEach(p -> validateParameterDefinitions(p, params));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled()
|
||||||
|
{
|
||||||
|
return IS_ENABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateParametersSize(final Map<String, Serializable> params, final ActionDefinition actionDefinition)
|
||||||
|
{
|
||||||
|
if (CollectionUtils.isNotEmpty(actionDefinition.getParameterDefinitions()) && MapUtils.isEmpty(params))
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException(String.format(PARAMS_SHOULD_NOT_BE_EMPTY, actionDefinition.getName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateParameterDefinitions(final ActionDefinition.ParameterDefinition parameterDefinition,
|
||||||
|
final Map<String, Serializable> params)
|
||||||
|
{
|
||||||
|
final Serializable parameterValue = params.get(parameterDefinition.getName());
|
||||||
|
if (parameterDefinition.isMandatory() && parameterValue == null)
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException(String.format(MISSING_PARAMETER, parameterDefinition.getName()));
|
||||||
|
}
|
||||||
|
if (parameterDefinition.getParameterConstraintName() != null)
|
||||||
|
{
|
||||||
|
final ActionParameterConstraint actionConstraint =
|
||||||
|
actions.getActionConstraint(parameterDefinition.getParameterConstraintName());
|
||||||
|
if (parameterValue != null && actionConstraint.getConstraintValues().stream()
|
||||||
|
.noneMatch(constraintData -> constraintData.getValue().equals(parameterValue.toString())))
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException(String.format(INVALID_PARAMETER_VALUE, parameterDefinition.getName(), parameterValue,
|
||||||
|
actionConstraint.getConstraintName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkParameterShouldExist(final String parameterName, final ActionDefinition actionDefinition)
|
||||||
|
{
|
||||||
|
if (actionDefinition.getParameterDefinitions().stream().noneMatch(pd -> parameterName.equals(pd.getName())))
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException(String.format(MUST_NOT_CONTAIN_PARAMETER, actionDefinition.getName(), parameterName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@@ -588,7 +588,14 @@
|
|||||||
<bean class="org.alfresco.rest.api.actions.ActionParameterConstraintsEntityResource">
|
<bean class="org.alfresco.rest.api.actions.ActionParameterConstraintsEntityResource">
|
||||||
<constructor-arg name="actions" ref="Actions"/>
|
<constructor-arg name="actions" ref="Actions"/>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
<!-- action parameter validators start here -->
|
||||||
|
<bean id="actionParameterConstraintsValidator" class="org.alfresco.rest.api.impl.validator.actions.ActionParameterDefinitionValidator">
|
||||||
|
<constructor-arg name="actions" ref="Actions"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<!-- action parameter validators end here-->
|
||||||
|
|
||||||
<bean id="Downloads" class="org.springframework.aop.framework.ProxyFactoryBean">
|
<bean id="Downloads" class="org.springframework.aop.framework.ProxyFactoryBean">
|
||||||
<property name="proxyInterfaces">
|
<property name="proxyInterfaces">
|
||||||
<value>org.alfresco.rest.api.Downloads</value>
|
<value>org.alfresco.rest.api.Downloads</value>
|
||||||
@@ -965,6 +972,11 @@
|
|||||||
|
|
||||||
<bean id="actionMapper" class="org.alfresco.rest.api.impl.mapper.rules.RestRuleActionModelMapper">
|
<bean id="actionMapper" class="org.alfresco.rest.api.impl.mapper.rules.RestRuleActionModelMapper">
|
||||||
<constructor-arg name="parameterConverter" ref="actionParameterConverter"/>
|
<constructor-arg name="parameterConverter" ref="actionParameterConverter"/>
|
||||||
|
<constructor-arg name="actionValidators">
|
||||||
|
<list>
|
||||||
|
<ref bean="actionParameterConstraintsValidator"/>
|
||||||
|
</list>
|
||||||
|
</constructor-arg>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<bean id="ruleMapper" class="org.alfresco.rest.api.impl.mapper.rules.RestRuleModelMapper">
|
<bean id="ruleMapper" class="org.alfresco.rest.api.impl.mapper.rules.RestRuleModelMapper">
|
||||||
|
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* #%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 <http://www.gnu.org/licenses/>.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.alfresco.rest.api.actions;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.mockito.BDDMockito.given;
|
||||||
|
import static org.mockito.BDDMockito.then;
|
||||||
|
|
||||||
|
import org.alfresco.rest.api.Actions;
|
||||||
|
import org.alfresco.rest.api.model.ActionParameterConstraint;
|
||||||
|
import org.alfresco.rest.framework.resource.parameters.Parameters;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class ActionConstraintsEntityResourceTest
|
||||||
|
{
|
||||||
|
@Mock
|
||||||
|
private Actions actionsMock;
|
||||||
|
@Mock
|
||||||
|
private Parameters parametersMock;
|
||||||
|
|
||||||
|
@InjectMocks
|
||||||
|
private ActionConstraintsEntityResource objectUnderTest;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReadById() {
|
||||||
|
final String name = "name";
|
||||||
|
final ActionParameterConstraint dummyConstraint = new ActionParameterConstraint();
|
||||||
|
given(actionsMock.getActionConstraint(name)).willReturn(dummyConstraint);
|
||||||
|
|
||||||
|
//when
|
||||||
|
ActionParameterConstraint result = objectUnderTest.readById(name, parametersMock);
|
||||||
|
|
||||||
|
then(actionsMock).should().getActionConstraint(name);
|
||||||
|
then(actionsMock).shouldHaveNoMoreInteractions();
|
||||||
|
assertThat(result).isNotNull().usingRecursiveComparison().isEqualTo(dummyConstraint);
|
||||||
|
}
|
||||||
|
}
|
@@ -43,11 +43,14 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.alfresco.repo.action.ActionImpl;
|
import org.alfresco.repo.action.ActionImpl;
|
||||||
|
import org.alfresco.rest.api.actions.ActionValidator;
|
||||||
import org.alfresco.rest.api.impl.rules.ActionParameterConverter;
|
import org.alfresco.rest.api.impl.rules.ActionParameterConverter;
|
||||||
import org.alfresco.rest.api.model.rules.Action;
|
import org.alfresco.rest.api.model.rules.Action;
|
||||||
import org.alfresco.service.Experimental;
|
import org.alfresco.service.Experimental;
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
import org.alfresco.service.cmr.repository.StoreRef;
|
import org.alfresco.service.cmr.repository.StoreRef;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
@@ -65,10 +68,17 @@ public class RestRuleActionModelMapperTest
|
|||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private ActionParameterConverter parameterConverter;
|
private ActionParameterConverter parameterConverter;
|
||||||
|
@Mock
|
||||||
|
private ActionValidator sampleValidatorMock;
|
||||||
|
|
||||||
@InjectMocks
|
|
||||||
private RestRuleActionModelMapper objectUnderTest;
|
private RestRuleActionModelMapper objectUnderTest;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
objectUnderTest = new RestRuleActionModelMapper(parameterConverter, List.of(sampleValidatorMock));
|
||||||
|
given(sampleValidatorMock.isEnabled()).willReturn(true);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testToRestModel()
|
public void testToRestModel()
|
||||||
{
|
{
|
||||||
|
@@ -0,0 +1,217 @@
|
|||||||
|
/*
|
||||||
|
* #%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 <http://www.gnu.org/licenses/>.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.alfresco.rest.api.impl.validator.actions;
|
||||||
|
|
||||||
|
import static org.alfresco.rest.api.impl.validator.actions.ActionParameterDefinitionValidator.MISSING_PARAMETER;
|
||||||
|
import static org.alfresco.rest.api.impl.validator.actions.ActionParameterDefinitionValidator.MUST_NOT_CONTAIN_PARAMETER;
|
||||||
|
import static org.alfresco.rest.api.impl.validator.actions.ActionParameterDefinitionValidator.PARAMS_SHOULD_NOT_BE_EMPTY;
|
||||||
|
import static org.alfresco.service.cmr.dictionary.DataTypeDefinition.BOOLEAN;
|
||||||
|
import static org.alfresco.service.cmr.dictionary.DataTypeDefinition.TEXT;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||||
|
import static org.mockito.BDDMockito.then;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.alfresco.rest.api.Actions;
|
||||||
|
import org.alfresco.rest.api.model.ActionDefinition;
|
||||||
|
import org.alfresco.rest.api.model.rules.Action;
|
||||||
|
import org.alfresco.service.Experimental;
|
||||||
|
import org.alfresco.service.namespace.QName;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.BDDMockito;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
|
@Experimental
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class ActionParameterDefinitionValidatorTest
|
||||||
|
{
|
||||||
|
private static final String MANDATORY_PARAM_KEY = "paramKey";
|
||||||
|
private static final String NON_MANDATORY_PARAM_KEY = "nonMandatoryParamKey";
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private Actions actionsMock;
|
||||||
|
|
||||||
|
@InjectMocks
|
||||||
|
private ActionParameterDefinitionValidator objectUnderTest;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSimpleValidationPasses()
|
||||||
|
{
|
||||||
|
final Action action = new Action();
|
||||||
|
final String actionDefinitionId = "properActionDefinition";
|
||||||
|
action.setActionDefinitionId(actionDefinitionId);
|
||||||
|
action.setParams(Map.of(MANDATORY_PARAM_KEY, "paramValue"));
|
||||||
|
final List<ActionDefinition.ParameterDefinition> parameterDefinitions =
|
||||||
|
List.of(createParameterDefinition(MANDATORY_PARAM_KEY, TEXT, true, null));
|
||||||
|
final ActionDefinition actionDefinition = createActionDefinition(actionDefinitionId, parameterDefinitions);
|
||||||
|
BDDMockito.given(actionsMock.getActionDefinitionById(actionDefinitionId)).willReturn(actionDefinition);
|
||||||
|
|
||||||
|
//when
|
||||||
|
objectUnderTest.validate(action);
|
||||||
|
|
||||||
|
then(actionsMock).should().getActionDefinitionById(actionDefinitionId);
|
||||||
|
then(actionsMock).shouldHaveNoMoreInteractions();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidationPassesWhenNoParametersNeeded()
|
||||||
|
{
|
||||||
|
final Action action = new Action();
|
||||||
|
final String actionDefinitionId = "properActionDefinition";
|
||||||
|
action.setActionDefinitionId(actionDefinitionId);
|
||||||
|
final ActionDefinition actionDefinition = createActionDefinition(actionDefinitionId, null);
|
||||||
|
BDDMockito.given(actionsMock.getActionDefinitionById(actionDefinitionId)).willReturn(actionDefinition);
|
||||||
|
|
||||||
|
//when
|
||||||
|
objectUnderTest.validate(action);
|
||||||
|
|
||||||
|
then(actionsMock).should().getActionDefinitionById(actionDefinitionId);
|
||||||
|
then(actionsMock).shouldHaveNoMoreInteractions();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidationPassesWhenNoMandatoryParameters()
|
||||||
|
{
|
||||||
|
final Action action = new Action();
|
||||||
|
final String actionDefinitionId = "properActionDefinition";
|
||||||
|
action.setActionDefinitionId(actionDefinitionId);
|
||||||
|
action.setParams(Map.of(MANDATORY_PARAM_KEY, "paramValue"));
|
||||||
|
final List<ActionDefinition.ParameterDefinition> parameterDefinitions =
|
||||||
|
List.of(createParameterDefinition(MANDATORY_PARAM_KEY, TEXT, true, null),
|
||||||
|
createParameterDefinition(NON_MANDATORY_PARAM_KEY, BOOLEAN, false, null));
|
||||||
|
final ActionDefinition actionDefinition = createActionDefinition(actionDefinitionId, parameterDefinitions);
|
||||||
|
BDDMockito.given(actionsMock.getActionDefinitionById(actionDefinitionId)).willReturn(actionDefinition);
|
||||||
|
|
||||||
|
//when
|
||||||
|
objectUnderTest.validate(action);
|
||||||
|
|
||||||
|
then(actionsMock).should().getActionDefinitionById(actionDefinitionId);
|
||||||
|
then(actionsMock).shouldHaveNoMoreInteractions();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidationFailsWhenTooManyParameters()
|
||||||
|
{
|
||||||
|
final Action action = new Action();
|
||||||
|
final String actionDefinitionId = "properActionDefinition";
|
||||||
|
action.setActionDefinitionId(actionDefinitionId);
|
||||||
|
action.setParams(Map.of(MANDATORY_PARAM_KEY, "paramValue", NON_MANDATORY_PARAM_KEY, false));
|
||||||
|
final List<ActionDefinition.ParameterDefinition> parameterDefinitions =
|
||||||
|
List.of(createParameterDefinition(MANDATORY_PARAM_KEY, TEXT, true, null));
|
||||||
|
final ActionDefinition actionDefinition = createActionDefinition(actionDefinitionId, parameterDefinitions);
|
||||||
|
BDDMockito.given(actionsMock.getActionDefinitionById(actionDefinitionId)).willReturn(actionDefinition);
|
||||||
|
|
||||||
|
//when
|
||||||
|
assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> objectUnderTest.validate(action))
|
||||||
|
.withMessageContaining(String.format(MUST_NOT_CONTAIN_PARAMETER, actionDefinitionId, NON_MANDATORY_PARAM_KEY));
|
||||||
|
|
||||||
|
then(actionsMock).should().getActionDefinitionById(actionDefinitionId);
|
||||||
|
then(actionsMock).shouldHaveNoMoreInteractions();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidationFailsWhenMissingParameters()
|
||||||
|
{
|
||||||
|
final Action action = new Action();
|
||||||
|
final String actionDefinitionId = "properActionDefinition";
|
||||||
|
action.setActionDefinitionId(actionDefinitionId);
|
||||||
|
final List<ActionDefinition.ParameterDefinition> parameterDefinitions =
|
||||||
|
List.of(createParameterDefinition(MANDATORY_PARAM_KEY, TEXT, true, null));
|
||||||
|
final ActionDefinition actionDefinition = createActionDefinition(actionDefinitionId, parameterDefinitions);
|
||||||
|
BDDMockito.given(actionsMock.getActionDefinitionById(actionDefinitionId)).willReturn(actionDefinition);
|
||||||
|
|
||||||
|
//when
|
||||||
|
assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> objectUnderTest.validate(action))
|
||||||
|
.withMessageContaining(String.format(PARAMS_SHOULD_NOT_BE_EMPTY, actionDefinitionId));
|
||||||
|
|
||||||
|
then(actionsMock).should().getActionDefinitionById(actionDefinitionId);
|
||||||
|
then(actionsMock).shouldHaveNoMoreInteractions();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidationFailsWhenMissingParameterValue()
|
||||||
|
{
|
||||||
|
final Action action = new Action();
|
||||||
|
final String actionDefinitionId = "properActionDefinition";
|
||||||
|
action.setActionDefinitionId(actionDefinitionId);
|
||||||
|
final Map<String, java.io.Serializable> params = new HashMap<>();
|
||||||
|
params.put(MANDATORY_PARAM_KEY, null);
|
||||||
|
action.setParams(params);
|
||||||
|
final List<ActionDefinition.ParameterDefinition> parameterDefinitions =
|
||||||
|
List.of(createParameterDefinition(MANDATORY_PARAM_KEY, TEXT, true, null));
|
||||||
|
final ActionDefinition actionDefinition = createActionDefinition(actionDefinitionId, parameterDefinitions);
|
||||||
|
BDDMockito.given(actionsMock.getActionDefinitionById(actionDefinitionId)).willReturn(actionDefinition);
|
||||||
|
|
||||||
|
//when
|
||||||
|
assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> objectUnderTest.validate(action))
|
||||||
|
.withMessageContaining(String.format(MISSING_PARAMETER, MANDATORY_PARAM_KEY));
|
||||||
|
|
||||||
|
then(actionsMock).should().getActionDefinitionById(actionDefinitionId);
|
||||||
|
then(actionsMock).shouldHaveNoMoreInteractions();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidationFailsWhenMandatoryParameterIsMissing()
|
||||||
|
{
|
||||||
|
final Action action = new Action();
|
||||||
|
final String actionDefinitionId = "properActionDefinition";
|
||||||
|
action.setActionDefinitionId(actionDefinitionId);
|
||||||
|
action.setParams(Map.of(NON_MANDATORY_PARAM_KEY, true));
|
||||||
|
final List<ActionDefinition.ParameterDefinition> parameterDefinitions =
|
||||||
|
List.of(createParameterDefinition(MANDATORY_PARAM_KEY, TEXT, true, null),
|
||||||
|
createParameterDefinition(NON_MANDATORY_PARAM_KEY, BOOLEAN, false, null));
|
||||||
|
final ActionDefinition actionDefinition = createActionDefinition(actionDefinitionId, parameterDefinitions);
|
||||||
|
BDDMockito.given(actionsMock.getActionDefinitionById(actionDefinitionId)).willReturn(actionDefinition);
|
||||||
|
|
||||||
|
//when
|
||||||
|
assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> objectUnderTest.validate(action))
|
||||||
|
.withMessageContaining(String.format(MISSING_PARAMETER, MANDATORY_PARAM_KEY));
|
||||||
|
|
||||||
|
then(actionsMock).should().getActionDefinitionById(actionDefinitionId);
|
||||||
|
then(actionsMock).shouldHaveNoMoreInteractions();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ActionDefinition createActionDefinition(final String actionDefinitionId,
|
||||||
|
List<ActionDefinition.ParameterDefinition> parameterDefinitions)
|
||||||
|
{
|
||||||
|
return new ActionDefinition(actionDefinitionId, actionDefinitionId, "title", "description", Collections.emptyList(), false, false,
|
||||||
|
parameterDefinitions);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ActionDefinition.ParameterDefinition createParameterDefinition(final String name, final QName qName, final boolean mandatory,
|
||||||
|
final String constraint)
|
||||||
|
{
|
||||||
|
return new ActionDefinition.ParameterDefinition(name, qName.toPrefixString(), false, mandatory, "label", constraint);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Reference in New Issue
Block a user