From: franciscovila Date: Fri, 7 Oct 2022 10:52:30 +0000 (+0100) Subject: Constraint validation - Node Template Interfaces X-Git-Tag: 1.12.0~7 X-Git-Url: https://gerrit.onap.org/r/gitweb?p=sdc.git;a=commitdiff_plain;h=5517cab153e2efce298f1da98fd4b41b483cb57f Constraint validation - Node Template Interfaces Validate constraints in node template interfaces Issue-ID: SDC-4207 Signed-off-by: franciscovila Change-Id: Ibe4a55342067942a2a29f540c896ecc39811220f --- diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ArtifactTypeBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ArtifactTypeBusinessLogic.java new file mode 100644 index 0000000000..126571741f --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ArtifactTypeBusinessLogic.java @@ -0,0 +1,71 @@ +/* + * - + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ +package org.openecomp.sdc.be.components.impl; + +import fj.data.Either; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.openecomp.sdc.be.model.ArtifactTypeDefinition; +import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ArtifactsOperations; +import org.openecomp.sdc.be.model.jsonjanusgraph.operations.InterfaceOperation; +import org.openecomp.sdc.be.model.operations.api.IElementOperation; +import org.openecomp.sdc.be.model.operations.api.IGroupInstanceOperation; +import org.openecomp.sdc.be.model.operations.api.IGroupOperation; +import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.operations.impl.ArtifactTypeOperation; +import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation; +import org.openecomp.sdc.common.log.wrappers.Logger; +import org.springframework.beans.factory.annotation.Autowired; + +@org.springframework.stereotype.Component("artifactTypeBusinessLogic") +public class ArtifactTypeBusinessLogic extends BaseBusinessLogic { + + private static final Logger log = Logger.getLogger(ArtifactTypeBusinessLogic.class.getName()); + + private final ArtifactTypeOperation artifactTypeOperation; + + @Autowired + public ArtifactTypeBusinessLogic(IElementOperation elementDao, IGroupOperation groupOperation, + IGroupInstanceOperation groupInstanceOperation, IGroupTypeOperation groupTypeOperation, + InterfaceOperation interfaceOperation, InterfaceLifecycleOperation interfaceLifecycleTypeOperation, + ArtifactsOperations artifactToscaOperation, + ArtifactTypeOperation artifactTypeOperation) { + super(elementDao, groupOperation, groupInstanceOperation, groupTypeOperation, interfaceOperation, interfaceLifecycleTypeOperation, + artifactToscaOperation); + this.artifactTypeOperation = artifactTypeOperation; + } + + public ArtifactTypeDefinition getArtifactTypeByUid(String uniqueId) { + Either eitherArtifact = artifactTypeOperation.getArtifactTypeByUid(uniqueId); + if (eitherArtifact == null || eitherArtifact.isRight()) { + return null; + } + return eitherArtifact.left().value(); + } + + public Map getAllToscaArtifactTypes(final String modelName) { + if (StringUtils.isNotEmpty(modelName)) { + artifactTypeOperation.validateModel(modelName); + } + return artifactTypeOperation.getAllArtifactTypes(modelName); + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ArtifactsBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ArtifactsBusinessLogic.java index eb3561afc0..a978154224 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ArtifactsBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ArtifactsBusinessLogic.java @@ -4261,13 +4261,6 @@ public class ArtifactsBusinessLogic extends BaseBusinessLogic { return ConfigurationManager.getConfigurationManager().getConfiguration().getArtifacts(); } - public Map getAllToscaArtifacts(final String modelName) { - if (StringUtils.isNotEmpty(modelName)) { - artifactTypeOperation.validateModel(modelName); - } - return artifactTypeOperation.getAllArtifactTypes(modelName); - } - public enum ArtifactOperationEnum { CREATE, UPDATE, DELETE, DOWNLOAD, LINK; diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInterfaceOperationBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInterfaceOperationBusinessLogic.java index eb8b35ec60..d194944786 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInterfaceOperationBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInterfaceOperationBusinessLogic.java @@ -20,26 +20,39 @@ */ package org.openecomp.sdc.be.components.impl; +import com.google.common.reflect.TypeToken; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import fj.data.Either; +import java.lang.reflect.Type; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.UUID; +import java.util.stream.Collectors; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; import org.openecomp.sdc.be.components.impl.exceptions.BusinessLogicException; import org.openecomp.sdc.be.components.validation.ComponentValidations; import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datamodel.utils.PropertyValueConstraintValidationUtil; import org.openecomp.sdc.be.datatypes.elements.ArtifactDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.ListDataDefinition; import org.openecomp.sdc.be.datatypes.elements.OperationDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition; +import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.model.ArtifactTypeDefinition; import org.openecomp.sdc.be.model.Component; import org.openecomp.sdc.be.model.ComponentInstance; import org.openecomp.sdc.be.model.ComponentInstanceInterface; import org.openecomp.sdc.be.model.ComponentParametersView; import org.openecomp.sdc.be.model.InterfaceDefinition; +import org.openecomp.sdc.be.model.PropertyConstraint; +import org.openecomp.sdc.be.model.PropertyDefinition; import org.openecomp.sdc.be.model.User; import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ArtifactsOperations; import org.openecomp.sdc.be.model.jsonjanusgraph.operations.InterfaceOperation; @@ -49,6 +62,8 @@ import org.openecomp.sdc.be.model.operations.api.IGroupOperation; import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation; +import org.openecomp.sdc.be.model.operations.impl.PropertyOperation; +import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder; import org.openecomp.sdc.be.user.Role; import org.openecomp.sdc.common.datastructure.Wrapper; import org.openecomp.sdc.exception.ResponseFormat; @@ -60,7 +75,13 @@ import org.springframework.beans.factory.annotation.Autowired; public class ComponentInterfaceOperationBusinessLogic extends BaseBusinessLogic { private static final Logger LOGGER = LoggerFactory.getLogger(ComponentInterfaceOperationBusinessLogic.class); + private static final String UPDATE_INTERFACE_OPERATION_ON_COMPONENT_INSTANCE = + "Update Interface Operation on Component instance"; + private static final String EXCEPTION_OCCURRED_WHEN_UPDATING_COMPONENT_INSTANCE_INTERFACES = + "Exception occurred when updating Component Instance Interfaces {}"; private final ComponentValidations componentValidations; + private final PropertyBusinessLogic propertyBusinessLogic; + private final ArtifactTypeBusinessLogic artifactTypeBusinessLogic; @Autowired public ComponentInterfaceOperationBusinessLogic(final IElementOperation elementDao, final IGroupOperation groupOperation, @@ -68,10 +89,14 @@ public class ComponentInterfaceOperationBusinessLogic extends BaseBusinessLogic final IGroupTypeOperation groupTypeOperation, final InterfaceOperation interfaceOperation, final InterfaceLifecycleOperation interfaceLifecycleTypeOperation, final ArtifactsOperations artifactToscaOperation, - final ComponentValidations componentValidations) { + final ComponentValidations componentValidations, + final PropertyBusinessLogic propertyBusinessLogic, + final ArtifactTypeBusinessLogic artifactTypeBusinessLogic) { super(elementDao, groupOperation, groupInstanceOperation, groupTypeOperation, interfaceOperation, interfaceLifecycleTypeOperation, artifactToscaOperation); this.componentValidations = componentValidations; + this.propertyBusinessLogic = propertyBusinessLogic; + this.artifactTypeBusinessLogic = artifactTypeBusinessLogic; } public Optional updateComponentInstanceInterfaceOperation(final String componentId, final String componentInstanceId, @@ -119,19 +144,33 @@ public class ComponentInterfaceOperationBusinessLogic extends BaseBusinessLogic errorWrapper.setInnerElement(responseFormat); return Optional.empty(); } + + final String model = propertyBusinessLogic.getComponentModelByComponentId(componentId); + PropertyValueConstraintValidationUtil constraintValidatorUtil = new PropertyValueConstraintValidationUtil(); + Either constraintValidatorResponse = + validateOperationInputConstraints(updatedOperationDataDefinition, constraintValidatorUtil, model); + if (!isConstraintsValidationSucceed(constraintValidatorResponse, errorWrapper, updatedOperationDataDefinition)) { + return Optional.empty(); + } + constraintValidatorResponse = validateOperationArtifactPropertyConstraints( + updatedOperationDataDefinition, constraintValidatorUtil, model); + if (!isConstraintsValidationSucceed(constraintValidatorResponse, errorWrapper, updatedOperationDataDefinition)) { + return Optional.empty(); + } + updateOperationDefinitionImplementation(updatedOperationDataDefinition); optionalComponentInstanceInterface.get().getOperations().replace(updatedOperationDataDefinition.getName(), updatedOperationDataDefinition); boolean wasLocked = false; try { if (shouldLock) { - lockComponent(componentId, component, "Update Interface Operation on Component instance"); + lockComponent(componentId, component, UPDATE_INTERFACE_OPERATION_ON_COMPONENT_INSTANCE); wasLocked = true; } final StorageOperationStatus status = toscaOperationFacade.updateComponentInstanceInterfaces(component, componentInstanceId); if (status != StorageOperationStatus.OK) { janusGraphDao.rollback(); responseFormat = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR); - LOGGER.error("Exception occurred when updating Component Instance Interfaces {}", responseFormat); + LOGGER.error(EXCEPTION_OCCURRED_WHEN_UPDATING_COMPONENT_INSTANCE_INTERFACES, responseFormat); errorWrapper.setInnerElement(responseFormat); return Optional.empty(); } @@ -165,6 +204,34 @@ public class ComponentInterfaceOperationBusinessLogic extends BaseBusinessLogic return componentInstanceOptional; } + private Either validateOperationInputConstraints ( + OperationDataDefinition operationDataDefinition, PropertyValueConstraintValidationUtil constraintValidatorUtil, String model) { + return constraintValidatorUtil + .validatePropertyConstraints(convertOperationInputsToPropertyDefinitions(operationDataDefinition), applicationDataTypeCache, + model); + } + + private Either validateOperationArtifactPropertyConstraints ( + OperationDataDefinition operationDataDefinition, PropertyValueConstraintValidationUtil constraintValidatorUtil, String model) { + return constraintValidatorUtil + .validatePropertyConstraints(convertOperationArtifactPropsToPropertyDefinitions(operationDataDefinition, model), applicationDataTypeCache, + model); + } + + private boolean isConstraintsValidationSucceed(Either constraintValidatorResponse, + Wrapper errorWrapper, + OperationDataDefinition updatedOperationDataDefinition) { + if (constraintValidatorResponse.isRight()) { + ResponseFormat responseFormat = constraintValidatorResponse.right().value(); + LOGGER.error("Failed constraints validation on inputs for interface operation: {} - {}", + updatedOperationDataDefinition.getName(), + constraintValidatorResponse.right().value()); + errorWrapper.setInnerElement(responseFormat); + return false; + } + return true; + } + public Optional updateResourceInterfaceOperation(final String componentId, final String user, final InterfaceDefinition interfaceDefinition, @@ -209,14 +276,14 @@ public class ComponentInterfaceOperationBusinessLogic extends BaseBusinessLogic boolean wasLocked = false; try { if (shouldLock) { - lockComponent(componentId, component, "Update Interface Operation on Component instance"); + lockComponent(componentId, component, UPDATE_INTERFACE_OPERATION_ON_COMPONENT_INSTANCE); wasLocked = true; } final StorageOperationStatus status = toscaOperationFacade.updateComponentInterfaces(component, interfaceDefinitionType); if (status != StorageOperationStatus.OK) { janusGraphDao.rollback(); responseFormat = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR); - LOGGER.error("Exception occurred when updating Component Instance Interfaces {}", responseFormat); + LOGGER.error(EXCEPTION_OCCURRED_WHEN_UPDATING_COMPONENT_INSTANCE_INTERFACES, responseFormat); errorWrapper.setInnerElement(responseFormat); return Optional.empty(); } @@ -287,7 +354,7 @@ public class ComponentInterfaceOperationBusinessLogic extends BaseBusinessLogic boolean wasLocked = false; try { if (shouldLock) { - lockComponent(componentId, component, "Update Interface Operation on Component instance"); + lockComponent(componentId, component, UPDATE_INTERFACE_OPERATION_ON_COMPONENT_INSTANCE); wasLocked = true; } final Either operationStatusEither = @@ -295,7 +362,7 @@ public class ComponentInterfaceOperationBusinessLogic extends BaseBusinessLogic if (operationStatusEither.isRight()) { janusGraphDao.rollback(); responseFormat = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR); - LOGGER.error("Exception occurred when updating Component Instance Interfaces {}", responseFormat); + LOGGER.error(EXCEPTION_OCCURRED_WHEN_UPDATING_COMPONENT_INSTANCE_INTERFACES, responseFormat); errorWrapper.setInnerElement(responseFormat); return Optional.empty(); } @@ -329,4 +396,61 @@ public class ComponentInterfaceOperationBusinessLogic extends BaseBusinessLogic artifactInfo.setArtifactName(String.format("'%s'", updatedOperationDataDefinition.getImplementation().getArtifactName())); updatedOperationDataDefinition.setImplementation(artifactInfo); } + + private List convertOperationInputsToPropertyDefinitions(final OperationDataDefinition operationDataDefinition) { + List propertyDefinitions = new ArrayList<>(); + ListDataDefinition inputsDefinitionListData = operationDataDefinition.getInputs(); + if (null != inputsDefinitionListData && !inputsDefinitionListData.isEmpty()) { + List inputDefinitionList = + inputsDefinitionListData.getListToscaDataDefinition(); + for (OperationInputDefinition operationInputDefinition : inputDefinitionList) { + PropertyDefinition propertyDefinition = new PropertyDefinition(); + propertyDefinition.setValue(operationInputDefinition.getValue()); + propertyDefinition.setType(operationInputDefinition.getType()); + propertyDefinition.setName(operationInputDefinition.getName()); + propertyDefinition.setDefaultValue(operationInputDefinition.getDefaultValue()); + propertyDefinition.setInputPath(operationInputDefinition.getInputPath()); + propertyDefinitions.add(propertyDefinition); + } + } + return propertyDefinitions; + } + + private List convertOperationArtifactPropsToPropertyDefinitions(final OperationDataDefinition operationDataDefinition, + final String model) { + List artifactPropertiesToValidateCollection = new ArrayList<>(); + final ArtifactDataDefinition artifactDataDefinition = operationDataDefinition.getImplementation(); + if (null != artifactDataDefinition) { + final String artifactType = artifactDataDefinition.getArtifactType(); + final String uniqueId = UniqueIdBuilder.buildArtifactTypeUid(model, artifactType); + ArtifactTypeDefinition retrievedArtifact = artifactTypeBusinessLogic.getArtifactTypeByUid(uniqueId); + if (retrievedArtifact != null) { + List artifactPropertiesList = artifactDataDefinition.getProperties(); + if (null != artifactPropertiesList && !artifactPropertiesList.isEmpty()) { + for (PropertyDataDefinition propertyDataDefinition : artifactPropertiesList) { + PropertyDefinition propertyDefinition = new PropertyDefinition(); + propertyDefinition.setConstraints(deserializePropertyConstraints(propertyDataDefinition.getPropertyConstraints())); + propertyDefinition.setValue(propertyDataDefinition.getValue()); + propertyDefinition.setType(propertyDataDefinition.getType()); + propertyDefinition.setName(propertyDataDefinition.getName()); + propertyDefinition.setDefaultValue(propertyDataDefinition.getDefaultValue()); + propertyDefinition.setInputPath(propertyDataDefinition.getInputPath()); + artifactPropertiesToValidateCollection.add(propertyDefinition); + } + } + } + } + return artifactPropertiesToValidateCollection; + } + + private List deserializePropertyConstraints(List constraints) { + if (CollectionUtils.isNotEmpty(constraints)) { + Type constraintType = new TypeToken() { + }.getType(); + Gson gson = new GsonBuilder().registerTypeAdapter(constraintType, new PropertyOperation.PropertyConstraintDeserialiser()).create(); + return constraints.stream().map(c -> (PropertyConstraint) gson.fromJson(c, constraintType)).collect( + Collectors.toList()); + } + return null; + } } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/datamodel/utils/PropertyValueConstraintValidationUtil.java b/catalog-be/src/main/java/org/openecomp/sdc/be/datamodel/utils/PropertyValueConstraintValidationUtil.java index 4b8d88fa79..37b86db3cf 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/datamodel/utils/PropertyValueConstraintValidationUtil.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/datamodel/utils/PropertyValueConstraintValidationUtil.java @@ -104,13 +104,15 @@ public class PropertyValueConstraintValidationUtil { propertyDefinition = getPropertyDefinitionObjectFromInputs(propertyDefinition); } if (propertyDefinition != null) { + List propertyConstraints = + dataTypeDefinitionCache.get(propertyDefinition.getType()).safeGetConstraints(); if (ToscaType.isPrimitiveType(propertyDefinition.getType())) { propertyDefinition.setConstraints(org.openecomp.sdc.be.dao.utils.CollectionUtils.merge(propertyDefinition.safeGetConstraints(), - dataTypeDefinitionCache.get(propertyDefinition.getType()).safeGetConstraints())); + propertyConstraints.isEmpty() ? new ArrayList<>() : propertyConstraints)); evaluateConstraintsOnProperty(propertyDefinition); } else if (ToscaType.isCollectionType(propertyDefinition.getType())) { propertyDefinition.setConstraints(org.openecomp.sdc.be.dao.utils.CollectionUtils.merge(propertyDefinition.safeGetConstraints(), - dataTypeDefinitionCache.get(propertyDefinition.getType()).safeGetConstraints())); + propertyConstraints.isEmpty() ? new ArrayList<>() : propertyConstraints)); evaluateConstraintsOnProperty(propertyDefinition); evaluateCollectionTypeProperties(propertyDefinition); } else { diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/TypesFetchServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/TypesFetchServlet.java index 953fcda1bf..7709721e61 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/TypesFetchServlet.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/TypesFetchServlet.java @@ -45,6 +45,7 @@ import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.apache.commons.collections4.ListUtils; +import org.openecomp.sdc.be.components.impl.ArtifactTypeBusinessLogic; import org.openecomp.sdc.be.components.impl.ArtifactsBusinessLogic; import org.openecomp.sdc.be.components.impl.CapabilitiesBusinessLogic; import org.openecomp.sdc.be.components.impl.ComponentBusinessLogic; @@ -91,7 +92,7 @@ public class TypesFetchServlet extends AbstractValidationsServlet { private final CapabilitiesBusinessLogic capabilitiesBusinessLogic; private final InterfaceOperationBusinessLogic interfaceOperationBusinessLogic; private final ResourceBusinessLogic resourceBusinessLogic; - private final ArtifactsBusinessLogic artifactsBusinessLogic; + private final ArtifactTypeBusinessLogic artifactTypeBusinessLogic; @Inject public TypesFetchServlet( @@ -103,7 +104,7 @@ public class TypesFetchServlet extends AbstractValidationsServlet { CapabilitiesBusinessLogic capabilitiesBusinessLogic, InterfaceOperationBusinessLogic interfaceOperationBusinessLogic, ResourceBusinessLogic resourceBusinessLogic, - ArtifactsBusinessLogic artifactsBusinessLogic + ArtifactTypeBusinessLogic artifactTypeBusinessLogic ) { super( componentInstanceBL, @@ -115,7 +116,7 @@ public class TypesFetchServlet extends AbstractValidationsServlet { this.capabilitiesBusinessLogic = capabilitiesBusinessLogic; this.interfaceOperationBusinessLogic = interfaceOperationBusinessLogic; this.resourceBusinessLogic = resourceBusinessLogic; - this.artifactsBusinessLogic = artifactsBusinessLogic; + this.artifactTypeBusinessLogic = artifactTypeBusinessLogic; } @GET @@ -338,7 +339,7 @@ public class TypesFetchServlet extends AbstractValidationsServlet { public Response getAllToscaArtifactTypes(@Parameter(description = "Model name") @QueryParam("model") String model, @Context final HttpServletRequest request, @HeaderParam(Constants.USER_ID_HEADER) String creator) { try { - return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), artifactsBusinessLogic.getAllToscaArtifacts(model)); + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), artifactTypeBusinessLogic.getAllToscaArtifactTypes(model)); } catch (final BusinessException e) { throw e; } catch (final Exception e) { diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ComponentInterfaceOperationBusinessLogicTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ComponentInterfaceOperationBusinessLogicTest.java index 6018207cb7..b3f6024a9b 100644 --- a/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ComponentInterfaceOperationBusinessLogicTest.java +++ b/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ComponentInterfaceOperationBusinessLogicTest.java @@ -20,11 +20,13 @@ package org.openecomp.sdc.be.components.impl; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; import fj.data.Either; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -41,28 +43,39 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.openecomp.sdc.be.components.impl.exceptions.BusinessLogicException; import org.openecomp.sdc.be.components.validation.ComponentValidations; import org.openecomp.sdc.be.components.validation.UserValidations; +import org.openecomp.sdc.be.dao.janusgraph.JanusGraphDao; import org.openecomp.sdc.be.dao.janusgraph.JanusGraphGenericDao; import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus; -import org.openecomp.sdc.be.dao.janusgraph.JanusGraphDao; import org.openecomp.sdc.be.datatypes.elements.ArtifactDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.ListDataDefinition; import org.openecomp.sdc.be.datatypes.elements.OperationDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition; +import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum; import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.model.ArtifactTypeDefinition; import org.openecomp.sdc.be.model.Component; import org.openecomp.sdc.be.model.ComponentInstance; import org.openecomp.sdc.be.model.ComponentInstanceInterface; import org.openecomp.sdc.be.model.ComponentParametersView; +import org.openecomp.sdc.be.model.DataTypeDefinition; import org.openecomp.sdc.be.model.InterfaceDefinition; +import org.openecomp.sdc.be.model.PropertyConstraint; +import org.openecomp.sdc.be.model.PropertyDefinition; import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.cache.ApplicationDataTypeCache; import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ToscaOperationFacade; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.be.model.operations.impl.GraphLockOperation; +import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder; +import org.openecomp.sdc.be.model.tosca.constraints.ValidValuesConstraint; import org.openecomp.sdc.common.datastructure.Wrapper; +import org.openecomp.sdc.exception.ResponseFormat; @ExtendWith(MockitoExtension.class) -public class ComponentInterfaceOperationBusinessLogicTest extends BaseBusinessLogicMock { +class ComponentInterfaceOperationBusinessLogicTest extends BaseBusinessLogicMock { @InjectMocks private ComponentInterfaceOperationBusinessLogic componentInterfaceOperationBusinessLogic; @@ -81,6 +94,12 @@ public class ComponentInterfaceOperationBusinessLogicTest extends BaseBusinessLo private UserValidations userValidations; @Mock private ComponentValidations componentValidations; + @Mock + private PropertyBusinessLogic propertyBusinessLogic; + @Mock + private ApplicationDataTypeCache applicationDataTypeCache; + @Mock + private ArtifactTypeBusinessLogic artifactTypeBusinessLogic; private Component component; private ComponentInstance componentInstance; @@ -92,19 +111,19 @@ public class ComponentInterfaceOperationBusinessLogicTest extends BaseBusinessLo componentInterfaceOperationBusinessLogic = new ComponentInterfaceOperationBusinessLogic(elementDao, groupOperation, groupInstanceOperation, groupTypeOperation, interfaceOperation, interfaceLifecycleTypeOperation, artifactToscaOperation, - componentValidations); + componentValidations, propertyBusinessLogic, artifactTypeBusinessLogic); componentInterfaceOperationBusinessLogic.setToscaOperationFacade(toscaOperationFacade); componentInterfaceOperationBusinessLogic.setGraphLockOperation(graphLockOperation); componentInterfaceOperationBusinessLogic.setComponentsUtils(componentsUtils); componentInterfaceOperationBusinessLogic.setUserValidations(userValidations); componentInterfaceOperationBusinessLogic.setJanusGraphGenericDao(janusGraphGenericDao); componentInterfaceOperationBusinessLogic.setJanusGraphDao(janusGraphDao); - + componentInterfaceOperationBusinessLogic.setApplicationDataTypeCache(applicationDataTypeCache); initComponentData(); } @Test - public void updateSubstitutionFilterTest() throws BusinessLogicException { + void updateComponentInstanceInterfaceOperationTest() throws BusinessLogicException { final String componentId = component.getUniqueId(); final String componentInstanceId = componentInstance.getUniqueId(); final InterfaceDefinition interfaceDefinition = new InterfaceDefinition(); @@ -141,6 +160,7 @@ public class ComponentInterfaceOperationBusinessLogicTest extends BaseBusinessLo when(janusGraphDao.commit()).thenReturn(JanusGraphOperationStatus.OK); when(graphLockOperation.unlockComponent(componentId, NodeTypeEnum.Service)) .thenReturn(StorageOperationStatus.OK); + when(applicationDataTypeCache.getAll(null)).thenReturn(Either.left(new HashMap<>())); final Optional result = componentInterfaceOperationBusinessLogic .updateComponentInstanceInterfaceOperation(componentId, componentInstanceId, interfaceDefinition, @@ -148,7 +168,257 @@ public class ComponentInterfaceOperationBusinessLogicTest extends BaseBusinessLo assertThat(result).isPresent(); } - public void initComponentData() { + @Test + void valueForInputFailsConstraintsValidation() throws BusinessLogicException { + final String inputType = "myType"; + final String componentId = component.getUniqueId(); + final String componentInstanceId = componentInstance.getUniqueId(); + final InterfaceDefinition interfaceDefinition = new InterfaceDefinition(); + interfaceDefinition.setUniqueId(UUID.randomUUID().toString()); + interfaceDefinition.setType("tosca.interfaces.node.lifecycle.Standard"); + final Map operations = new HashMap<>(); + final OperationDataDefinition operationDataDefinition = new OperationDataDefinition(); + operationDataDefinition.setUniqueId(UUID.randomUUID().toString()); + final ArtifactDataDefinition artifactDataDefinition = new ArtifactDataDefinition(); + final ListDataDefinition inputsDefinitionListData = new ListDataDefinition<>(); + OperationInputDefinition input1 = new OperationInputDefinition(); + input1.setName("input_1"); + input1.setType(inputType); + input1.setValue("{\"input_range\": \"invalid\"}"); + inputsDefinitionListData.add(input1); + artifactDataDefinition.setArtifactName("EO Implementation info"); + operationDataDefinition.setImplementation(artifactDataDefinition); + operationDataDefinition.setInputs(inputsDefinitionListData); + operations.put("configure", operationDataDefinition); + interfaceDefinition.setOperations(operations ); + + DataTypeDefinition myType = new DataTypeDefinition(); + myType.setName(inputType); + PropertyDefinition input_range = new PropertyDefinition(); + input_range.setName("input_range"); + input_range.setType("string"); + PropertyConstraint constraint1 = new ValidValuesConstraint(Arrays.asList("value1", "value2", "value3")); + input_range.setConstraints(List.of(constraint1)); + myType.setProperties(List.of(input_range)); + Map dataTypes = Collections.singletonMap(myType.getName(), myType); + Wrapper errorWrapper = new Wrapper<>(); + + final ComponentInstanceInterface componentInstanceInterface = + new ComponentInstanceInterface("interfaceId", interfaceDefinition); + Map> componentInstancesInterfacesMap = new HashMap<>(); + componentInstancesInterfacesMap.put(componentInstanceId, Collections.singletonList(componentInstanceInterface)); + component.setComponentInstancesInterfaces(componentInstancesInterfacesMap); + componentInstance.setInterfaces( + (Map) new HashMap<>().put(componentInstanceId, interfaceDefinition)); + component.setComponentInstances(Collections.singletonList(componentInstance)); + + when(toscaOperationFacade.getToscaElement(componentId)).thenReturn(Either.left(component)); + when(componentValidations.getComponentInstance(component, componentInstanceId)) + .thenReturn(Optional.of(componentInstance)); + when(applicationDataTypeCache.getAll(null)).thenReturn(Either.left(dataTypes)); + + final Optional result = componentInterfaceOperationBusinessLogic + .updateComponentInstanceInterfaceOperation(componentId, componentInstanceId, interfaceDefinition, + ComponentTypeEnum.SERVICE, errorWrapper, false); + assertThat(result).isNotPresent(); + assertTrue(errorWrapper.getInnerElement().getStatus() == 400); + assertTrue(errorWrapper.getInnerElement().getRequestError().getRequestError().getServiceException().getText() + .contains("Error: Invalid property values provided")); + } + + @Test + void valueForInputSucceedsConstraintsValidation() throws BusinessLogicException { + final String inputType = "myType"; + final String componentId = component.getUniqueId(); + final String componentInstanceId = componentInstance.getUniqueId(); + final InterfaceDefinition interfaceDefinition = new InterfaceDefinition(); + interfaceDefinition.setUniqueId(UUID.randomUUID().toString()); + interfaceDefinition.setType("tosca.interfaces.node.lifecycle.Standard"); + final Map operations = new HashMap<>(); + final OperationDataDefinition operationDataDefinition = new OperationDataDefinition(); + operationDataDefinition.setUniqueId(UUID.randomUUID().toString()); + final ArtifactDataDefinition artifactDataDefinition = new ArtifactDataDefinition(); + final ListDataDefinition inputsDefinitionListData = new ListDataDefinition<>(); + OperationInputDefinition input1 = new OperationInputDefinition(); + input1.setName("input_1"); + input1.setType(inputType); + input1.setValue("{\"input_range\": \"value1\"}"); + inputsDefinitionListData.add(input1); + artifactDataDefinition.setArtifactName("EO Implementation info"); + operationDataDefinition.setImplementation(artifactDataDefinition); + operationDataDefinition.setInputs(inputsDefinitionListData); + operations.put("configure", operationDataDefinition); + interfaceDefinition.setOperations(operations ); + + DataTypeDefinition myType = new DataTypeDefinition(); + myType.setName(inputType); + PropertyDefinition input_range = new PropertyDefinition(); + input_range.setName("input_range"); + input_range.setType("string"); + PropertyConstraint constraint1 = new ValidValuesConstraint(Arrays.asList("value1", "value2", "value3")); + input_range.setConstraints(List.of(constraint1)); + myType.setProperties(List.of(input_range)); + Map dataTypes = Collections.singletonMap(myType.getName(), myType); + Wrapper errorWrapper = new Wrapper<>(); + + final ComponentInstanceInterface componentInstanceInterface = + new ComponentInstanceInterface("interfaceId", interfaceDefinition); + Map> componentInstancesInterfacesMap = new HashMap<>(); + componentInstancesInterfacesMap.put(componentInstanceId, Collections.singletonList(componentInstanceInterface)); + component.setComponentInstancesInterfaces(componentInstancesInterfacesMap); + componentInstance.setInterfaces( + (Map) new HashMap<>().put(componentInstanceId, interfaceDefinition)); + component.setComponentInstances(Collections.singletonList(componentInstance)); + + when(toscaOperationFacade.getToscaElement(componentId)).thenReturn(Either.left(component)); + when(componentValidations.getComponentInstance(component, componentInstanceId)) + .thenReturn(Optional.of(componentInstance)); + when(toscaOperationFacade.updateComponentInstanceInterfaces(component, componentInstanceId)) + .thenReturn(StorageOperationStatus.OK); + when(toscaOperationFacade + .updateComponentInstanceMetadataOfTopologyTemplate(any(Service.class), any(ComponentParametersView.class))) + .thenReturn(Either.left(component)); + when(applicationDataTypeCache.getAll(null)).thenReturn(Either.left(dataTypes)); + + final Optional result = componentInterfaceOperationBusinessLogic + .updateComponentInstanceInterfaceOperation(componentId, componentInstanceId, interfaceDefinition, + ComponentTypeEnum.SERVICE, errorWrapper, false); + assertThat(result).isPresent(); + } + + @Test + void valueForArtifactInputFailsConstraintsValidation() throws BusinessLogicException { + final String inputType = "myType"; + final String artifactType = "artifactType"; + final String componentId = component.getUniqueId(); + final String componentInstanceId = componentInstance.getUniqueId(); + final InterfaceDefinition interfaceDefinition = new InterfaceDefinition(); + interfaceDefinition.setUniqueId(UUID.randomUUID().toString()); + interfaceDefinition.setType("tosca.interfaces.node.lifecycle.Standard"); + final Map operations = new HashMap<>(); + final OperationDataDefinition operationDataDefinition = new OperationDataDefinition(); + operationDataDefinition.setUniqueId(UUID.randomUUID().toString()); + final ArtifactDataDefinition artifactDataDefinition = new ArtifactDataDefinition(); + + artifactDataDefinition.setArtifactName("EO Implementation info"); + artifactDataDefinition.setArtifactType(artifactType); + PropertyDataDefinition propertyDataDefinition = new PropertyDataDefinition(); + propertyDataDefinition.setName("propertyWithRestrictedValues"); + propertyDataDefinition.setType(inputType); + propertyDataDefinition.setValue("{\"propertyWithRestrictedValues\": \"invalid\"}"); + artifactDataDefinition.addProperty(propertyDataDefinition); + + operationDataDefinition.setImplementation(artifactDataDefinition); + operations.put("configure", operationDataDefinition); + interfaceDefinition.setOperations(operations ); + + final DataTypeDefinition myType = new DataTypeDefinition(); + final ArtifactTypeDefinition artifactTypeDefinitionFromCache = new ArtifactTypeDefinition(); + artifactTypeDefinitionFromCache.setName(UniqueIdBuilder.buildArtifactTypeUid(null, artifactType)); + myType.setName(inputType); + PropertyDefinition propertyWithRestrictedValues = new PropertyDefinition(); + propertyWithRestrictedValues.setName("propertyWithRestrictedValues"); + propertyWithRestrictedValues.setType("string"); + PropertyConstraint constraint1 = new ValidValuesConstraint(Arrays.asList("value1", "value2", "value3")); + propertyWithRestrictedValues.setConstraints(List.of(constraint1)); + artifactTypeDefinitionFromCache.setProperties(List.of(propertyWithRestrictedValues)); + myType.setProperties(List.of(propertyWithRestrictedValues)); + Map dataTypes = Collections.singletonMap(myType.getName(), myType); + Wrapper errorWrapper = new Wrapper<>(); + + final ComponentInstanceInterface componentInstanceInterface = + new ComponentInstanceInterface("interfaceId", interfaceDefinition); + Map> componentInstancesInterfacesMap = new HashMap<>(); + componentInstancesInterfacesMap.put(componentInstanceId, Collections.singletonList(componentInstanceInterface)); + component.setComponentInstancesInterfaces(componentInstancesInterfacesMap); + componentInstance.setInterfaces( + (Map) new HashMap<>().put(componentInstanceId, interfaceDefinition)); + component.setComponentInstances(Collections.singletonList(componentInstance)); + + when(toscaOperationFacade.getToscaElement(componentId)).thenReturn(Either.left(component)); + when(componentValidations.getComponentInstance(component, componentInstanceId)) + .thenReturn(Optional.of(componentInstance)); + when(applicationDataTypeCache.getAll(null)).thenReturn(Either.left(dataTypes)); + when(artifactTypeBusinessLogic.getArtifactTypeByUid(UniqueIdBuilder.buildArtifactTypeUid( + null, artifactType))).thenReturn(artifactTypeDefinitionFromCache); + + final Optional result = componentInterfaceOperationBusinessLogic + .updateComponentInstanceInterfaceOperation(componentId, componentInstanceId, interfaceDefinition, + ComponentTypeEnum.SERVICE, errorWrapper, false); + assertThat(result).isNotPresent(); + assertTrue(errorWrapper.getInnerElement().getStatus() == 400); + assertTrue(errorWrapper.getInnerElement().getRequestError().getRequestError().getServiceException().getText() + .contains("Error: Invalid property values provided")); + } + + @Test + void valueForArtifactInputSucceedsConstraintsValidation() throws BusinessLogicException { + final String inputType = "myType"; + final String artifactType = "artifactType"; + final String componentId = component.getUniqueId(); + final String componentInstanceId = componentInstance.getUniqueId(); + final InterfaceDefinition interfaceDefinition = new InterfaceDefinition(); + interfaceDefinition.setUniqueId(UUID.randomUUID().toString()); + interfaceDefinition.setType("tosca.interfaces.node.lifecycle.Standard"); + final Map operations = new HashMap<>(); + final OperationDataDefinition operationDataDefinition = new OperationDataDefinition(); + operationDataDefinition.setUniqueId(UUID.randomUUID().toString()); + final ArtifactDataDefinition artifactDataDefinition = new ArtifactDataDefinition(); + + artifactDataDefinition.setArtifactName("EO Implementation info"); + artifactDataDefinition.setArtifactType(artifactType); + PropertyDataDefinition propertyDataDefinition = new PropertyDataDefinition(); + propertyDataDefinition.setName("input_range"); + propertyDataDefinition.setType(inputType); + propertyDataDefinition.setValue("{\"input_range\": \"value2\"}"); + artifactDataDefinition.addProperty(propertyDataDefinition); + + operationDataDefinition.setImplementation(artifactDataDefinition); + operations.put("configure", operationDataDefinition); + interfaceDefinition.setOperations(operations ); + + DataTypeDefinition myType = new DataTypeDefinition(); + final ArtifactTypeDefinition artifactTypeDefinitionFromCache = new ArtifactTypeDefinition(); + artifactTypeDefinitionFromCache.setName(UniqueIdBuilder.buildArtifactTypeUid(null, artifactType)); + myType.setName(inputType); + PropertyDefinition input_range = new PropertyDefinition(); + input_range.setName("input_range"); + input_range.setType("string"); + PropertyConstraint constraint1 = new ValidValuesConstraint(Arrays.asList("value1", "value2", "value3")); + input_range.setConstraints(List.of(constraint1)); + artifactTypeDefinitionFromCache.setProperties(List.of(input_range)); + myType.setProperties(List.of(input_range)); + Map dataTypes = Collections.singletonMap(myType.getName(), myType); + Wrapper errorWrapper = new Wrapper<>(); + + final ComponentInstanceInterface componentInstanceInterface = + new ComponentInstanceInterface("interfaceId", interfaceDefinition); + Map> componentInstancesInterfacesMap = new HashMap<>(); + componentInstancesInterfacesMap.put(componentInstanceId, Collections.singletonList(componentInstanceInterface)); + component.setComponentInstancesInterfaces(componentInstancesInterfacesMap); + componentInstance.setInterfaces( + (Map) new HashMap<>().put(componentInstanceId, interfaceDefinition)); + component.setComponentInstances(Collections.singletonList(componentInstance)); + + when(toscaOperationFacade.getToscaElement(componentId)).thenReturn(Either.left(component)); + when(componentValidations.getComponentInstance(component, componentInstanceId)) + .thenReturn(Optional.of(componentInstance)); + when(toscaOperationFacade.updateComponentInstanceInterfaces(component, componentInstanceId)) + .thenReturn(StorageOperationStatus.OK); + when(toscaOperationFacade + .updateComponentInstanceMetadataOfTopologyTemplate(any(Service.class), any(ComponentParametersView.class))) + .thenReturn(Either.left(component)); + when(applicationDataTypeCache.getAll(null)).thenReturn(Either.left(dataTypes)); + when(artifactTypeBusinessLogic.getArtifactTypeByUid(UniqueIdBuilder.buildArtifactTypeUid( + null, artifactType))).thenReturn(artifactTypeDefinitionFromCache); + + final Optional result = componentInterfaceOperationBusinessLogic + .updateComponentInstanceInterfaceOperation(componentId, componentInstanceId, interfaceDefinition, + ComponentTypeEnum.SERVICE, errorWrapper, false); + assertThat(result).isPresent(); + } + + private void initComponentData() { try { component = new Service(); component.setName("MyTestService"); diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/servlets/TypesFetchServletTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/servlets/TypesFetchServletTest.java index 1808560b4e..031377f2e9 100644 --- a/catalog-be/src/test/java/org/openecomp/sdc/be/servlets/TypesFetchServletTest.java +++ b/catalog-be/src/test/java/org/openecomp/sdc/be/servlets/TypesFetchServletTest.java @@ -43,7 +43,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.openecomp.sdc.be.components.impl.ArtifactsBusinessLogic; +import org.openecomp.sdc.be.components.impl.ArtifactTypeBusinessLogic; import org.openecomp.sdc.be.components.impl.CapabilitiesBusinessLogic; import org.openecomp.sdc.be.components.impl.ComponentInstanceBusinessLogic; import org.openecomp.sdc.be.components.impl.InterfaceOperationBusinessLogic; @@ -113,7 +113,7 @@ class TypesFetchServletTest extends JerseyTest { @Mock private ResourceBusinessLogic resourceBusinessLogic; @Mock - private ArtifactsBusinessLogic artifactsBusinessLogic; + private ArtifactTypeBusinessLogic artifactTypeBusinessLogic; @Mock private ResponseFormatManager responseFormatManager; @@ -213,7 +213,7 @@ class TypesFetchServletTest extends JerseyTest { bind(relationshipTypeBusinessLogic).to(RelationshipTypeBusinessLogic.class); bind(capabilitiesBusinessLogic).to(CapabilitiesBusinessLogic.class); bind(interfaceOperationBusinessLogic).to(InterfaceOperationBusinessLogic.class); - bind(artifactsBusinessLogic).to(ArtifactsBusinessLogic.class); + bind(artifactTypeBusinessLogic).to(ArtifactTypeBusinessLogic.class); } }) .register(new OperationExceptionMapper( @@ -256,8 +256,8 @@ class TypesFetchServletTest extends JerseyTest { .thenReturn(interfaceOperationBusinessLogic); when(webApplicationContext.getBean(ResourceBusinessLogic.class)) .thenReturn(resourceBusinessLogic); - when(webApplicationContext.getBean(ArtifactsBusinessLogic.class)) - .thenReturn(artifactsBusinessLogic); + when(webApplicationContext.getBean(ArtifactTypeBusinessLogic.class)) + .thenReturn(artifactTypeBusinessLogic); } void initConfig() {