Fix added datatype property not include in model definitions 46/133046/3
authorJvD_Ericsson <jeff.van.dam@est.tech>
Thu, 26 Jan 2023 15:53:57 +0000 (15:53 +0000)
committerJvD_Ericsson <jeff.van.dam@est.tech>
Fri, 27 Jan 2023 12:20:26 +0000 (12:20 +0000)
Issue-ID: SDC-4349
Signed-off-by: JvD_Ericsson <jeff.van.dam@est.tech>
Change-Id: Ie94d697a64816f83be4783f1e52657b7fdd77b8c

catalog-be/src/main/java/org/openecomp/sdc/be/servlets/DataTypeServlet.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/DataTypeOperation.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/ModelOperation.java
catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/ModelOperationTest.java
catalog-model/src/test/resources/modelOperation/expected-additional_types-4.yaml [new file with mode: 0644]

index a7327bf..13e2ba3 100644 (file)
@@ -144,21 +144,22 @@ public class DataTypeServlet extends BeGenericServlet {
     public Response createProperty(@Parameter(in = ParameterIn.PATH, required = true, description = "The data type id")
                                    @PathParam("id") final String id,
                                    @RequestBody(description = "Property to add", required = true) final PropertyDefinitionDto propertyDefinitionDto) {
-        Optional<DataTypeDataDefinition> dataType = dataTypeOperation.getDataTypeByUid(id);
-        dataType.ifPresentOrElse(dt -> {
-            String model = dt.getModel();
-            Optional<DataTypeDataDefinition> propertyDataType = dataTypeOperation.getDataTypeByNameAndModel(propertyDefinitionDto.getType(), model);
-            if (propertyDataType.isEmpty()) {
-                if (model == null || model.isEmpty()) {
-                    model = "SDC AID";
-                }
-                throw new OperationException(ActionStatus.INVALID_MODEL,
-                        String.format("Property model is not the same as the data type model. Must be be '%s'", model));
-            }
-        }, () -> {
+        Optional<DataTypeDataDefinition> dataTypeOptional = dataTypeOperation.getDataTypeByUid(id);
+        dataTypeOptional.orElseThrow(() -> {
             throw new OperationException(ActionStatus.DATA_TYPE_NOT_FOUND, String.format("Failed to find data type '%s'", id));
         });
+        DataTypeDataDefinition dataType = dataTypeOptional.get();
+        String model = dataType.getModel();
+        Optional<DataTypeDataDefinition> propertyDataType = dataTypeOperation.getDataTypeByNameAndModel(propertyDefinitionDto.getType(), model);
+        if (propertyDataType.isEmpty()) {
+            if (model == null || model.isEmpty()) {
+                model = "SDC AID";
+            }
+            throw new OperationException(ActionStatus.INVALID_MODEL,
+                String.format("Property model is not the same as the data type model. Must be be '%s'", model));
+        }
         final PropertyDefinitionDto property = dataTypeOperation.createProperty(id, propertyDefinitionDto);
+        dataTypeOperation.addPropertyToAdditionalTypeDataType(dataType, property);
         dataTypeBusinessLogic.updateApplicationDataTypeCache(id);
         return Response.status(Status.CREATED).entity(property).build();
     }
index 7d01f3f..103221c 100644 (file)
@@ -50,6 +50,7 @@ import org.openecomp.sdc.be.model.PropertyDefinition;
 import org.openecomp.sdc.be.model.dto.PropertyDefinitionDto;
 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.OperationException;
 import org.openecomp.sdc.be.model.mapper.PropertyDefinitionDtoMapper;
+import org.openecomp.sdc.be.model.normatives.ElementTypeEnum;
 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
 import org.openecomp.sdc.be.resources.data.DataTypeData;
 import org.openecomp.sdc.be.resources.data.PropertyData;
@@ -279,4 +280,8 @@ public class DataTypeOperation extends AbstractOperation {
         return PropertyDefinitionDtoMapper.mapFrom(propertyDataDefinition);
     }
 
+    public void addPropertyToAdditionalTypeDataType(DataTypeDataDefinition dataTypeDataDefinition, PropertyDefinitionDto property) {
+        modelOperation.addPropertyToAdditionalType(ElementTypeEnum.DATA_TYPE, property, dataTypeDataDefinition.getModel(), dataTypeDataDefinition.getName());
+    }
+
 }
index 8baa9a7..2e35c30 100644 (file)
@@ -54,14 +54,15 @@ import org.openecomp.sdc.be.data.model.ToscaImportByModel;
 import org.openecomp.sdc.be.datatypes.enums.GraphPropertyEnum;
 import org.openecomp.sdc.be.datatypes.enums.ModelTypeEnum;
 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
-import org.openecomp.sdc.be.model.DataTypeDefinition;
 import org.openecomp.sdc.be.model.Model;
+import org.openecomp.sdc.be.model.dto.PropertyDefinitionDto;
 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.ModelOperationExceptionSupplier;
 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.OperationException;
 import org.openecomp.sdc.be.model.normatives.ElementTypeEnum;
 import org.openecomp.sdc.be.model.operations.api.DerivedFromOperation;
 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
 import org.openecomp.sdc.be.resources.data.ModelData;
+import org.openecomp.sdc.be.utils.TypeUtils;
 import org.openecomp.sdc.common.log.enums.EcompLoggerErrorCode;
 import org.openecomp.sdc.common.log.wrappers.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -424,10 +425,69 @@ public class ModelOperation {
         final List<ToscaImportByModel> modelImportList = toscaModelImportCassandraDao.findAllByModel(modelName);
         return modelImportList.stream().filter(t -> ADDITIONAL_TYPE_DEFINITIONS_PATH.equals(Path.of(t.getFullPath()))).findAny();
     }
-    
+
     private Map<String, Object> getExistingTypes(final ElementTypeEnum elementTypeEnum, final ToscaImportByModel additionalTypeDefinitionsImport) {
         final Map<String, Object> existingContent = new Yaml().load(additionalTypeDefinitionsImport.getContent());
         return  (Map<String, Object>) existingContent.get(elementTypeEnum.getToscaEntryName());
     }
 
+    public void addPropertyToAdditionalType(final ElementTypeEnum elementTypeEnum, final PropertyDefinitionDto property,
+                                            final String modelName, final String name) {
+        final List<ToscaImportByModel> modelImportList = toscaModelImportCassandraDao.findAllByModel(modelName);
+        final Optional<ToscaImportByModel> additionalTypeDefinitionsImportOptional = modelImportList.stream()
+                .filter(t -> ADDITIONAL_TYPE_DEFINITIONS_PATH.equals(Path.of(t.getFullPath()))).findAny();
+        final ToscaImportByModel additionalTypeDefinitionsImport;
+        final List<ToscaImportByModel> rebuiltModelImportList;
+        if (additionalTypeDefinitionsImportOptional.isEmpty()) {
+            return;
+        }
+        additionalTypeDefinitionsImport = additionalTypeDefinitionsImportOptional.get();
+        rebuiltModelImportList = modelImportList.stream()
+                .filter(toscaImportByModel -> !ADDITIONAL_TYPE_DEFINITIONS_PATH.equals(Path.of(toscaImportByModel.getFullPath())))
+                .collect(Collectors.toList());
+        final Map<String, Object> originalContent = new Yaml().load(additionalTypeDefinitionsImport.getContent());
+        additionalTypeDefinitionsImport.setContent(buildPropertyAdditionalTypeDefinitionContent(elementTypeEnum, name, property, originalContent));
+        rebuiltModelImportList.add(additionalTypeDefinitionsImport);
+        toscaModelImportCassandraDao.saveAll(modelName, rebuiltModelImportList);
+    }
+
+    private String buildPropertyAdditionalTypeDefinitionContent(final ElementTypeEnum elementTypeEnum, final String name,
+                                                                final PropertyDefinitionDto property, final Map<String, Object> originalContent) {
+        final Map<String, Object> originalTypeContent = (Map<String, Object>) originalContent.get(elementTypeEnum.getToscaEntryName());
+        Map<String, Object> typeContent = (Map<String, Object>) originalTypeContent.get(name);
+        Map<String, Object> typeProperties = (Map<String, Object>) typeContent.get("properties");
+        if (typeProperties == null) {
+            typeProperties = new HashMap<>();
+        }
+        Map<String, Object> typeProp = constructProperty(property);
+        typeProperties.put(property.getName(), typeProp);
+        typeContent.put("properties", typeProperties);
+        return new YamlUtil().objectToYaml(originalContent);
+    }
+
+    private Map<String, Object> constructProperty(final PropertyDefinitionDto property) {
+        Map<String, Object> typeProp = new HashMap<>();
+        if (property.getType() != null) {
+            typeProp.put(TypeUtils.ToscaTagNamesEnum.TYPE.getElementName(), property.getType());
+        }
+        if (property.getDescription() != null) {
+            typeProp.put(TypeUtils.ToscaTagNamesEnum.DESCRIPTION.getElementName(), property.getDescription());
+        }
+        Map<String, Object> schema = new HashMap<>();
+        if (property.getSchemaType() != null) {
+            schema.put(TypeUtils.ToscaTagNamesEnum.TYPE.getElementName(), property.getSchemaType());
+            typeProp.put(TypeUtils.ToscaTagNamesEnum.ENTRY_SCHEMA.getElementName(), schema);
+        }
+        if (property.getDefaultValue() != null) {
+            typeProp.put(TypeUtils.ToscaTagNamesEnum.DEFAULT.getElementName(), property.getDefaultValue());
+        }
+        if (property.getRequired() != null) {
+            typeProp.put(TypeUtils.ToscaTagNamesEnum.REQUIRED.getElementName(), property.getRequired());
+        }
+        if (property.getConstraints() != null) {
+            typeProp.put(TypeUtils.ToscaTagNamesEnum.CONSTRAINTS.getElementName(), property.getConstraints());
+        }
+        return typeProp;
+    }
+
 }
index acff2a3..8fe8921 100644 (file)
@@ -16,6 +16,7 @@
  *  SPDX-License-Identifier: Apache-2.0
  *  ============LICENSE_END=========================================================
  */
+
 package org.openecomp.sdc.be.model.operations.impl;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -43,6 +44,7 @@ import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
@@ -72,6 +74,7 @@ import org.openecomp.sdc.be.datatypes.enums.ModelTypeEnum;
 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
 import org.openecomp.sdc.be.model.Model;
 import org.openecomp.sdc.be.model.ModelTestBase;
+import org.openecomp.sdc.be.model.dto.PropertyDefinitionDto;
 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.ModelOperationExceptionSupplier;
 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.OperationException;
 import org.openecomp.sdc.be.model.normatives.ElementTypeEnum;
@@ -504,26 +507,27 @@ class ModelOperationTest extends ModelTestBase {
         final ToscaImportByModel actualImport1 = actualImportList.stream().filter(expectedImport1::equals).findFirst().orElse(null);
         assertNotNull(actualImport1);
         assertEquals(expectedImport1.getContent(), actualImport1.getContent());
-        
+
         // Update the added additional type
         final var updatedDataTypesPath = testResourcePath.resolve(Path.of("input-data_types-updated.yaml"));
         final var updatedDataTypes = Files.readString(updatedDataTypesPath);
         modelOperation.updateTypesInAdditionalTypesImport(ElementTypeEnum.DATA_TYPE, updatedDataTypes, modelName);
-        
+
         ArgumentCaptor<List<ToscaImportByModel>> updatedImportListArgumentCaptor = ArgumentCaptor.forClass(List.class);
         verify(toscaModelImportCassandraDao, times(2)).saveAll(eq(modelName), updatedImportListArgumentCaptor.capture());
 
         final List<ToscaImportByModel> updatedActualImportList = updatedImportListArgumentCaptor.getValue();
         assertEquals(2, updatedActualImportList.size());
-        
+
         var expectedUpdatedAdditionalTypesImport = new ToscaImportByModel();
         expectedUpdatedAdditionalTypesImport.setModelId(modelName);
         expectedUpdatedAdditionalTypesImport.setFullPath(ADDITIONAL_TYPE_DEFINITIONS_PATH.toString());
-        expectedUpdatedAdditionalTypesImport.setContent(Files.readString(testResourcePath.resolve(Path.of("expected-additional_types-2-updated.yaml"))));
+        expectedUpdatedAdditionalTypesImport.setContent(
+            Files.readString(testResourcePath.resolve(Path.of("expected-additional_types-2-updated.yaml"))));
         final ToscaImportByModel actualUpdatedAdditionalTypesImport =
             actualImportList.stream().filter(expectedUpdatedAdditionalTypesImport::equals).findFirst().orElse(null);
         assertNotNull(actualUpdatedAdditionalTypesImport);
-        
+
         assertTrue(actualUpdatedAdditionalTypesImport.getContent().contains("added_property_1"));
         assertTrue(actualUpdatedAdditionalTypesImport.getContent().contains("added_property_2"));
     }
@@ -582,6 +586,50 @@ class ModelOperationTest extends ModelTestBase {
 
     }
 
+    @Test
+    void addPropertyToExistingAdditionalType() throws IOException {
+        var modelName = "model";
+        final Path testResourcePath = Path.of("src/test/resources/modelOperation");
+
+        var originalAdditionalTypesImport = new ToscaImportByModel();
+        originalAdditionalTypesImport.setModelId(modelName);
+        originalAdditionalTypesImport.setFullPath(ADDITIONAL_TYPE_DEFINITIONS_PATH.toString());
+        final Path originalAdditionalTypesImportPath = testResourcePath.resolve(Path.of("original-additional_types-1.yaml"));
+        originalAdditionalTypesImport.setContent(Files.readString(originalAdditionalTypesImportPath));
+
+        final List<ToscaImportByModel> modelImports = new ArrayList<>();
+        modelImports.add(originalAdditionalTypesImport);
+        when(toscaModelImportCassandraDao.findAllByModel(modelName)).thenReturn(modelImports);
+
+        PropertyDefinitionDto property = new PropertyDefinitionDto();
+        property.setName("addedMapProperty");
+        property.setType("map");
+        property.setSchemaType("string");
+        property.setDescription("This is a description");
+        Map<Object, Object> defaultValue = new HashMap<>();
+        defaultValue.put("k1", "v1");
+        defaultValue.put("k2", "v2");
+        property.setDefaultValue(defaultValue);
+        property.setRequired(true);
+
+        String dataTypeName = "tosca.datatypes.nfv.PreviouslyExistingType1";
+        modelOperation.addPropertyToAdditionalType(ElementTypeEnum.DATA_TYPE, property, modelName, dataTypeName);
+        ArgumentCaptor<List<ToscaImportByModel>> importListArgumentCaptor = ArgumentCaptor.forClass(List.class);
+        verify(toscaModelImportCassandraDao).saveAll(eq(modelName), importListArgumentCaptor.capture());
+
+        final List<ToscaImportByModel> actualImportList = importListArgumentCaptor.getValue();
+        assertEquals(1, actualImportList.size());
+
+        var expectedAdditionalTypesImport = new ToscaImportByModel();
+        expectedAdditionalTypesImport.setModelId(modelName);
+        expectedAdditionalTypesImport.setFullPath(ADDITIONAL_TYPE_DEFINITIONS_PATH.toString());
+        expectedAdditionalTypesImport.setContent(Files.readString(testResourcePath.resolve(Path.of("expected-additional_types-4.yaml"))));
+        final ToscaImportByModel actualAdditionalTypesImport =
+            actualImportList.stream().filter(expectedAdditionalTypesImport::equals).findFirst().orElse(null);
+        assertNotNull(actualAdditionalTypesImport);
+        assertEquals(expectedAdditionalTypesImport.getContent(), actualAdditionalTypesImport.getContent());
+    }
+
     private ToscaImportByModel createModelImport(final String parentModelName, final String importPath) {
         var toscaImportByModel = new ToscaImportByModel();
         toscaImportByModel.setModelId(parentModelName);
diff --git a/catalog-model/src/test/resources/modelOperation/expected-additional_types-4.yaml b/catalog-model/src/test/resources/modelOperation/expected-additional_types-4.yaml
new file mode 100644 (file)
index 0000000..2d8fb24
--- /dev/null
@@ -0,0 +1,20 @@
+tosca_definitions_version: tosca_simple_yaml_1_3
+description: Auto-generated file that contains package custom types or types added
+  after system installation.
+data_types:
+  tosca.datatypes.nfv.PreviouslyExistingType1:
+    derived_from: tosca.datatypes.Root
+    description: additional type
+    properties:
+      addedMapProperty:
+        default:
+          k1: v1
+          k2: v2
+        entry_schema:
+          type: string
+        description: This is a description
+        type: map
+        required: true
+  tosca.datatypes.nfv.PreviouslyExistingType2:
+    derived_from: tosca.datatypes.Root
+    description: additional type