Operation Outputs - Operation screen BE 18/77518/3
authorojasdubey <ojas.dubey@amdocs.com>
Tue, 29 Jan 2019 14:54:39 +0000 (20:24 +0530)
committerojasdubey <ojas.dubey@amdocs.com>
Thu, 31 Jan 2019 08:56:43 +0000 (14:26 +0530)
1. Fixed bug in tosca generation for mapped outputs
2. Fixed issues in validation of modified mapped
outputs and tosca generation
3. Unit tests

Change-Id: I2cb9a55d58d8e9a8d2a4a064646d6ef7ec93e61f
Issue-ID: SDC-2085
Signed-off-by: ojasdubey <ojas.dubey@amdocs.com>
catalog-be/src/main/java/org/openecomp/sdc/be/components/validation/InterfaceOperationValidation.java
catalog-be/src/main/java/org/openecomp/sdc/be/tosca/utils/InterfacesOperationsToscaUtil.java
catalog-be/src/main/resources/config/error-configuration.yaml
catalog-be/src/test/java/org/openecomp/sdc/be/tosca/utils/InterfacesOperationsToscaUtilTest.java
catalog-be/src/test/java/org/openecomp/sdc/test/utils/InterfaceOperationTestUtils.java
catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java

index d17762f..250fc03 100644 (file)
@@ -179,11 +179,11 @@ public class InterfaceOperationValidation {
         }
 
         if (MapUtils.isNotEmpty(component.getInterfaces()) && isUpdate) {
-            Either<Boolean, ResponseFormat> mappedOutputDeletedResponse =
-                    validateMappedOutputNotDeleted(interfaceOperation, component, inputInterfaceDefinition,
+            Either<Boolean, ResponseFormat> mappedOutputModifiedResponse =
+                    validateMappedOutputNotModified(interfaceOperation, component, inputInterfaceDefinition,
                             responseFormatManager);
-            if (mappedOutputDeletedResponse.isRight()) {
-                return Either.right(mappedOutputDeletedResponse.right().value());
+            if (mappedOutputModifiedResponse.isRight()) {
+                return Either.right(mappedOutputModifiedResponse.right().value());
             }
         }
 
@@ -191,7 +191,7 @@ public class InterfaceOperationValidation {
     }
 
 
-    private Either<Boolean, ResponseFormat> validateMappedOutputNotDeleted(Operation interfaceOperation,
+    private Either<Boolean, ResponseFormat> validateMappedOutputNotModified(Operation interfaceOperation,
             org.openecomp.sdc.be.model.Component component, InterfaceDefinition interfaceDefinition,
             ResponseFormatManager responseFormatManager) {
 
@@ -222,6 +222,18 @@ public class InterfaceOperationValidation {
         if (CollectionUtils.isNotEmpty(deletedMappedOutputs)) {
             return getMappedOutputErrorResponse(responseFormatManager, deletedMappedOutputs);
         }
+
+        if (currentOutputs != null && !currentOutputs.isEmpty()) {
+            Set<String> unchangedOutputNames = Sets.intersection(existingOperationOutputNames,
+                    currentOperationOutputNames);
+            Set<String> modifiedMappedOutputNames =
+                    getModifiedMappedOutputNames(currentOutputs.getListToscaDataDefinition(),
+                            existingOperationOutputs, unchangedOutputNames);
+            if (CollectionUtils.isNotEmpty(modifiedMappedOutputNames)) {
+                return getMappedOutputErrorResponse(responseFormatManager, modifiedMappedOutputNames);
+            }
+        }
+
         return Either.left(Boolean.TRUE);
     }
 
@@ -234,13 +246,36 @@ public class InterfaceOperationValidation {
                         .equals(mappedOutputPrefix + "." + outputName));
     }
 
+    private static Set<String> getModifiedMappedOutputNames(List<OperationOutputDefinition> currentOperationOutputs,
+            List<OperationOutputDefinition> existingOperationOutputs,
+            Set<String> unchangedOutputNames) {
+        Set<String> modifiedOutputDefinitionNames = new HashSet<>();
+        Map<String, OperationOutputDefinition> newOutputMap =
+                currentOperationOutputs.stream().collect(Collectors.toMap(OperationOutputDefinition::getName,
+                        (OperationOutputDefinition operationOutputDefinition) -> operationOutputDefinition));
+
+        Map<String, OperationOutputDefinition> existingOutputMap =
+                existingOperationOutputs.stream().collect(Collectors.toMap(OperationOutputDefinition::getName,
+                        (OperationOutputDefinition operationOutputDefinition) -> operationOutputDefinition));
+
+        for (String outputName : unchangedOutputNames) {
+            OperationOutputDefinition existingOutputDefinition = existingOutputMap.get(outputName);
+            OperationOutputDefinition newOutputDefinition = newOutputMap.get(outputName);
+            if (!existingOutputDefinition.getType().equals(newOutputDefinition.getType())
+                        || !existingOutputDefinition.isRequired().equals(newOutputDefinition.isRequired())) {
+                modifiedOutputDefinitionNames.add(outputName);
+            }
+        }
+        return modifiedOutputDefinitionNames;
+    }
+
     private Either<Boolean, ResponseFormat> getMappedOutputErrorResponse(ResponseFormatManager responseFormatManager,
-                                                                         Set<String> deletedMappedOutputs) {
-        String deletedOutputNameList = String.join(",", deletedMappedOutputs);
-        LOGGER.error("Cannot update name or delete interface operation output(s) '{}' mapped to an operation input",
-                deletedOutputNameList);
+                                                                         Set<String> modifiedMappedOutputs) {
+        String modifiedOutputNameList = String.join(",", modifiedMappedOutputs);
+        LOGGER.error("Cannot update or delete interface operation output(s) '{}' mapped to an operation input",
+                modifiedOutputNameList);
         ResponseFormat errorResponse = responseFormatManager.getResponseFormat(ActionStatus
-                .INTERFACE_OPERATION_MAPPED_OUTPUT_DELETED, deletedOutputNameList);
+                .INTERFACE_OPERATION_MAPPED_OUTPUT_MODIFIED, modifiedOutputNameList);
         return Either.right(errorResponse);
     }
 
index efed3e9..106aa58 100644 (file)
@@ -20,14 +20,12 @@ import static org.openecomp.sdc.be.components.utils.InterfaceOperationUtils.isOp
 
 import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.databind.ObjectMapper;
-
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-
 import org.apache.commons.collections.MapUtils;
 import org.openecomp.sdc.be.datatypes.elements.OperationDataDefinition;
 import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition;
@@ -59,7 +57,7 @@ public class InterfacesOperationsToscaUtil {
     }
 
     /**
-     * Creates the interface_types element
+     * Creates the interface_types element.
      *
      * @param component to work on
      * @return the added element
@@ -99,7 +97,7 @@ public class InterfacesOperationsToscaUtil {
     }
 
     /**
-     * Adds the 'interfaces' element to the node type provided
+     * Adds the 'interfaces' element to the node type provided.
      *
      * @param component to work on
      * @param nodeType  to which the interfaces element will be added
@@ -131,7 +129,7 @@ public class InterfacesOperationsToscaUtil {
                     toscaOperation.setImplementation(operationArtifactPath);
                 }
                 toscaOperation.setDescription(operationEntry.getValue().getDescription());
-                fillToscaOperationInputs(operationEntry.getValue(), toscaOperation, interfaceType, component);
+                fillToscaOperationInputs(operationEntry.getValue(), toscaOperation, component);
 
                 toscaOperations.put(operationEntry.getValue().getName(), toscaOperation);
             }
@@ -148,7 +146,7 @@ public class InterfacesOperationsToscaUtil {
         }
     }
 
-    /***
+    /*
      * workaround for : currently "defaultp" is not being converted to "default" by the relevant code in
      * ToscaExportHandler so, any string Map key named "defaultp" will have its named changed to "default"
      * @param operationsMap the map to update
@@ -181,7 +179,6 @@ public class InterfacesOperationsToscaUtil {
 
     private static void fillToscaOperationInputs(OperationDataDefinition operation,
                                                  ToscaLifecycleOperationDefinition toscaOperation,
-                                                 String interfaceType,
                                                  Component component) {
         if (Objects.isNull(operation.getInputs()) || operation.getInputs().isEmpty()) {
             toscaOperation.setInputs(null);
@@ -199,7 +196,7 @@ public class InterfacesOperationsToscaUtil {
                     toscaInput.setDefaultp(createMappedInputPropertyDefaultValue(mappedPropertyName));
                 } else {
                     mappedPropertyName = input.getInputId();
-                    toscaInput.setDefaultp(createMappedOutputDefaultValue(mappedPropertyName, interfaceType));
+                    toscaInput.setDefaultp(createMappedOutputDefaultValue(mappedPropertyName));
                 }
             }
             toscaInput.setType(input.getType());
@@ -224,23 +221,28 @@ public class InterfacesOperationsToscaUtil {
     }
 
     /**
-     * Create the value for operation input mapped to an operation output
+     * Create the value for operation input mapped to an operation output.
      * @param propertyName the mapped other operation output full name
-     * @param interfaceType full interface name
      * @return input map for tosca
      */
-    private static Map<String, List<String>> createMappedOutputDefaultValue(String propertyName, String interfaceType) {
+    private static Map<String, List<String>> createMappedOutputDefaultValue(String propertyName) {
         Map<String, List<String>> getOperationOutputMap = new HashMap<>();
         //For operation input mapped to other operation output parameter, the mapped property value
         // should be of the format <interface name>.<operation name>.<output parameter name>
+        // Operation name and output param name should not contain "."
         List<String> defaultMappedOperationOutputValue = new ArrayList<>();
-        defaultMappedOperationOutputValue.add(SELF);
-        String fullOutputPropertyName =
-                propertyName.substring(propertyName.indexOf(interfaceType) + interfaceType.length() + 1);
-        defaultMappedOperationOutputValue.add(interfaceType);
-        //Output name should not contain dot
-        defaultMappedOperationOutputValue.addAll(Arrays.asList(fullOutputPropertyName.split("\\.")));
-        getOperationOutputMap.put(GET_OPERATION_OUTPUT, defaultMappedOperationOutputValue);
+        String[] tokens = propertyName.split("\\.");
+        if (tokens.length > 2) {
+            defaultMappedOperationOutputValue.add(SELF);
+            String outputPropertyName = tokens[tokens.length - 1];
+            String operationName = tokens[tokens.length - 2];
+            String mappedPropertyInterfaceType =
+                    propertyName.substring(0, propertyName.indexOf(operationName + '.' + outputPropertyName) - 1);
+            String interfaceName =
+                    mappedPropertyInterfaceType.substring(mappedPropertyInterfaceType.lastIndexOf('.') + 1);
+            defaultMappedOperationOutputValue.addAll(Arrays.asList(interfaceName, operationName, outputPropertyName));
+            getOperationOutputMap.put(GET_OPERATION_OUTPUT, defaultMappedOperationOutputValue);
+        }
         return getOperationOutputMap;
     }
 
index 69f67e6..c92b0fd 100644 (file)
@@ -2235,10 +2235,10 @@ errors:
         message: "Error: Property type %1 provided against %2 is not supported for static value.",
         messageId: "SVC4721"
     }
-#---------SVC4714-----------------------------
+#---------SVC4723-----------------------------
 # %1 - Interface Operation output name
-    INTERFACE_OPERATION_MAPPED_OUTPUT_DELETED: {
+    INTERFACE_OPERATION_MAPPED_OUTPUT_MODIFIED: {
         code: 400,
-        message: "Error: Cannot update name or delete interface operation output(s) '%1' mapped to an operation input",
-        messageId: "SVC4714"
+        message: "Error: Cannot update or delete interface operation output(s) '%1' mapped to an operation input",
+        messageId: "SVC4723"
     }
\ No newline at end of file
index 36dd5d9..156d280 100644 (file)
@@ -24,13 +24,11 @@ import static org.openecomp.sdc.be.tosca.utils.InterfacesOperationsToscaUtil.add
 
 import com.fasterxml.jackson.databind.DeserializationFeature;
 import com.fasterxml.jackson.databind.ObjectMapper;
-
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-
 import org.junit.Assert;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -236,6 +234,54 @@ public class InterfacesOperationsToscaUtilTest {
         validateOperationInputs(mainYaml, 2, "name_for_op_1");
     }
 
+    @Test
+    public void addInterfaceDefinitionElementInputMappedToOtherOperationOutputFromOtherInterface() {
+        String addedInterfaceType = "com.some.resource.or.other.resourceNameInputMappedToOutput";
+        Component component = new Resource();
+        component.setNormalizedName("normalizedComponentName");
+        InterfaceDefinition addedInterface = new InterfaceDefinition();
+        addedInterface.setType(addedInterfaceType);
+        addOperationsToInterface(component, addedInterface, 2, 2, true, true);
+        addedInterface.getOperationsMap().values().stream()
+                      .filter(operationInputDefinition -> operationInputDefinition.getName().equalsIgnoreCase(
+                              "name_for_op_0"))
+                      .forEach(operation -> operation.getInputs().getListToscaDataDefinition().stream()
+                                                     .filter(opInputDef -> opInputDef.getName().contains("integer"))
+                                                     .forEach(opInputDef -> opInputDef.setInputId(
+                                                             addedInterfaceType +".name_for_op_1.output_integer_1")));
+        //Mapping to operation from another interface
+        String secondInterfaceType = "org.test.lifecycle.standard.interfaceType.second";
+        InterfaceDefinition secondInterface = new InterfaceDefinition();
+        secondInterface.setType(secondInterfaceType);
+        addOperationsToInterface(component, secondInterface, 2, 2, true, true);
+        secondInterface.getOperationsMap().values().stream()
+                      .filter(operationInputDefinition -> operationInputDefinition.getName().equalsIgnoreCase(
+                              "name_for_op_0"))
+                      .forEach(operation -> operation.getInputs().getListToscaDataDefinition().stream()
+                                                     .filter(opInputDef -> opInputDef.getName().contains("integer"))
+                                                     .forEach(opInputDef -> opInputDef.setInputId(
+                                                             addedInterfaceType +".name_for_op_1.output_integer_1")));
+        component.setInterfaces(new HashMap<>());
+        component.getInterfaces().put(addedInterfaceType, addedInterface);
+        component.getInterfaces().put(secondInterfaceType, secondInterface);
+
+        ToscaNodeType nodeType = new ToscaNodeType();
+        addInterfaceDefinitionElement(component, nodeType, false);
+
+        ToscaExportHandler handler = new ToscaExportHandler(null,null,null,null,null,null, null);
+        ToscaTemplate template = new ToscaTemplate("test");
+        Map<String, ToscaNodeType> nodeTypes = new HashMap<>();
+        nodeTypes.put("test", nodeType);
+        template.setNode_types(nodeTypes);
+        final ToscaRepresentation toscaRepresentation = handler.createToscaRepresentation(template);
+
+        String mainYaml = toscaRepresentation.getMainYaml();
+        Assert.assertFalse(mainYaml.contains("operations"));
+        Assert.assertTrue(mainYaml.contains("resourceNameInputMappedToOutput:"));
+        Assert.assertTrue(mainYaml.contains("inputs:"));
+        validateOperationInputs(mainYaml, 2, "name_for_op_1");
+    }
+
     private void addOperationsToInterface(Component component, InterfaceDefinition addedInterface, int numOfOps,
                                           int numOfInputsPerOp, boolean hasInputs, boolean hasOutputs) {
 
@@ -319,7 +365,8 @@ public class InterfacesOperationsToscaUtilTest {
             for (Map.Entry<String, Object> operationEntry : interfaceDefinition.entrySet()) {
                 Object operationVal = operationEntry.getValue();
                 if (operationVal instanceof Map) {
-                    validateOperationInputDefinition((String) interfaceDefinition.get("type"), mappedOperationName,
+                    //Since the inputs are mapped to output operations from only first interface so using that name
+                    validateOperationInputDefinition(interfaces.keySet().iterator().next(), mappedOperationName,
                             operationVal);
                 }
             }
index c614c6e..1cc5b56 100644 (file)
@@ -18,7 +18,6 @@ package org.openecomp.sdc.test.utils;
 
 import java.util.HashMap;
 import java.util.Map;
-
 import org.openecomp.sdc.be.datatypes.elements.ListDataDefinition;
 import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition;
 import org.openecomp.sdc.be.datatypes.elements.OperationOutputDefinition;
@@ -87,6 +86,8 @@ public class InterfaceOperationTestUtils {
         operationInputDefinition.setInputId("ComponentInput" + num + "_uniqueId");
         operationInputDefinition.setValue(inputName + "_value");
         operationInputDefinition.setDefaultValue(inputName + "_defaultValue");
+        operationInputDefinition.setType("string");
+        operationInputDefinition.setRequired(true);
         return operationInputDefinition;
     }
 
@@ -96,6 +97,8 @@ public class InterfaceOperationTestUtils {
         operationOutputDefinition.setUniqueId(outputName + "_uniqueId");
         operationOutputDefinition.setValue(outputName + "_value");
         operationOutputDefinition.setDefaultValue(outputName + "_defaultValue");
+        operationOutputDefinition.setType("string");
+        operationOutputDefinition.setRequired(true);
         return operationOutputDefinition;
     }
 
index 8715e1d..33515c3 100644 (file)
@@ -124,7 +124,7 @@ public enum ActionStatus {
     INTERFACE_OPERATION_NOT_FOUND, INTERFACE_OPERATION_NAME_ALREADY_IN_USE, INTERFACE_OPERATION_NAME_MANDATORY,
     INTERFACE_OPERATION_NAME_INVALID, INTERFACE_OPERATION_INPUT_NAME_ALREADY_IN_USE,
     INTERFACE_OPERATION_OUTPUT_NAME_ALREADY_IN_USE, INTERFACE_OPERATION_NOT_DELETED,
-    INTERFACE_OPERATION_MAPPED_OUTPUT_DELETED,
+    INTERFACE_OPERATION_MAPPED_OUTPUT_MODIFIED,
     INTERFACE_OPERATION_INPUT_NAME_MANDATORY, INTERFACE_OPERATION_OUTPUT_NAME_MANDATORY,
     INTERFACE_OPERATION_INPUT_PROPERTY_NOT_FOUND_IN_COMPONENT, INTERFACE_OPERATION_INVALID_FOR_LOCAL_TYPE,
     INTERFACE_OPERATION_INVALID_FOR_GLOBAL_TYPE,
@@ -142,5 +142,5 @@ public enum ActionStatus {
 
 
     //InterfaceLifeCycleType
-    INTERFACE_LIFECYCLE_TYPES_NOT_FOUND;
+    INTERFACE_LIFECYCLE_TYPES_NOT_FOUND
 }