Error reporting when registering cm handle with alternate id 2 - update scenario 71/137371/10
authorhalil.cakal <halil.cakal@est.tech>
Tue, 5 Mar 2024 17:15:42 +0000 (17:15 +0000)
committerhalil.cakal <halil.cakal@est.tech>
Tue, 5 Mar 2024 17:15:42 +0000 (17:15 +0000)
    - added error collection to cmhandle update

Issue-ID: CPS-2109
Change-Id: I751cad7c35ec53e914888760dd66eb52054da36e
Signed-off-by: halil.cakal <halil.cakal@est.tech>
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandler.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/AlternateIdChecker.java
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandlerSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/AlternateIdCheckerSpec.groovy

index 3e304a4..42076a4 100755 (executable)
@@ -423,7 +423,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
         final List<NcmpServiceCmHandle> cmHandlesToBeCreated,
         final List<CmHandleRegistrationResponse> cmHandleRegistrationResponses) {
         final Collection<String> rejectedCmHandleIds = alternateIdChecker
-            .getIdsOfCmHandlesWithRejectedAlternateId(cmHandlesToBeCreated);
+            .getIdsOfCmHandlesWithRejectedAlternateId(cmHandlesToBeCreated, AlternateIdChecker.Operation.CREATE);
         cmHandleRegistrationResponses.addAll(CmHandleRegistrationResponse.createFailureResponses(
             rejectedCmHandleIds, ALTERNATE_ID_ALREADY_ASSOCIATED));
         return rejectedCmHandleIds;
index f5d22af..3d15291 100644 (file)
@@ -22,6 +22,7 @@
 
 package org.onap.cps.ncmp.api.impl;
 
+import static org.onap.cps.ncmp.api.NcmpResponseStatus.ALTERNATE_ID_ALREADY_ASSOCIATED;
 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;
@@ -46,8 +47,6 @@ import lombok.extern.slf4j.Slf4j;
 import org.onap.cps.api.CpsDataService;
 import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence;
 import org.onap.cps.ncmp.api.impl.utils.AlternateIdChecker;
-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;
@@ -70,67 +69,76 @@ public class NetworkCmProxyDataServicePropertyHandler {
     private final AlternateIdChecker alternateIdChecker;
 
     /**
-     * Iterates over incoming ncmpServiceCmHandles and update the dataNodes based on the updated attributes.
+     * Iterates over incoming updatedNcmpServiceCmHandles and update the dataNodes based on the updated attributes.
      * The attributes which are not passed will remain as is.
      *
-     * @param ncmpServiceCmHandles collection of ncmpServiceCmHandles
+     * @param updatedNcmpServiceCmHandles collection of CmHandles
      */
     public List<CmHandleRegistrationResponse> updateCmHandleProperties(
-        final Collection<NcmpServiceCmHandle> ncmpServiceCmHandles) {
-        final List<CmHandleRegistrationResponse> cmHandleRegistrationResponses
-            = new ArrayList<>(ncmpServiceCmHandles.size());
-        for (final NcmpServiceCmHandle ncmpServiceCmHandle : ncmpServiceCmHandles) {
-            final String cmHandleId = ncmpServiceCmHandle.getCmHandleId();
-            try {
-                final DataNode existingCmHandleDataNode = inventoryPersistence
-                    .getCmHandleDataNodeByCmHandleId(cmHandleId).iterator().next();
-                updateAlternateId(existingCmHandleDataNode, ncmpServiceCmHandle);
-                processUpdates(existingCmHandleDataNode, ncmpServiceCmHandle);
-                cmHandleRegistrationResponses.add(CmHandleRegistrationResponse.createSuccessResponse(cmHandleId));
-            } catch (final DataNodeNotFoundException e) {
-                log.error("Unable to find dataNode for cmHandleId : {} , caused by : {}", cmHandleId, e.getMessage());
-                cmHandleRegistrationResponses.add(
-                    CmHandleRegistrationResponse.createFailureResponse(cmHandleId, CM_HANDLES_NOT_FOUND));
-            } catch (final DataValidationException e) {
-                log.error("Unable to update cm handle : {}, caused by : {}", cmHandleId, e.getMessage());
-                cmHandleRegistrationResponses.add(
-                    CmHandleRegistrationResponse.createFailureResponse(cmHandleId, CM_HANDLE_INVALID_ID));
-            } catch (final Exception exception) {
-                log.error("Unable to update cmHandle : {} , caused by : {}", cmHandleId, exception.getMessage());
-                cmHandleRegistrationResponses.add(
-                    CmHandleRegistrationResponse.createFailureResponse(cmHandleId, exception));
+            final Collection<NcmpServiceCmHandle> updatedNcmpServiceCmHandles) {
+        final Collection<String> rejectedCmHandleIds = alternateIdChecker
+            .getIdsOfCmHandlesWithRejectedAlternateId(updatedNcmpServiceCmHandles, AlternateIdChecker.Operation.UPDATE);
+        final List<CmHandleRegistrationResponse> failureResponses =
+            CmHandleRegistrationResponse.createFailureResponses(rejectedCmHandleIds, ALTERNATE_ID_ALREADY_ASSOCIATED);
+        final List<CmHandleRegistrationResponse> cmHandleRegistrationResponses = new ArrayList<>(failureResponses);
+        for (final NcmpServiceCmHandle updatedNcmpServiceCmHandle : updatedNcmpServiceCmHandles) {
+            final String cmHandleId = updatedNcmpServiceCmHandle.getCmHandleId();
+            if (!rejectedCmHandleIds.contains(cmHandleId)) {
+                try {
+                    final DataNode existingCmHandleDataNode = inventoryPersistence
+                            .getCmHandleDataNodeByCmHandleId(cmHandleId).iterator().next();
+                    processUpdates(existingCmHandleDataNode, updatedNcmpServiceCmHandle);
+                    cmHandleRegistrationResponses.add(CmHandleRegistrationResponse.createSuccessResponse(cmHandleId));
+                } catch (final DataNodeNotFoundException e) {
+                    log.error("Unable to find dataNode for cmHandleId : {} , caused by : {}", cmHandleId,
+                            e.getMessage());
+                    cmHandleRegistrationResponses.add(
+                            CmHandleRegistrationResponse.createFailureResponse(cmHandleId, CM_HANDLES_NOT_FOUND));
+                } catch (final DataValidationException e) {
+                    log.error("Unable to update cm handle : {}, caused by : {}", cmHandleId, e.getMessage());
+                    cmHandleRegistrationResponses.add(
+                            CmHandleRegistrationResponse.createFailureResponse(cmHandleId, CM_HANDLE_INVALID_ID));
+                } catch (final Exception exception) {
+                    log.error("Unable to update cmHandle : {} , caused by : {}", cmHandleId, exception.getMessage());
+                    cmHandleRegistrationResponses.add(
+                            CmHandleRegistrationResponse.createFailureResponse(cmHandleId, exception));
+                }
             }
         }
         return cmHandleRegistrationResponses;
     }
 
-    private void updateAlternateId(final DataNode existingCmHandleDataNode,
-                                   final NcmpServiceCmHandle ncmpServiceCmHandle) {
-        final YangModelCmHandle yangModelCmHandle =
-            YangDataConverter.convertCmHandleToYangModel(existingCmHandleDataNode);
-        final String currentAlternateId = yangModelCmHandle.getAlternateId();
-        final String newAlternateId = ncmpServiceCmHandle.getAlternateId();
-        if (alternateIdChecker.canApplyAlternateId(ncmpServiceCmHandle.getCmHandleId(),
-            currentAlternateId, newAlternateId)) {
-            setAndUpdateAlternateId(yangModelCmHandle, newAlternateId);
+    private void processUpdates(final DataNode existingCmHandleDataNode,
+                                final NcmpServiceCmHandle updatedNcmpServiceCmHandle) {
+        updateAlternateId(updatedNcmpServiceCmHandle);
+        if (!updatedNcmpServiceCmHandle.getPublicProperties().isEmpty()) {
+            updateProperties(existingCmHandleDataNode, PUBLIC_PROPERTY,
+                updatedNcmpServiceCmHandle.getPublicProperties());
+        }
+        if (!updatedNcmpServiceCmHandle.getDmiProperties().isEmpty()) {
+            updateProperties(existingCmHandleDataNode, DMI_PROPERTY, updatedNcmpServiceCmHandle.getDmiProperties());
         }
     }
 
-    private void processUpdates(final DataNode existingCmHandleDataNode, final NcmpServiceCmHandle incomingCmHandle) {
-        if (!incomingCmHandle.getPublicProperties().isEmpty()) {
-            updateProperties(existingCmHandleDataNode, PUBLIC_PROPERTY, incomingCmHandle.getPublicProperties());
-        }
-        if (!incomingCmHandle.getDmiProperties().isEmpty()) {
-            updateProperties(existingCmHandleDataNode, DMI_PROPERTY, incomingCmHandle.getDmiProperties());
-        }
+    private void updateAlternateId(final NcmpServiceCmHandle updatedNcmpServiceCmHandle) {
+        final String updatedAlternateId = updatedNcmpServiceCmHandle.getAlternateId();
+        final String cmHandleId = updatedNcmpServiceCmHandle.getCmHandleId();
+        final Map<String, String> cmHandleProperties = new HashMap<>(2);
+        cmHandleProperties.put("id", cmHandleId);
+        cmHandleProperties.put("alternate-id", updatedAlternateId);
+        final Map<String, Map<String, String>> dmiRegistryProperties = new HashMap<>(1);
+        dmiRegistryProperties.put("cm-handles", cmHandleProperties);
+        cpsDataService.updateNodeLeaves(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, NCMP_DMI_REGISTRY_PARENT,
+                jsonObjectMapper.asJsonString(dmiRegistryProperties), OffsetDateTime.now());
+        log.debug("Updating alternateId for cmHandle {} with value : {})", cmHandleId, updatedAlternateId);
     }
 
     private void updateProperties(final DataNode existingCmHandleDataNode, final PropertyType propertyType,
-            final Map<String, String> incomingProperties) {
+                                  final Map<String, String> updatedProperties) {
         final Collection<DataNode> replacementPropertyDataNodes =
-                getReplacementDataNodes(existingCmHandleDataNode, propertyType, incomingProperties);
+                getReplacementDataNodes(existingCmHandleDataNode, propertyType, updatedProperties);
         replacementPropertyDataNodes.addAll(
-                getUnchangedPropertyDataNodes(existingCmHandleDataNode, propertyType, incomingProperties));
+                getUnchangedPropertyDataNodes(existingCmHandleDataNode, propertyType, updatedProperties));
         if (replacementPropertyDataNodes.isEmpty()) {
             removeAllProperties(existingCmHandleDataNode, propertyType);
         } else {
@@ -149,13 +157,14 @@ public class NetworkCmProxyDataServicePropertyHandler {
     }
 
     private Collection<DataNode> getUnchangedPropertyDataNodes(final DataNode existingCmHandleDataNode,
-            final PropertyType propertyType, final Map<String, String> incomingProperties) {
+                                                               final PropertyType propertyType,
+                                                               final Map<String, String> updatedProperties) {
         final Collection<DataNode> unchangedPropertyDataNodes = new HashSet<>();
         for (final DataNode existingPropertyDataNode : existingCmHandleDataNode.getChildDataNodes()) {
             final Matcher matcher = propertyType.propertyXpathPattern.matcher(existingPropertyDataNode.getXpath());
             if (matcher.find()) {
                 final String keyName = matcher.group(2);
-                if (!incomingProperties.containsKey(keyName)) {
+                if (!updatedProperties.containsKey(keyName)) {
                     unchangedPropertyDataNodes.add(existingPropertyDataNode);
                 }
             }
@@ -164,9 +173,10 @@ public class NetworkCmProxyDataServicePropertyHandler {
     }
 
     private Collection<DataNode> getReplacementDataNodes(final DataNode existingCmHandleDataNode,
-            final PropertyType propertyType, final Map<String, String> incomingProperties) {
+                                                         final PropertyType propertyType,
+                                                         final Map<String, String> updatedProperties) {
         final Collection<DataNode> replacementPropertyDataNodes = new HashSet<>();
-        incomingProperties.forEach((updatedAttributeKey, updatedAttributeValue) -> {
+        updatedProperties.forEach((updatedAttributeKey, updatedAttributeValue) -> {
             final String propertyXpath = getAttributeXpath(existingCmHandleDataNode, propertyType, updatedAttributeKey);
             if (updatedAttributeValue != null) {
                 log.info("Creating a new DataNode with xpath {} , key : {} and value : {}", propertyXpath,
@@ -179,7 +189,7 @@ public class NetworkCmProxyDataServicePropertyHandler {
     }
 
     private String getAttributeXpath(final DataNode cmHandle, final PropertyType propertyType,
-            final String attributeKey) {
+                                     final String attributeKey) {
         return cmHandle.getXpath() + "/" + propertyType.xpathPrefix + String.format("[@name='%s']", attributeKey);
     }
 
@@ -192,17 +202,6 @@ 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 4ac6537..f14439f 100644 (file)
@@ -38,6 +38,10 @@ import org.springframework.stereotype.Service;
 @RequiredArgsConstructor
 public class AlternateIdChecker {
 
+    public enum Operation {
+        CREATE, UPDATE
+    }
+
     private final InventoryPersistence inventoryPersistence;
 
     private static final String NO_CURRENT_ALTERNATE_ID = "";
@@ -96,15 +100,16 @@ public class AlternateIdChecker {
     }
 
     /**
-     * Check all alternate ids of a batch of NEW cm handles.
+     * Check all alternate ids of a batch of cm handles.
      * Includes cross-checks in the batch itself for duplicates. Only the first entry encountered wil be accepted.
-     * This method can only be used for NEW cm handle registrations NOT for updating existing ones
      *
      * @param newNcmpServiceCmHandles the proposed new cm handles
+     * @param operation type of operation being executed
      * @return collection of cm handles ids which are acceptable
      */
     public Collection<String> getIdsOfCmHandlesWithRejectedAlternateId(
-                                    final Collection<NcmpServiceCmHandle> newNcmpServiceCmHandles) {
+                                    final Collection<NcmpServiceCmHandle> newNcmpServiceCmHandles,
+                                    final Operation operation) {
         final Set<String> acceptedAlternateIds = new HashSet<>(newNcmpServiceCmHandles.size());
         final Collection<String> rejectedCmHandleIds = new ArrayList<>();
         for (final NcmpServiceCmHandle ncmpServiceCmHandle : newNcmpServiceCmHandles) {
@@ -119,7 +124,11 @@ public class AlternateIdChecker {
                     log.warn("Alternate id update ignored, cannot update cm handle {}, alternate id is already "
                         + "assigned to a different cm handle (in this batch)", cmHandleId);
                 } else {
-                    isAcceptable = canApplyAlternateId(cmHandleId, NO_CURRENT_ALTERNATE_ID, proposedAlternateId);
+                    if (Operation.CREATE.equals(operation)) {
+                        isAcceptable = canApplyAlternateId(cmHandleId, NO_CURRENT_ALTERNATE_ID, proposedAlternateId);
+                    } else {
+                        isAcceptable = canApplyAlternateId(cmHandleId, proposedAlternateId);
+                    }
                 }
             }
             if (isAcceptable) {
index cb7e1ef..fbfbac5 100644 (file)
@@ -78,7 +78,7 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
 
     def setup() {
         // always accept all cm handles
-        mockAlternateIdChecker.getIdsOfCmHandlesWithRejectedAlternateId(_) >> []
+        mockAlternateIdChecker.getIdsOfCmHandlesWithRejectedAlternateId(*_) >> []
 
         // always can find all cm handles in DB
         mockInventoryPersistence.getYangModelCmHandles(_) >> { args -> args[0].collect { new YangModelCmHandle(id:it) } }
@@ -418,14 +418,4 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
         'an unexpected exception'    | 'cmhandle'             | new RuntimeException('Failed')            || UNKNOWN_ERROR        | 'Failed'
     }
 
-    def 'Adding data to alternate id caches.'() {
-        given: 'a registration with three CM Handles to be created'
-            def ncmpServiceCmHandles = [new NcmpServiceCmHandle(cmHandleId: 'cmhandle1', alternateId: 'my-alternate-id-1')]
-            def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: 'my-server', createdCmHandles: ncmpServiceCmHandles)
-        when: 'the DMI plugin registration happens'
-            objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
-        then: 'the new alternate id is added to the cache'
-            1 * mockAlternateIdChecker.getIdsOfCmHandlesWithRejectedAlternateId(ncmpServiceCmHandles) >> ['cmhandle1']
-    }
-
 }
index 71380d4..5b3ffe5 100644 (file)
@@ -274,7 +274,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
             dmiPluginRegistration.createdCmHandles = [ncmpServiceCmHandle]
             mockDmiPluginRegistration.getCreatedCmHandles() >> [ncmpServiceCmHandle]
         and: 'no rejected cm handles because of alternate ids'
-            mockAlternateIdChecker.getIdsOfCmHandlesWithRejectedAlternateId(_) >> []
+            mockAlternateIdChecker.getIdsOfCmHandlesWithRejectedAlternateId(*_) >> []
         when: 'parse and create cm handle in dmi registration then sync module'
             mockDmiPluginRegistration.createdCmHandles = ['test-cm-handle-id']
             objectUnderTest.processCreatedCmHandles(mockDmiPluginRegistration, new DmiPluginRegistrationResponse())
index e00a426..cbed417 100644 (file)
@@ -49,6 +49,12 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification {
     def mockAlternateIdChecker = Mock(AlternateIdChecker)
 
     def objectUnderTest = new NetworkCmProxyDataServicePropertyHandler(mockInventoryPersistence, mockCpsDataService, jsonObjectMapper, mockAlternateIdChecker)
+
+    def setup() {
+        // Always accept all alternate IDs
+        mockAlternateIdChecker.getIdsOfCmHandlesWithRejectedAlternateId(*_) >> []
+    }
+
     def static cmHandleId = 'myHandle1'
     def static cmHandleXpath = "/dmi-registry/cm-handles[@id='${cmHandleId}']"
 
@@ -66,7 +72,7 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification {
         when: 'update data node leaves is called with the update request'
             objectUnderTest.updateCmHandleProperties(cmHandleUpdateRequest)
         then: 'the replace list method is called with correct params'
-            1 * mockInventoryPersistence.replaceListContent(cmHandleXpath,_) >> { args ->
+            1 * mockInventoryPersistence.replaceListContent(cmHandleXpath, _) >> { args ->
                 {
                     assert args[1].leaves.size() == expectedPropertiesAfterUpdate.size()
                     assert args[1].leaves.containsAll(convertToProperties(expectedPropertiesAfterUpdate))
@@ -142,10 +148,10 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification {
                 assert it.errorText == expectedErrorText
             }
         where:
-        scenario                   | cmHandleId               | exception                                                                                           || expectedError        | expectedErrorText
-        'Cm Handle does not exist' | 'cmHandleId'             | new DataNodeNotFoundException(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR)                        || CM_HANDLES_NOT_FOUND | 'cm handle id(s) not found'
-        'Unknown'                  | 'cmHandleId'             | new RuntimeException('Failed')                                                                      || UNKNOWN_ERROR        | 'Failed'
-        'Invalid cm handle id'     | 'cmHandleId with spaces' | new DataValidationException('Name Validation Error.', cmHandleId + 'contains an invalid character') || CM_HANDLE_INVALID_ID | 'cm-handle has an invalid character(s) in id'
+            scenario                   | cmHandleId               | exception                                                                                           || expectedError        | expectedErrorText
+            'Cm Handle does not exist' | 'cmHandleId'             | new DataNodeNotFoundException(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR)                        || CM_HANDLES_NOT_FOUND | 'cm handle id(s) not found'
+            'Unknown'                  | 'cmHandleId'             | new RuntimeException('Failed')                                                                      || UNKNOWN_ERROR        | 'Failed'
+            'Invalid cm handle id'     | 'cmHandleId with spaces' | new DataValidationException('Name Validation Error.', cmHandleId + 'contains an invalid character') || CM_HANDLE_INVALID_ID | 'cm-handle has an invalid character(s) in id'
     }
 
     def 'Multiple update operations in a single request'() {
@@ -177,42 +183,44 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification {
                 assert it.errorText == 'cm handle id(s) not found'
             }
         then: 'the replace list method is called twice'
-            2 * mockInventoryPersistence.replaceListContent(cmHandleXpath,_)
+            2 * mockInventoryPersistence.replaceListContent(cmHandleXpath, _)
     }
 
-    def 'Update CM Handle Alternate ID with #scenario'() {
-        given: 'an existing cm handle'
-            DataNode existingCmHandleDataNode = new DataNode(xpath: cmHandleXpath, leaves: ['id': cmHandleId])
-        and: 'an update request with an alternate id'
-            def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, alternateId: 'alt-1')
-        when: 'update alternate id method is called with the update request'
-            objectUnderTest.updateAlternateId(existingCmHandleDataNode, ncmpServiceCmHandle)
-        then: 'the update node leaves method is invoked as many times as expected'
-            callsToDataService * mockCpsDataService.updateNodeLeaves('NCMP-Admin', 'ncmp-dmi-registry', '/dmi-registry', _, _) >>
+    def 'Update alternate id of existing CM Handle.'() {
+        given: 'cm handles request'
+            def cmHandleUpdateRequest = [new NcmpServiceCmHandle(cmHandleId: cmHandleId, alternateId: 'alt-1')]
+        and: 'a data node found'
+            def dataNode = new DataNode(xpath: cmHandleXpath, leaves: ['id': cmHandleId, 'alternate-id': 'alt-1'])
+            mockInventoryPersistence.getCmHandleDataNodeByCmHandleId(cmHandleId) >> [dataNode]
+        when: 'cm handle properties is updated'
+            def response = objectUnderTest.updateCmHandleProperties(cmHandleUpdateRequest)
+        then: 'the update is delegated to cps data service with correct parameters'
+            1 * mockCpsDataService.updateNodeLeaves('NCMP-Admin', 'ncmp-dmi-registry', '/dmi-registry', _, _) >>
                     { args ->
                         assert args[3].contains('alt-1')
                     }
-            mockAlternateIdChecker.canApplyAlternateId(cmHandleId, '','alt-1') >> isNewMapping
-        where: 'following updates are attempted'
-            scenario                | isNewMapping || callsToDataService
-            'new alternate id   '   | true         || 1
-            'existing alternate id' | false        || 0
+        and: 'one successful registration response'
+            response.size() == 1
+        and: 'the response shows success for the given cm handle id'
+                assert response[0].status == Status.SUCCESS
+                assert response[0].cmHandle == cmHandleId
     }
 
-    def 'Alternate ID removed from cache when persisting fails.'() {
-        given: 'an existing data node and an update request with an alternate id'
-            def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, alternateId: 'alt-1')
-            DataNode existingCmHandleDataNode = new DataNode(xpath: cmHandleXpath, leaves: ['id': cmHandleId, 'alternate-id': null])
-        and: 'an applicable alternate id for the cm handle'
-            mockAlternateIdChecker.canApplyAlternateId(cmHandleId, '','alt-1') >> true
-        and: 'but an exception occurs while saving'
-            def originalException = new NullPointerException('some exception')
-            mockCpsDataService.updateNodeLeaves(*_) >> { throw originalException }
-        when: 'updating of alternate id called'
-            objectUnderTest.updateAlternateId(existingCmHandleDataNode, ncmpServiceCmHandle)
-        then: 'the original exception is thrown up'
-            def thrownException = thrown(NullPointerException)
-            assert thrownException == originalException
+    def 'Update with rejected alternate id.'() {
+        given: 'cm handles request'
+            def updatedNcmpServiceCmHandles = [new NcmpServiceCmHandle(cmHandleId: cmHandleId, alternateId: 'alt-1')]
+        and: 'a data node found'
+            def dataNode = new DataNode(xpath: cmHandleXpath, leaves: ['id': cmHandleId, 'alternate-id': 'alt-1'])
+            mockInventoryPersistence.getCmHandleDataNodeByCmHandleId(cmHandleId) >> [dataNode]
+        when: 'attempt to update the cm handle'
+            def response = objectUnderTest.updateCmHandleProperties(updatedNcmpServiceCmHandles)
+        then: 'the update is NOT delegated to cps data service'
+            0 * mockCpsDataService.updateNodeLeaves(*_)
+        and:  'the alternate id checker rejects the given cm handle (override default setup behavior)'
+            mockAlternateIdChecker.getIdsOfCmHandlesWithRejectedAlternateId(*_) >> [cmHandleId]
+        and: 'the response shows a failure for the given cm handle id'
+            assert response[0].status == Status.FAILURE
+            assert response[0].cmHandle == cmHandleId
     }
 
     def convertToProperties(expectedPropertiesAfterUpdateAsMap) {
index aaa0344..0eabaa1 100644 (file)
@@ -20,7 +20,6 @@
 
 package org.onap.cps.ncmp.api.impl.utils
 
-
 import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence
 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
 import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
@@ -68,25 +67,41 @@ class AlternateIdCheckerSpec extends Specification {
             'other alternate id' || false
     }
 
-    def 'Check a batch of NEW cm handles with #scenario.'() {
+    def 'Check a batch of created cm handles with #scenario.'() {
         given: 'a batch of 2 new cm handles alternate id ids #alt1 and #alt2'
             def batch = [new NcmpServiceCmHandle(cmHandleId: 'ch-1', alternateId: alt1),
                          new NcmpServiceCmHandle(cmHandleId: 'ch-2', alternateId: alt2)]
-        and: 'the database already contains cm handle(s) with these alternate ids: #alreadyinDb'
+        and: 'the database already contains cm handle(s) with these alternate ids: #altAlreadyInDb'
             mockInventoryPersistenceService.getCmHandleDataNodeByAlternateId(_) >>
                 {  args -> altAlreadyInDb.contains(args[0]) ? new DataNode() : throwDataNodeNotFoundException() }
         when: 'the batch of new cm handles is checked'
-            def result = objectUnderTest.getIdsOfCmHandlesWithRejectedAlternateId(batch)
-        then: 'the result only contains the ids of the acceptable cm handles'
-            assert result.contains('ch-1') == rejectCh1
-            assert result.contains('ch-2') == rejectCh2
+            def result = objectUnderTest.getIdsOfCmHandlesWithRejectedAlternateId(batch, AlternateIdChecker.Operation.CREATE)
+        then: 'the result contains ids of the rejected cm handles'
+            assert result == expectedRejectedCmHandleIds
         where: 'the following alternate ids are used'
-            scenario                          | alt1   | alt2   | altAlreadyInDb  || rejectCh1 | rejectCh2
-            'no alternate ids'                | ''     | ''     | ['dont matter'] || false      | false
-            'new alternate ids'               | 'fdn1' | 'fdn2' | ['other fdn']   || false      | false
-            'one already used alternate id'   | 'fdn1' | 'fdn2' | ['fdn1']        || true       | false
-            'two already used alternate ids'  | 'fdn1' | 'fdn2' | ['fdn1','fdn2'] || true       | true
-            'duplicate alternate id in batch' | 'fdn1' | 'fdn1' | ['dont matter'] || false      | true
+            scenario                          | alt1   | alt2   | altAlreadyInDb  || expectedRejectedCmHandleIds
+            'no alternate ids'                | ''     | ''     | ['dont matter'] || []
+            'new alternate ids'               | 'fdn1' | 'fdn2' | ['other fdn']   || []
+            'one already used alternate id'   | 'fdn1' | 'fdn2' | ['fdn1']        || ['ch-1']
+            'duplicate alternate id in batch' | 'fdn1' | 'fdn1' | ['dont matter'] || ['ch-2']
+    }
+
+    def 'Check a batch of updates to existing cm handles with #scenario.'() {
+        given: 'a batch of 1 existing cm handle update alternate id to #proposedAlt'
+            def batch = [new NcmpServiceCmHandle(cmHandleId: 'ch-1', alternateId: proposedAlt)]
+        and: 'the database already contains a cm handle with alternate id: #altAlreadyInDb'
+            mockInventoryPersistenceService.getCmHandleDataNodeByAlternateId(_) >>
+                    {  args -> altAlreadyInDb.equals(args[0]) ? new DataNode() : throwDataNodeNotFoundException() }
+            mockInventoryPersistenceService.getYangModelCmHandle(_) >> new YangModelCmHandle(alternateId: altAlreadyInDb)
+        when: 'the batch of cm handle updates is checked'
+            def result = objectUnderTest.getIdsOfCmHandlesWithRejectedAlternateId(batch, AlternateIdChecker.Operation.UPDATE)
+        then: 'the result contains ids of the rejected cm handles'
+            assert result == expectedRejectedCmHandleIds
+        where: 'the following parameters are used'
+            scenario                      | proposedAlt | altAlreadyInDb || expectedRejectedCmHandleIds
+            'no alternate id'             | 'fdn1'      | ''             || []
+            'used the same alternate id'  | 'fdn1'      | 'fdn1'         || []
+            'used different alternate id' | 'otherFdn'  | 'fdn1'         || ['ch-1']
     }
 
     def throwDataNodeNotFoundException() {