Constraint validation for instance properties in a service

Validating the properties of instance in a service against it's constraints

Issue-ID: SDC-4190
Signed-off-by: Imam hussain <imam.hussain@est.tech>
Change-Id: I04bb907f52229c3d214e15434595e5429ef5101c
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java
index 1d10c92..0b3610a 100644
--- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java
@@ -63,6 +63,7 @@
 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
 import org.openecomp.sdc.be.dao.jsongraph.types.JsonParseFlagEnum;
 import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary;
+import org.openecomp.sdc.be.datamodel.utils.PropertyValueConstraintValidationUtil;
 import org.openecomp.sdc.be.datatypes.elements.CINodeFilterDataDefinition;
 import org.openecomp.sdc.be.datatypes.elements.CapabilityDataDefinition;
 import org.openecomp.sdc.be.datatypes.elements.ForwardingPathDataDefinition;
@@ -187,6 +188,7 @@
     @Autowired
     private ContainerInstanceTypesData containerInstanceTypesData;
     private final ToscaFunctionValidator toscaFunctionValidator;
+    private final PropertyBusinessLogic propertyBusinessLogic;
 
     @Autowired
     public ComponentInstanceBusinessLogic(IElementOperation elementDao, IGroupOperation groupOperation,
@@ -196,7 +198,8 @@
                                           ComponentInstanceMergeDataBusinessLogic compInstMergeDataBL,
                                           ComponentInstanceChangeOperationOrchestrator onChangeInstanceOperationOrchestrator,
                                           ForwardingPathOperation forwardingPathOperation, NodeFilterOperation nodeFilterOperation,
-                                          ArtifactsOperations artifactToscaOperation, final ToscaFunctionValidator toscaFunctionValidator) {
+                                          ArtifactsOperations artifactToscaOperation, final ToscaFunctionValidator toscaFunctionValidator,
+                                          PropertyBusinessLogic propertyBusinessLogic) {
         super(elementDao, groupOperation, groupInstanceOperation, groupTypeOperation, interfaceOperation, interfaceLifecycleTypeOperation,
             artifactToscaOperation);
         this.componentInstanceOperation = componentInstanceOperation;
@@ -206,6 +209,7 @@
         this.forwardingPathOperation = forwardingPathOperation;
         this.nodeFilterOperation = nodeFilterOperation;
         this.toscaFunctionValidator = toscaFunctionValidator;
+        this.propertyBusinessLogic = propertyBusinessLogic;
     }
 
     public ComponentInstance createComponentInstance(String containerComponentParam, String containerComponentId, String userId,
@@ -1953,6 +1957,12 @@
         }
         ComponentInstance foundResourceInstance = resourceInstanceStatus.left().value();
 
+        // Validate instance property against it's constrains
+        Either<Boolean, ResponseFormat> constraintValidatorResponse = validatePropertyValueConstraint(properties,componentId);
+        if (constraintValidatorResponse.isRight()) {
+            log.error("Failed validation value and constraint of property: {}", constraintValidatorResponse.right().value());
+            return Either.right(constraintValidatorResponse.right().value());
+        }
         // lock resource
         StorageOperationStatus lockStatus = graphLockOperation.lockComponent(componentId, componentTypeEnum.getNodeType());
         if (lockStatus != StorageOperationStatus.OK) {
@@ -3908,6 +3918,16 @@
         }
     }
 
+    private Either<Boolean, ResponseFormat> validatePropertyValueConstraint(List<ComponentInstanceProperty> properties, final String componentId) {
+        try {
+            String propertyModel = propertyBusinessLogic.getComponentModelByComponentId(componentId);
+            PropertyValueConstraintValidationUtil propertyValueConstraintValidationUtil = new PropertyValueConstraintValidationUtil();
+            return propertyValueConstraintValidationUtil.validatePropertyConstraints(properties, applicationDataTypeCache, propertyModel);
+        } catch (BusinessLogicException e) {
+            return Either.right(e.getResponseFormat());
+        }
+    }
+
     public void validateUser(final String userId) {
         final User user = userValidations.validateUserExists(userId);
         userValidations.validateUserRole(user, Arrays.asList(Role.DESIGNER, Role.ADMIN));
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 442c3da..2d3ef85 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
@@ -34,6 +34,7 @@
 import org.openecomp.sdc.be.components.impl.ResponseFormatManager;
 import org.openecomp.sdc.be.dao.api.ActionStatus;
 import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition;
+import org.openecomp.sdc.be.model.ComponentInstanceInput;
 import org.openecomp.sdc.be.model.DataTypeDefinition;
 import org.openecomp.sdc.be.model.InputDefinition;
 import org.openecomp.sdc.be.model.PropertyConstraint;
@@ -77,6 +78,9 @@
     }
 
     private boolean isValuePresent(PropertyDefinition propertyDefinition) {
+        if (propertyDefinition instanceof ComponentInstanceInput) {
+            return StringUtils.isNotEmpty(propertyDefinition.getValue());
+        }
         if (propertyDefinition instanceof InputDefinition) {
             return StringUtils.isNotEmpty(propertyDefinition.getDefaultValue());
         }
@@ -90,6 +94,11 @@
         }
         completeInputName = "";
         completePropertyName = new StringBuilder();
+        if (propertyDefinition instanceof ComponentInstanceInput) {
+            setCompletePropertyName(propertyDefinition);
+            evaluateComplexTypeProperties(propertyDefinition);
+            return;
+        }
         if (propertyDefinition instanceof InputDefinition) {
             completeInputName = propertyDefinition.getName();
             propertyDefinition = getPropertyDefinitionObjectFromInputs(propertyDefinition);
diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogicTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogicTest.java
index 3a5f40c..f22b346 100644
--- a/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogicTest.java
+++ b/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogicTest.java
@@ -51,6 +51,7 @@
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
+import lombok.SneakyThrows;
 import mockit.Deencapsulation;
 import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.apache.commons.lang3.tuple.Pair;
@@ -72,6 +73,7 @@
 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphDao;
 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
 import org.openecomp.sdc.be.dao.jsongraph.types.JsonParseFlagEnum;
+import org.openecomp.sdc.be.datamodel.utils.PropertyValueConstraintValidationUtil;
 import org.openecomp.sdc.be.datatypes.elements.CapabilityDataDefinition;
 import org.openecomp.sdc.be.datatypes.elements.ForwardingPathDataDefinition;
 import org.openecomp.sdc.be.datatypes.elements.ForwardingPathElementDataDefinition;
@@ -190,7 +192,8 @@
     private CompositionBusinessLogic compositionBusinessLogic;
     @Mock
     private ToscaFunctionValidator toscaFunctionValidator;
-
+    @Mock
+    private PropertyBusinessLogic propertyBusinessLogic;
     private Component service;
     private Component resource;
     private ComponentInstance toInstance;
@@ -216,7 +219,7 @@
     void init() {
         MockitoAnnotations.openMocks(this);
         componentInstanceBusinessLogic = new ComponentInstanceBusinessLogic(null, null, null, null, null, null, null, artifactsBusinessLogic, null,
-            null, forwardingPathOperation, null, null, toscaFunctionValidator);
+            null, forwardingPathOperation, null, null, toscaFunctionValidator, propertyBusinessLogic);
         componentInstanceBusinessLogic.setComponentsUtils(componentsUtils);
         componentInstanceBusinessLogic.setToscaOperationFacade(toscaOperationFacade);
         componentInstanceBusinessLogic.setUserValidations(userValidations);
@@ -305,6 +308,7 @@
 
     }
 
+    @SneakyThrows
     @Test
     void testCreateOrUpdatePropertiesValues2() {
         String containerComponentID = "containerId";
@@ -356,6 +360,10 @@
         when(janusGraphDao.commit()).thenReturn(JanusGraphOperationStatus.OK);
         when(graphLockOperation.unlockComponent(containerComponentID, NodeTypeEnum.ResourceInstance))
             .thenReturn(StorageOperationStatus.OK);
+        when(propertyBusinessLogic.getComponentModelByComponentId(any())).thenReturn(component.getModel());
+        when(applicationDataTypeCache.getAll(any())).thenReturn(Either.left(types));
+        PropertyValueConstraintValidationUtil validationUtil = Mockito.mock(PropertyValueConstraintValidationUtil.class);
+        when(validationUtil.validatePropertyConstraints(any(),any(),any())).thenReturn(Either.left(any()));
 
         Either<List<ComponentInstanceProperty>, ResponseFormat> responseFormatEither = componentInstanceBusinessLogic
             .createOrUpdatePropertiesValues(
@@ -365,6 +373,7 @@
 
 
 
+    @SneakyThrows
     @Test
     void testCreateOrUpdatePropertiesValuesPropertyNotExists() {
         String containerComponentID = "containerId";
@@ -396,6 +405,12 @@
             .thenReturn(StorageOperationStatus.OK);
         when(graphLockOperation.unlockComponent(containerComponentID, NodeTypeEnum.ResourceInstance))
             .thenReturn(StorageOperationStatus.OK);
+        when(propertyBusinessLogic.getComponentModelByComponentId(any())).thenReturn(component.getModel());
+        Map<String, DataTypeDefinition> dataTypeMap = new HashMap<>();
+        when(applicationDataTypeCache.getAll(any())).thenReturn(Either.left(dataTypeMap));
+        PropertyValueConstraintValidationUtil validationUtil = Mockito.mock(PropertyValueConstraintValidationUtil.class);
+        when(validationUtil.validatePropertyConstraints(any(),any(),any()))
+            .thenReturn(Either.left(any()));
 
         try {
             componentInstanceBusinessLogic.createOrUpdatePropertiesValues(
@@ -406,6 +421,7 @@
 
     }
 
+    @SneakyThrows
     @Test
     void testCreateOrUpdatePropertiesValuesValidationFailure() {
         String containerComponentID = "containerId";
@@ -449,15 +465,22 @@
             .thenReturn(Either.right(false));
         when(componentsUtils.convertFromStorageResponse(StorageOperationStatus.BAD_REQUEST))
             .thenReturn(ActionStatus.INVALID_CONTENT);
+        when(propertyBusinessLogic.getComponentModelByComponentId(any())).thenReturn(component.getModel());
+        Map<String, DataTypeDefinition> dataTypeMap = new HashMap<>();
+        when(applicationDataTypeCache.getAll(any())).thenReturn(Either.left(dataTypeMap));
+        PropertyValueConstraintValidationUtil validationUtil = Mockito.mock(PropertyValueConstraintValidationUtil.class);
+        when(validationUtil.validatePropertyConstraints(any(),any(),any()))
+            .thenReturn(Either.left(any()));
 
         final Either<List<ComponentInstanceProperty>, ResponseFormat> response = componentInstanceBusinessLogic.createOrUpdatePropertiesValues(
             ComponentTypeEnum.RESOURCE_INSTANCE, containerComponentID, resourceInstanceId, properties, "userId");
         assertThat(response.isRight()).as("Response should be an error").isTrue();
         final ResponseFormat responseFormat = response.right().value();
         assertThat(responseFormat.getStatus()).as("Response status should be as expected").isEqualTo(400);
-        assertThat(responseFormat.getMessageId()).as("Error message id should be as expected").isEqualTo("SVC4000");
+        assertThat(responseFormat.getMessageId()).as("Error message id should be as expected").isEqualTo("SVC4726");
     }
 
+    @SneakyThrows
     @Test
     void testCreateOrUpdatePropertiesValuesMissingFieldFailure() {
         String containerComponentID = "containerId";
@@ -491,6 +514,12 @@
             .thenReturn(Either.left(component));
         when(graphLockOperation.lockComponent(containerComponentID, NodeTypeEnum.ResourceInstance))
             .thenReturn(StorageOperationStatus.OK);
+        when(propertyBusinessLogic.getComponentModelByComponentId(any())).thenReturn(component.getModel());
+        Map<String, DataTypeDefinition> dataTypeMap = new HashMap<>();
+        when(applicationDataTypeCache.getAll(any())).thenReturn(Either.left(dataTypeMap));
+        PropertyValueConstraintValidationUtil validationUtil = Mockito.mock(PropertyValueConstraintValidationUtil.class);
+        when(validationUtil.validatePropertyConstraints(any(),any(),any()))
+            .thenReturn(Either.left(any()));
 
         try {
             componentInstanceBusinessLogic.createOrUpdatePropertiesValues(
diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ResourceInstanceBusinessLogicTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ResourceInstanceBusinessLogicTest.java
index 8bd39af..e5ecf0c 100644
--- a/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ResourceInstanceBusinessLogicTest.java
+++ b/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ResourceInstanceBusinessLogicTest.java
@@ -90,7 +90,7 @@
     private final ForwardingPathOperation forwardingPathOperation = mock(ForwardingPathOperation.class);
     private final NodeFilterOperation serviceFilterOperation = mock(NodeFilterOperation.class);
     private final ToscaFunctionValidator toscaFunctionValidator = mock(ToscaFunctionValidator.class);
-
+    private final PropertyBusinessLogic propertyBusinessLogic = mock(PropertyBusinessLogic.class);
     private static final UserBusinessLogic userAdminManager = mock(UserBusinessLogic.class);
     public static final ComponentsUtils componentsUtils = mock(ComponentsUtils.class);
     public static final IGroupInstanceOperation groupInstanceOperation = mock(IGroupInstanceOperation.class);
@@ -101,7 +101,7 @@
     private final ComponentInstanceBusinessLogic bl = new ComponentInstanceBusinessLogic(elementDao, groupOperation, groupInstanceOperation,
         groupTypeOperation, interfaceOperation, interfaceLifecycleTypeOperation,
         componentInstanceOperation, artifactBusinessLogic, compInstMergeDataBL, onChangeInstanceOperationOrchestrator,
-        forwardingPathOperation, serviceFilterOperation, artifactToscaOperation, toscaFunctionValidator);
+        forwardingPathOperation, serviceFilterOperation, artifactToscaOperation, toscaFunctionValidator, propertyBusinessLogic);
 
     @BeforeEach
     void setUp() throws Exception {