Allow updating of cmHandles with an alternateId 18/136918/13
authorleventecsanyi <levente.csanyi@est.tech>
Thu, 4 Jan 2024 09:06:00 +0000 (10:06 +0100)
committerleventecsanyi <levente.csanyi@est.tech>
Mon, 8 Jan 2024 09:52:57 +0000 (10:52 +0100)
  - added methods to update alternate id
  - fixed unit tests
  - added new unit test for coverage

Issue-ID: CPS-1986
Change-Id: I9ef717c5f2c405482e0a5bb70f94f465ba1ff64f
Signed-off-by: leventecsanyi <levente.csanyi@est.tech>
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandler.java
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandlerSpec.groovy

index be6a401..1520932 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2022-2023 Nordix Foundation
+ *  Copyright (C) 2022-2024 Nordix Foundation
  *  Modifications Copyright (C) 2022 Bell Canada
  *  Modifications Copyright (C) 2023 TechMahindra Ltd.
  *  ================================================================================
@@ -26,10 +26,15 @@ import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLES_NOT_FOUND;
 import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLE_INVALID_ID;
 import static org.onap.cps.ncmp.api.impl.NetworkCmProxyDataServicePropertyHandler.PropertyType.DMI_PROPERTY;
 import static org.onap.cps.ncmp.api.impl.NetworkCmProxyDataServicePropertyHandler.PropertyType.PUBLIC_PROPERTY;
+import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME;
+import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR;
+import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_PARENT;
 
 import com.google.common.collect.ImmutableMap;
+import java.time.OffsetDateTime;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -38,13 +43,18 @@ import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.onap.cps.api.CpsDataService;
 import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence;
+import org.onap.cps.ncmp.api.impl.utils.YangDataConverter;
+import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
 import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse;
 import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
 import org.onap.cps.spi.exceptions.DataNodeNotFoundException;
 import org.onap.cps.spi.exceptions.DataValidationException;
 import org.onap.cps.spi.model.DataNode;
 import org.onap.cps.spi.model.DataNodeBuilder;
+import org.onap.cps.utils.JsonObjectMapper;
 import org.springframework.stereotype.Service;
 
 @Slf4j
@@ -55,6 +65,8 @@ import org.springframework.stereotype.Service;
 public class NetworkCmProxyDataServicePropertyHandler {
 
     private final InventoryPersistence inventoryPersistence;
+    private final CpsDataService cpsDataService;
+    private final JsonObjectMapper jsonObjectMapper;
 
     /**
      * Iterates over incoming ncmpServiceCmHandles and update the dataNodes based on the updated attributes.
@@ -70,6 +82,7 @@ public class NetworkCmProxyDataServicePropertyHandler {
             try {
                 final DataNode existingCmHandleDataNode = inventoryPersistence.getCmHandleDataNode(cmHandleId)
                         .iterator().next();
+                updateAlternateId(existingCmHandleDataNode, ncmpServiceCmHandle);
                 processUpdates(existingCmHandleDataNode, ncmpServiceCmHandle);
                 cmHandleRegistrationResponses.add(CmHandleRegistrationResponse.createSuccessResponse(cmHandleId));
             } catch (final DataNodeNotFoundException e) {
@@ -89,6 +102,26 @@ public class NetworkCmProxyDataServicePropertyHandler {
         return cmHandleRegistrationResponses;
     }
 
+    private void updateAlternateId(final DataNode existingCmHandleDataNode,
+                                   final NcmpServiceCmHandle ncmpServiceCmHandle) {
+        final String newAlternateId = ncmpServiceCmHandle.getAlternateId();
+        if (!StringUtils.isEmpty(newAlternateId)) {
+            final String existingAlternateId = (String) existingCmHandleDataNode.getLeaves().get("alternate-id");
+            if (StringUtils.isEmpty(existingAlternateId)) {
+                final YangModelCmHandle yangModelCmHandle =
+                        YangDataConverter.convertCmHandleToYangModel(existingCmHandleDataNode,
+                                ncmpServiceCmHandle.getCmHandleId());
+                setAndUpdateAlternateId(yangModelCmHandle, newAlternateId);
+            } else {
+                if (!newAlternateId.equals(existingAlternateId)) {
+                    log.warn("Unable to update alternateId for cmHandle {}. "
+                                    + "Value for alternateId has been set previously.",
+                            ncmpServiceCmHandle.getCmHandleId());
+                }
+            }
+        }
+    }
+
     private void processUpdates(final DataNode existingCmHandleDataNode, final NcmpServiceCmHandle incomingCmHandle) {
         if (!incomingCmHandle.getPublicProperties().isEmpty()) {
             updateProperties(existingCmHandleDataNode, PUBLIC_PROPERTY, incomingCmHandle.getPublicProperties());
@@ -165,6 +198,17 @@ public class NetworkCmProxyDataServicePropertyHandler {
         return new DataNodeBuilder().withXpath(xpath).withLeaves(ImmutableMap.copyOf(updatedLeaves)).build();
     }
 
+    private void setAndUpdateAlternateId(final YangModelCmHandle upgradedCmHandle, final String alternateId) {
+        final Map<String, Map<String, String>> dmiRegistryProperties = new HashMap<>(1);
+        final Map<String, String> cmHandleProperties = new HashMap<>(2);
+        cmHandleProperties.put("id", upgradedCmHandle.getId());
+        cmHandleProperties.put("alternate-id", alternateId);
+        dmiRegistryProperties.put("cm-handles", cmHandleProperties);
+        cpsDataService.updateNodeLeaves(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, NCMP_DMI_REGISTRY_PARENT,
+                jsonObjectMapper.asJsonString(dmiRegistryProperties), OffsetDateTime.now());
+        log.info("Updating alternateId for cmHandle {} with value : {})", upgradedCmHandle.getId(), alternateId);
+    }
+
     enum PropertyType {
         DMI_PROPERTY("additional-properties"), PUBLIC_PROPERTY("public-properties");
 
index 6439f0b..2a15e6c 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * ============LICENSE_START=======================================================
- * Copyright (C) 2022-2023 Nordix Foundation
+ * Copyright (C) 2022-2024 Nordix Foundation
  * Modifications Copyright (C) 2022 Bell Canada
  * Modifications Copyright (C) 2023 TechMahindra Ltd.
  * ================================================================================
 
 package org.onap.cps.ncmp.api.impl
 
+import ch.qos.logback.classic.Level
+import ch.qos.logback.classic.Logger
+import ch.qos.logback.classic.spi.ILoggingEvent
+import com.fasterxml.jackson.databind.ObjectMapper
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.BeforeEach
+import org.slf4j.LoggerFactory
+
 import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME
 import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR
 import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLES_NOT_FOUND
@@ -29,6 +37,9 @@ import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLE_INVALID_ID
 import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNKNOWN_ERROR
 import static org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.Status
 
+import ch.qos.logback.core.read.ListAppender
+import org.onap.cps.api.CpsDataService
+import org.onap.cps.utils.JsonObjectMapper
 import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence
 import org.onap.cps.spi.exceptions.DataValidationException
 import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
@@ -40,8 +51,22 @@ import spock.lang.Specification
 class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification {
 
     def mockInventoryPersistence = Mock(InventoryPersistence)
+    def mockCpsDataService = Mock(CpsDataService)
+    def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper())
+    def logger = Spy(ListAppender<ILoggingEvent>)
+
+    @BeforeEach
+    void setup() {
+        ((Logger) LoggerFactory.getLogger(NetworkCmProxyDataServicePropertyHandler.class)).addAppender(logger);
+        logger.start();
+    }
 
-    def objectUnderTest = new NetworkCmProxyDataServicePropertyHandler(mockInventoryPersistence)
+    @AfterEach
+    void teardown() {
+        ((Logger) LoggerFactory.getLogger(NetworkCmProxyDataServicePropertyHandler.class)).detachAndStopAllAppenders();
+    }
+
+    def objectUnderTest = new NetworkCmProxyDataServicePropertyHandler(mockInventoryPersistence, mockCpsDataService, jsonObjectMapper)
     def static cmHandleId = 'myHandle1'
     def static cmHandleXpath = "/dmi-registry/cm-handles[@id='${cmHandleId}']"
 
@@ -173,6 +198,38 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification {
             2 * mockInventoryPersistence.replaceListContent(cmHandleXpath,_)
     }
 
+    def 'Update CM Handle Alternate ID when #scenario'() {
+        given: 'an existing cm handle with alternate id #existingAlternateId'
+            DataNode existingCmHandleDataNode = new DataNode(xpath: cmHandleXpath, leaves: ['alternate-id': oldAlternateId])
+        and: 'an update request with an alternate id #newAlternateId'
+            def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, alternateId: newAlternateId)
+        when: 'update data node leaves is called with the update request'
+            objectUnderTest.updateAlternateId(existingCmHandleDataNode, ncmpServiceCmHandle)
+        then: 'the update node leaves method is invoked as many times as expected'
+            numberOfInvocations * mockCpsDataService.updateNodeLeaves('NCMP-Admin', 'ncmp-dmi-registry', '/dmi-registry', _, _) >> { args ->
+                assert args[3].contains(newAlternateId)
+            }
+        and: 'correct information is logged'
+            def lastLoggingEvent = logger.list[0]
+            if (expectLogWarning) {
+                assert lastLoggingEvent.level == Level.WARN
+                assert lastLoggingEvent.formattedMessage.contains('Unable')
+            } else if (numberOfInvocations == 1) {
+                assert lastLoggingEvent.level == Level.INFO
+                assert lastLoggingEvent.formattedMessage.contains('Updating alternateId')
+            } else {
+                assert lastLoggingEvent == null
+            }
+        where: 'following updates are attempted'
+            scenario                     | oldAlternateId | newAlternateId || numberOfInvocations | expectLogWarning
+            'old alternate id null'      | null           | 'new'          || 1                   | false
+            'old alternate id empty'     | ''             | 'new'          || 1                   | false
+            'old alternate id not empty' | 'old'          | 'new'          || 0                   | true
+            'same alternate id'          | 'old'          | 'old'          || 0                   | false
+            'empty new alternate id'     | 'old'          | ''             || 0                   | false
+            'null new alternate id'      | 'old'          | null           || 0                   | false
+    }
+
     def convertToProperties(expectedPropertiesAfterUpdateAsMap) {
         def properties = [].withDefault { [:] }
         expectedPropertiesAfterUpdateAsMap.forEach(property ->
@@ -181,5 +238,4 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification {
             }))
         return properties
     }
-
 }