Merge "Fix release notes"
authorJoseph Keenan <joseph.keenan@est.tech>
Fri, 17 Jun 2022 10:25:36 +0000 (10:25 +0000)
committerGerrit Code Review <gerrit@onap.org>
Fri, 17 Jun 2022 10:25:36 +0000 (10:25 +0000)
19 files changed:
cps-application/src/main/resources/application.yml
cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java
cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/DeprecationHelper.java
cps-ncmp-service/pom.xml
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyCmHandlerQueryService.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceImpl.java
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/inventory/InventoryPersistence.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdog.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/SyncUtils.java
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceSpec.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/inventory/InventoryPersistenceSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/SyncUtilsSpec.groovy
cps-service/src/main/java/org/onap/cps/spi/model/CmHandleQueryServiceParameters.java [moved from cps-service/src/main/java/org/onap/cps/spi/model/CmHandleQueryParameters.java with 97% similarity]
cps-service/src/main/java/org/onap/cps/utils/CmHandleQueryRestParametersValidator.java
cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAdminServiceImplSpec.groovy
cps-service/src/test/groovy/org/onap/cps/utils/CmHandleQueryRestParametersValidatorSpec.groovy

index 3f005c9..2b4dc4b 100644 (file)
@@ -1,6 +1,6 @@
 #  ============LICENSE_START=======================================================\r
 #  Copyright (C) 2021 Pantheon.tech\r
-#  Modifications Copyright (C) 2021 Bell Canada\r
+#  Modifications Copyright (C) 2021-2022 Bell Canada\r
 #  Modifications Copyright (C) 2021-2022 Nordix Foundation\r
 #  ================================================================================\r
 #  Licensed under the Apache License, Version 2.0 (the "License");\r
@@ -157,4 +157,7 @@ dmi:
 \r
 timers:\r
     advised-modules-sync:\r
-        sleep-time-ms: 30000
\ No newline at end of file
+        sleep-time-ms: 30000\r
+\r
+    locked-modules-sync:\r
+        sleep-time-ms: 300000
\ No newline at end of file
index ccb1e9b..fb234ef 100755 (executable)
@@ -211,6 +211,7 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
      * @return collection of cm handles
      */
     @Override
+    @SuppressWarnings("deprecation") // mapOldConditionProperties method will be removed in Release 12
     public ResponseEntity<List<RestOutputCmHandle>> searchCmHandles(
             final CmHandleQueryParameters cmHandleQueryParameters) {
         final CmHandleQueryApiParameters cmHandleQueryApiParameters =
index fc992da..573491c 100644 (file)
@@ -40,9 +40,11 @@ public class DeprecationHelper {
      * !!! remove it after the old condition removed !!!
      * it only works for module names
      *
+     * @deprecated this method will be removed in Release 12 (No Name know yet)
+     *
      * @param cmHandleQueryParameters the original input parameter
      */
-    @Deprecated //this method wil be removed in Release 12 (No Name know yet)
+    @Deprecated
     public CmHandleQueryApiParameters mapOldConditionProperties(
                                            final CmHandleQueryParameters cmHandleQueryParameters) {
         final CmHandleQueryApiParameters cmHandleQueryApiParameters =
index 99a024e..502e982 100644 (file)
@@ -3,6 +3,7 @@
   ============LICENSE_START=======================================================
   Copyright (C) 2021-2022 Nordix Foundation
   Modifications Copyright (C) 2021 Pantheon.tech
+ Modifications Copyright (C) 2022 Bell Canada
   ================================================================================
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
     </parent>
 
     <artifactId>cps-ncmp-service</artifactId>
+
     <properties>
-    <minimum-coverage>0.93</minimum-coverage>
+        <minimum-coverage>0.96</minimum-coverage>
     </properties>
-
     <dependencies>
         <dependency>
             <groupId>${project.groupId}</groupId>
index f8d51fe..92b1e82 100644 (file)
 package org.onap.cps.ncmp.api;
 
 import java.util.Collection;
-import org.onap.cps.spi.model.CmHandleQueryParameters;
+import org.onap.cps.spi.model.CmHandleQueryServiceParameters;
 import org.onap.cps.spi.model.DataNode;
 
 public interface NetworkCmProxyCmHandlerQueryService {
     /**
      * Query and return cm handles that match the given query parameters.
      *
-     * @param cmHandleQueryParameters the cm handle query parameters
+     * @param cmHandleQueryServiceParameters the cm handle query parameters
      * @return collection of cm handles
      */
-    Collection<DataNode> queryCmHandles(CmHandleQueryParameters cmHandleQueryParameters);
+    Collection<DataNode> queryCmHandles(CmHandleQueryServiceParameters cmHandleQueryServiceParameters);
 }
index ef6e953..00cbe69 100644 (file)
@@ -37,7 +37,7 @@ import org.onap.cps.ncmp.api.NetworkCmProxyCmHandlerQueryService;
 import org.onap.cps.spi.CpsAdminPersistenceService;
 import org.onap.cps.spi.CpsDataPersistenceService;
 import org.onap.cps.spi.model.Anchor;
-import org.onap.cps.spi.model.CmHandleQueryParameters;
+import org.onap.cps.spi.model.CmHandleQueryServiceParameters;
 import org.onap.cps.spi.model.ConditionProperties;
 import org.onap.cps.spi.model.DataNode;
 import org.onap.cps.spi.model.DataNodeIdentifier;
@@ -58,23 +58,23 @@ public class NetworkCmProxyCmHandlerQueryServiceImpl implements NetworkCmProxyCm
     /**
      * Query and return cm handles that match the given query parameters.
      *
-     * @param cmHandleQueryParameters the cm handle query parameters
+     * @param cmHandleQueryServiceParameters the cm handle query parameters
      * @return collection of cm handles
      */
     @Override
-    public Collection<DataNode> queryCmHandles(final CmHandleQueryParameters cmHandleQueryParameters) {
+    public Collection<DataNode> queryCmHandles(final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) {
 
-        if (cmHandleQueryParameters.getCmHandleQueryParameters().isEmpty()) {
+        if (cmHandleQueryServiceParameters.getCmHandleQueryParameters().isEmpty()) {
             return getAllCmHandles();
         }
 
         final Collection<DataNodeIdentifier> amalgamatedQueryResultIdentifiers = new ArrayList<>();
         final Map<DataNodeIdentifier, DataNode> amalgamatedQueryResults = new HashMap<>();
 
-        final boolean firstQuery = moduleNameQuery(cmHandleQueryParameters,
+        final boolean firstQuery = moduleNameQuery(cmHandleQueryServiceParameters,
                 amalgamatedQueryResultIdentifiers, amalgamatedQueryResults);
 
-        publicPropertyQuery(cmHandleQueryParameters, amalgamatedQueryResultIdentifiers,
+        publicPropertyQuery(cmHandleQueryServiceParameters, amalgamatedQueryResultIdentifiers,
                 amalgamatedQueryResults, firstQuery);
 
         final Collection<DataNode> filteredDataNodes = new ArrayList<>();
@@ -85,12 +85,12 @@ public class NetworkCmProxyCmHandlerQueryServiceImpl implements NetworkCmProxyCm
         return filteredDataNodes;
     }
 
-    private void publicPropertyQuery(final CmHandleQueryParameters cmHandleQueryParameters,
+    private void publicPropertyQuery(final CmHandleQueryServiceParameters cmHandleQueryServiceParameters,
                                      final Collection<DataNodeIdentifier> amalgamatedQueryResultIdentifiers,
                                      final Map<DataNodeIdentifier, DataNode> amalgamatedQueryResults,
                                      boolean firstQuery) {
         for (final Map.Entry<String, String> entry :
-                getPublicPropertyPairs(cmHandleQueryParameters.getCmHandleQueryParameters()).entrySet()) {
+                getPublicPropertyPairs(cmHandleQueryServiceParameters.getCmHandleQueryParameters()).entrySet()) {
             final String cmHandlePath = "//public-properties[@name='" + entry.getKey() + "' " + "and @value='"
                     + entry.getValue() + "']" + "/ancestor::cm-handles";
 
@@ -121,13 +121,13 @@ public class NetworkCmProxyCmHandlerQueryServiceImpl implements NetworkCmProxyCm
         }
     }
 
-    private boolean moduleNameQuery(final CmHandleQueryParameters cmHandleQueryParameters,
+    private boolean moduleNameQuery(final CmHandleQueryServiceParameters cmHandleQueryServiceParameters,
                                     final Collection<DataNodeIdentifier> amalgamatedQueryResultIdentifiers,
                                     final Map<DataNodeIdentifier, DataNode> amalgamatedQueryResults) {
         boolean firstQuery = true;
-        if (!getModuleNames(cmHandleQueryParameters.getCmHandleQueryParameters()).isEmpty()) {
+        if (!getModuleNames(cmHandleQueryServiceParameters.getCmHandleQueryParameters()).isEmpty()) {
             final Collection<Anchor> anchors = cpsAdminPersistenceService.queryAnchors("NFP-Operational",
-                    getModuleNames(cmHandleQueryParameters.getCmHandleQueryParameters()));
+                    getModuleNames(cmHandleQueryServiceParameters.getCmHandleQueryParameters()));
             anchors.forEach(anchor -> {
                 final List<DataNode> dataNodes = getDataNodes("//cm-handles[@id='" + anchor.getName() + "']");
                 dataNodes.parallelStream().forEach(dataNode -> {
index d1f72a5..f8cab4f 100755 (executable)
@@ -63,7 +63,7 @@ import org.onap.cps.spi.exceptions.AlreadyDefinedException;
 import org.onap.cps.spi.exceptions.DataNodeNotFoundException;
 import org.onap.cps.spi.exceptions.DataValidationException;
 import org.onap.cps.spi.exceptions.SchemaSetNotFoundException;
-import org.onap.cps.spi.model.CmHandleQueryParameters;
+import org.onap.cps.spi.model.CmHandleQueryServiceParameters;
 import org.onap.cps.spi.model.ModuleReference;
 import org.onap.cps.utils.CpsValidator;
 import org.onap.cps.utils.JsonObjectMapper;
@@ -167,12 +167,12 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
     @Override
     public Set<NcmpServiceCmHandle> executeCmHandleSearch(final CmHandleQueryApiParameters cmHandleQueryApiParameters) {
 
-        final CmHandleQueryParameters cmHandleQueryParameters = jsonObjectMapper.convertToValueType(
-                cmHandleQueryApiParameters, CmHandleQueryParameters.class);
+        final CmHandleQueryServiceParameters cmHandleQueryServiceParameters = jsonObjectMapper.convertToValueType(
+                cmHandleQueryApiParameters, CmHandleQueryServiceParameters.class);
 
-        validateCmHandleQueryParameters(cmHandleQueryParameters);
+        validateCmHandleQueryParameters(cmHandleQueryServiceParameters);
 
-        return networkCmProxyCmHandlerQueryService.queryCmHandles(cmHandleQueryParameters).stream()
+        return networkCmProxyCmHandlerQueryService.queryCmHandles(cmHandleQueryServiceParameters).stream()
                 .map(dataNode -> YangDataConverter
                         .convertCmHandleToYangModel(dataNode, dataNode.getLeaves().get("id").toString()))
                 .map(YangDataConverter::convertYangModelCmHandleToNcmpServiceCmHandle).collect(Collectors.toSet());
index 2fc2dc5..ce34154 100644 (file)
@@ -1,6 +1,7 @@
 /*
  *  ============LICENSE_START=======================================================
  *  Copyright (C) 2022 Nordix Foundation
+ *  Modifications Copyright (C) 2022 Bell Canada
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -91,6 +92,17 @@ public class InventoryPersistence {
             FetchDescendantsOption.OMIT_DESCENDANTS);
     }
 
+    /**
+     * Method to return cm handles from the cps path.
+     *
+     * @param cpsPath cps path for which the cmHandle is requested
+     * @return a list of cm handles
+     */
+    public List<DataNode> getCmHandlesByCpsPath(final String cpsPath) {
+        return cpsDataPersistenceService.queryDataNodes(
+            NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, cpsPath, FetchDescendantsOption.OMIT_DESCENDANTS);
+    }
+
     /**
      * This method retrieves DMI service name, DMI properties and the state for a given cm handle.
      * @param cmHandleId the id of the cm handle
index bcc7daa..dbc7dd4 100644 (file)
@@ -1,6 +1,7 @@
 /*
- *  ============LICENSE_START=======================================================
+ * ============LICENSE_START=======================================================
  *  Copyright (C) 2022 Nordix Foundation
+ *  Modifications Copyright (C) 2022 Bell Canada
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
 
 package org.onap.cps.ncmp.api.inventory.sync;
 
+import java.util.List;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
 import org.onap.cps.ncmp.api.inventory.CmHandleState;
 import org.onap.cps.ncmp.api.inventory.CompositeState;
+import org.onap.cps.ncmp.api.inventory.CompositeState.LockReason;
 import org.onap.cps.ncmp.api.inventory.InventoryPersistence;
 import org.onap.cps.ncmp.api.inventory.LockReasonCategory;
 import org.springframework.scheduling.annotation.Scheduled;
@@ -44,7 +47,7 @@ public class ModuleSyncWatchdog {
     /**
      * Execute Cm Handle poll which changes the cm handle state from 'ADVISED' to 'READY'.
      */
-    @Scheduled(fixedDelayString = "${timers.advised-modules-sync.sleep-time-ms}")
+    @Scheduled(fixedDelayString = "${timers.advised-modules-sync.sleep-time-ms:30000}")
     public void executeAdvisedCmHandlePoll() {
         YangModelCmHandle advisedCmHandle = syncUtils.getAnAdvisedCmHandle();
         while (advisedCmHandle != null) {
@@ -68,4 +71,20 @@ public class ModuleSyncWatchdog {
         log.debug("No Cm-Handles currently found in an ADVISED state");
     }
 
+    /**
+     * Execute Cm Handle poll which changes the cm handle state from 'LOCKED' to 'ADVISED'.
+     */
+    @Scheduled(fixedDelayString = "${timers.locked-modules-sync.sleep-time-ms:300000}")
+    public void executeLockedMisbehavingCmHandlePoll() {
+        final List<YangModelCmHandle> lockedMisbehavingCmHandles = syncUtils.getLockedMisbehavingCmHandles();
+        for (final YangModelCmHandle lockedMisbehavingModelCmHandle: lockedMisbehavingCmHandles) {
+            final CompositeState updatedCompositeState = lockedMisbehavingModelCmHandle.getCompositeState();
+            updatedCompositeState.setCmHandleState(CmHandleState.ADVISED);
+            updatedCompositeState.setLastUpdateTimeNow();
+            updatedCompositeState.setLockReason(LockReason.builder()
+                .details(updatedCompositeState.getLockReason().getDetails()).build());
+            log.debug("Locked misbehaving cm handle {} is being recycled", lockedMisbehavingModelCmHandle.getId());
+            inventoryPersistence.saveCmHandleState(lockedMisbehavingModelCmHandle.getId(), updatedCompositeState);
+        }
+    }
 }
index a4f29de..22eeabb 100644 (file)
@@ -1,6 +1,7 @@
 /*
  *  ============LICENSE_START=======================================================
  *  Copyright (C) 2022 Nordix Foundation
+ *  Modifications Copyright (C) 2022 Bell Canada
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -24,8 +25,10 @@ import java.security.SecureRandom;
 import java.util.List;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.onap.cps.ncmp.api.impl.utils.YangDataConverter;
 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
 import org.onap.cps.ncmp.api.inventory.CmHandleState;
 import org.onap.cps.ncmp.api.inventory.CompositeState;
@@ -41,7 +44,6 @@ public class SyncUtils {
 
     private static final SecureRandom secureRandom = new SecureRandom();
 
-
     private final InventoryPersistence inventoryPersistence;
 
     private static final Pattern retryAttemptPattern = Pattern.compile("^Attempt #(\\d+) failed:");
@@ -63,6 +65,19 @@ public class SyncUtils {
     }
 
 
+    /**
+     * Query data nodes for cm handles with an "LOCKED" cm handle state with reason LOCKED_MISBEHAVING".
+     *
+     * @return a random yang model cm handle with an ADVISED state, return null if not found
+     */
+    public List<YangModelCmHandle> getLockedMisbehavingCmHandles() {
+        final List<DataNode> lockedCmHandleAsDataNodeList = inventoryPersistence.getCmHandlesByCpsPath(
+            "//lock-reason[@reason=\"LOCKED_MISBEHAVING\"]/ancestor::cm-handles");
+        return lockedCmHandleAsDataNodeList.stream()
+            .map(cmHandle -> YangDataConverter.convertCmHandleToYangModel(cmHandle,
+                cmHandle.getLeaves().get("id").toString())).collect(Collectors.toList());
+    }
+
     /**
      * Update Composite State attempts counter and set new lock reason and details.
      *
@@ -84,5 +99,4 @@ public class SyncUtils {
             .lockReasonCategory(lockReasonCategory).build());
     }
 
-
 }
index a1ad9af..b689097 100644 (file)
@@ -25,7 +25,7 @@ import org.onap.cps.ncmp.api.NetworkCmProxyCmHandlerQueryService
 import org.onap.cps.spi.CpsAdminPersistenceService
 import org.onap.cps.spi.CpsDataPersistenceService
 import org.onap.cps.spi.model.Anchor
-import org.onap.cps.spi.model.CmHandleQueryParameters
+import org.onap.cps.spi.model.CmHandleQueryServiceParameters
 import org.onap.cps.spi.model.ConditionProperties
 import org.onap.cps.spi.model.DataNode
 import org.onap.cps.utils.JsonObjectMapper
@@ -44,7 +44,7 @@ class NetworkCmProxyCmHandlerQueryServiceSpec extends Specification {
 
     def 'Retrieve cm handles with public properties when #scenario.'() {
         given: 'a condition property'
-            def cmHandleQueryParameters = new CmHandleQueryParameters()
+            def cmHandleQueryParameters = new CmHandleQueryServiceParameters()
             def conditionProperties = new ConditionProperties()
             conditionProperties.conditionName = 'hasAllProperties'
             conditionProperties.conditionParameters = publicProperties
@@ -65,7 +65,7 @@ class NetworkCmProxyCmHandlerQueryServiceSpec extends Specification {
 
     def 'Retrieve cm handles with module names when #scenario.'() {
         given: 'a condition property'
-            def cmHandleQueryParameters = new CmHandleQueryParameters()
+            def cmHandleQueryParameters = new CmHandleQueryServiceParameters()
             def conditionProperties = new ConditionProperties()
             conditionProperties.conditionName = 'hasAllModules'
             conditionProperties.conditionParameters = moduleNames
@@ -86,7 +86,7 @@ class NetworkCmProxyCmHandlerQueryServiceSpec extends Specification {
 
     def 'Retrieve cm handles with combined queries when #scenario.'() {
         given: 'condition properties'
-            def cmHandleQueryParameters = new CmHandleQueryParameters()
+            def cmHandleQueryParameters = new CmHandleQueryServiceParameters()
             def conditionProperties1 = new ConditionProperties()
             conditionProperties1.conditionName = 'hasAllProperties'
             conditionProperties1.conditionParameters = publicProperties
@@ -111,7 +111,7 @@ class NetworkCmProxyCmHandlerQueryServiceSpec extends Specification {
         given: 'mock services'
             mockResponses()
         when: 'the service is invoked'
-            def cmHandleQueryParameters = new CmHandleQueryParameters()
+            def cmHandleQueryParameters = new CmHandleQueryServiceParameters()
             def returnedCmHandles = objectUnderTest.queryCmHandles(cmHandleQueryParameters)
         then: 'the correct expected cm handles are returned'
             returnedCmHandles.stream().map(d -> d.leaves.get('id').toString()).collect(Collectors.toList()) == ['PNFDemo', 'PNFDemo2', 'PNFDemo3', 'PNFDemo4']
index 6ba2a2c..d58fe6a 100644 (file)
@@ -33,7 +33,7 @@ import org.onap.cps.ncmp.api.models.DmiPluginRegistration
 import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
 import org.onap.cps.spi.exceptions.DataValidationException
 import org.onap.cps.ncmp.api.inventory.sync.ModuleSyncService
-import org.onap.cps.spi.model.CmHandleQueryParameters
+import org.onap.cps.spi.model.CmHandleQueryServiceParameters
 import org.onap.cps.spi.model.ConditionProperties
 import spock.lang.Shared
 
@@ -252,7 +252,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
             conditionApiProperties.conditionParameters = [[moduleName: 'module-name-1']]
             cmHandleQueryApiParameters.cmHandleQueryParameters = [conditionApiProperties]
         and: 'valid CmHandleQueryParameters input'
-            def cmHandleQueryParameters = new CmHandleQueryParameters()
+            def cmHandleQueryParameters = new CmHandleQueryServiceParameters()
             def conditionProperties = new ConditionProperties()
             conditionProperties.conditionName = 'hasAllModules'
             conditionProperties.conditionParameters = [[moduleName: 'module-name-1']]
index a2ebcb5..e6346cb 100644 (file)
@@ -1,6 +1,7 @@
 /*
  *  ============LICENSE_START=======================================================
  *  Copyright (C) 2022 Nordix Foundation
+ *  Modifications Copyright (C) 2022 Bell Canada
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -27,6 +28,7 @@ import org.onap.cps.spi.CpsDataPersistenceService
 import org.onap.cps.spi.FetchDescendantsOption
 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 spock.lang.Shared
 import spock.lang.Specification
@@ -50,7 +52,7 @@ class InventoryPersistenceSpec extends Specification {
     def objectUnderTest = new InventoryPersistence(spiedJsonObjectMapper, mockCpsDataService, mockCpsDataPersistenceService)
 
     def formattedDateAndTime = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
-        .format(OffsetDateTime.of(2022, 12, 31, 20, 30, 40, 1, ZoneOffset.UTC))
+            .format(OffsetDateTime.of(2022, 12, 31, 20, 30, 40, 1, ZoneOffset.UTC))
 
     def cmHandleId = 'some-cm-handle'
     def leaves = ["dmi-service-name":"common service name","dmi-data-service-name":"data service name","dmi-model-service-name":"model service name"]
@@ -88,7 +90,7 @@ class InventoryPersistenceSpec extends Specification {
         where: 'the following parameters are used'
             scenario                    | childDataNodes                                || expectedDmiProperties                               || expectedPublicProperties                              || expectedCompositeState
             'no properties'             | []                                            || []                                                  || []                                                    || null
-            'DMI and public properties' | childDataNodesForCmHandleWithAllProperties    || [new YangModelCmHandle.Property("name1", "value1")] || [new YangModelCmHandle.Property("name2", "value2")]   || null
+            'DMI and public properties' | childDataNodesForCmHandleWithAllProperties    || [new YangModelCmHandle.Property("name1", "value1")] || [new YangModelCmHandle.Property("name2", "value2")] || null
             'just DMI properties'       | childDataNodesForCmHandleWithDMIProperties    || [new YangModelCmHandle.Property("name1", "value1")] || []                                                    || null
             'just public properties'    | childDataNodesForCmHandleWithPublicProperties || []                                                  || [new YangModelCmHandle.Property("name2", "value2")]   || null
             'with state details'        | childDataNodesForCmHandleWithState            || []                                                  || []                                                    || CmHandleState.ADVISED
@@ -105,7 +107,7 @@ class InventoryPersistenceSpec extends Specification {
 
     def "Handling missing service names as null CPS-1043."() {
         given: 'the cps data service returns a data node from the DMI registry with empty child and leaf attributes'
-            def dataNode = new DataNode(childDataNodes:[], leaves: ["cm-handle-state":"ADVISED"])
+            def dataNode = new DataNode(childDataNodes:[], leaves: [:])
             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry', xpath, INCLUDE_ALL_DESCENDANTS) >> dataNode
         when: 'retrieving the yang modelled cm handle'
             def result = objectUnderTest.getYangModelCmHandle(cmHandleId)
@@ -121,7 +123,7 @@ class InventoryPersistenceSpec extends Specification {
             def dataNode = new DataNode(leaves: ['cm-handle-state': 'ADVISED'])
         and: 'cps data service returns a valid data node'
             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
-                '/dmi-registry/cm-handles[@id=\'Some-Cm-Handle\']/state', FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
+                    '/dmi-registry/cm-handles[@id=\'Some-Cm-Handle\']/state', FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
         when: 'get cm handle state is invoked'
             def result = objectUnderTest.getCmHandleState(cmHandleId)
         then: 'result has returned the correct cm handle state'
@@ -137,7 +139,7 @@ class InventoryPersistenceSpec extends Specification {
         then: 'update node leaves is invoked with the correct params'
             1 * mockCpsDataService.replaceNodeTree('NCMP-Admin', 'ncmp-dmi-registry', '/dmi-registry/cm-handles[@id=\'Some-Cm-Handle\']', expectedJsonData, _ as OffsetDateTime)
         where: 'the following states are used'
-             scenario | cmHandleState        || expectedJsonData
+            scenario | cmHandleState        || expectedJsonData
             'READY'   | CmHandleState.READY  || '{"state":{"cm-handle-state":"READY","last-update-time":"2022-12-31T20:30:40.000+0000"}}'
             'LOCKED'  | CmHandleState.LOCKED || '{"state":{"cm-handle-state":"LOCKED","last-update-time":"2022-12-31T20:30:40.000+0000"}}'
     }
@@ -148,11 +150,25 @@ class InventoryPersistenceSpec extends Specification {
         and: 'cps data service returns a list of data nodes'
             def dataNodes = [new DataNode()]
             mockCpsDataPersistenceService.queryDataNodes('NCMP-Admin', 'ncmp-dmi-registry',
-                '//state[@cm-handle-state="ADVISED"]/ancestor::cm-handles', OMIT_DESCENDANTS) >> dataNodes
+                    '//state[@cm-handle-state="ADVISED"]/ancestor::cm-handles', OMIT_DESCENDANTS) >> dataNodes
         when: 'get cm handles by state is invoked'
             def result = objectUnderTest.getCmHandlesByState(cmHandleState)
         then: 'the returned result is a list of data nodes returned by cps data service'
             assert result == dataNodes
     }
 
+    def 'Retrieve cm handle by cps path '() {
+        given: 'a cm handle state to query based on the cps path'
+            def cmHandleDataNode = new DataNode(xpath: 'xpath', leaves: ['cm-handle-state': 'LOCKED'])
+            def cpsPath = '//cps-path'
+        and: 'cps data service returns a valid data node'
+            mockCpsDataPersistenceService.queryDataNodes('NCMP-Admin', 'ncmp-dmi-registry',
+                    cpsPath, OMIT_DESCENDANTS)
+                    >> Arrays.asList(cmHandleDataNode)
+        when: 'get cm handles by cps path is invoked'
+            def result = objectUnderTest.getCmHandlesByCpsPath(cpsPath)
+        then: 'the returned result is a list of data nodes returned by cps data service'
+            assert result.contains(cmHandleDataNode)
+    }
+
 }
index 97bea09..544f739 100644 (file)
@@ -1,6 +1,7 @@
 /*
  *  ============LICENSE_START=======================================================
  *  Copyright (C) 2022 Nordix Foundation
+ *  Modifications Copyright (C) 2022 Bell Canada
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -25,6 +26,7 @@ import org.onap.cps.ncmp.api.inventory.CmHandleState
 import org.onap.cps.ncmp.api.inventory.CompositeState
 import org.onap.cps.ncmp.api.inventory.InventoryPersistence
 import org.onap.cps.ncmp.api.inventory.LockReasonCategory
+import org.onap.cps.ncmp.api.inventory.CompositeStateBuilder
 import spock.lang.Specification
 
 class ModuleSyncSpec extends Specification {
@@ -88,4 +90,16 @@ class ModuleSyncSpec extends Specification {
 
     }
 
+    def 'Schedule a Cm-Handle Sync for LOCKED with reason LOCKED_MISBEHAVING Cm-Handles '() {
+        given: 'cm handles in an locked state'
+            def compositeState = new CompositeStateBuilder().withCmHandleState(CmHandleState.LOCKED)
+                    .withLockReason(LockReasonCategory.LOCKED_MISBEHAVING, '').build()
+            def yangModelCmHandle = new YangModelCmHandle(id: 'some-cm-handle', compositeState: compositeState)
+        and: 'sync utilities return a cm handle twice'
+            mockSyncUtils.getLockedMisbehavingCmHandles() >> [yangModelCmHandle, yangModelCmHandle]
+        when: 'module sync poll is executed'
+            objectUnderTest.executeLockedMisbehavingCmHandlePoll()
+        then: 'the first cm handle is updated to state "ADVISED" from "READY"'
+            2 * mockInventoryPersistence.saveCmHandleState(yangModelCmHandle.id, compositeState)
+    }
 }
index 7d67acc..15d1efe 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2022 Nordix Foundation
+ *  Modifications Copyright (C) 2022 Bell Canada
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -24,15 +25,12 @@ import org.onap.cps.ncmp.api.inventory.CmHandleState
 import org.onap.cps.ncmp.api.inventory.CompositeState
 import org.onap.cps.ncmp.api.inventory.InventoryPersistence
 import org.onap.cps.ncmp.api.inventory.LockReasonCategory
-import org.onap.cps.spi.CpsDataPersistenceService
-import org.onap.cps.spi.FetchDescendantsOption
 import org.onap.cps.spi.model.DataNode
 import spock.lang.Shared
 import spock.lang.Specification
 
 class SyncUtilsSpec extends Specification{
 
-    def mockCpsDataPersistenceService = Mock(CpsDataPersistenceService)
     def mockInventoryPersistence = Mock(InventoryPersistence)
 
     def objectUnderTest = new SyncUtils(mockInventoryPersistence)
@@ -40,8 +38,6 @@ class SyncUtilsSpec extends Specification{
     @Shared
     def dataNode = new DataNode(leaves: ['id': 'cm-handle-123'])
 
-
-
     def 'Get an advised Cm-Handle where ADVISED cm handle #scenario'() {
         given: 'the inventory persistence service returns a collection of data nodes'
             mockInventoryPersistence.getCmHandlesByState(CmHandleState.ADVISED) >> dataNodeCollection
@@ -71,5 +67,15 @@ class SyncUtilsSpec extends Specification{
             'does not exist' | null                                                                                         || 'Attempt #1 failed: new error message'
             'exists'         | CompositeState.LockReason.builder().details("Attempt #2 failed: some error message").build() || 'Attempt #3 failed: new error message'
     }
-
+    def 'Get all locked Cm-Handle where Lock Reason is LOCKED_MISBEHAVING cm handle #scenario'() {
+        given: 'the cps (persistence service) returns a collection of data nodes'
+            mockInventoryPersistence.getCmHandlesByCpsPath(
+                    '//lock-reason[@reason="LOCKED_MISBEHAVING"]/ancestor::cm-handles') >> [dataNode ]
+        when: 'get locked Misbehaving cm handle is called'
+            def result = objectUnderTest.getLockedMisbehavingCmHandles()
+        then: 'the returned cm handle collection is the correct size'
+            result.size() == 1
+        and: 'the correct cm handle is returned'
+            result[0].id == 'cm-handle-123'
+    }
 }
@@ -34,7 +34,7 @@ import lombok.Setter;
 @Getter
 @EqualsAndHashCode
 @JsonInclude(Include.NON_EMPTY)
-public class CmHandleQueryParameters {
+public class CmHandleQueryServiceParameters {
     @JsonProperty("cmHandleQueryParameters")
     @Valid
     private List<ConditionProperties> cmHandleQueryParameters = Collections.emptyList();
index c510a73..c3811eb 100644 (file)
@@ -27,7 +27,7 @@ import java.util.Map;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import org.onap.cps.spi.exceptions.DataValidationException;
-import org.onap.cps.spi.model.CmHandleQueryParameters;
+import org.onap.cps.spi.model.CmHandleQueryServiceParameters;
 
 @NoArgsConstructor(access = AccessLevel.PRIVATE)
 public class CmHandleQueryRestParametersValidator {
@@ -36,10 +36,11 @@ public class CmHandleQueryRestParametersValidator {
 
     /**
      * Validate cm handle query parameters.
-     * @param cmHandleQueryParameters name of data to be validated
+     * @param cmHandleQueryServiceParameters name of data to be validated
      */
-    public static void validateCmHandleQueryParameters(final CmHandleQueryParameters cmHandleQueryParameters) {
-        cmHandleQueryParameters.getCmHandleQueryParameters().forEach(
+    public static void validateCmHandleQueryParameters(
+            final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) {
+        cmHandleQueryServiceParameters.getCmHandleQueryParameters().forEach(
                 conditionApiProperty -> {
                     if (Strings.isNullOrEmpty(conditionApiProperty.getConditionName())) {
                         throwDataValidationException("Missing 'conditionName' - please supply a valid name.");
@@ -54,27 +55,29 @@ public class CmHandleQueryRestParametersValidator {
                                 "Empty 'conditionsParameters' - please supply a valid condition parameter.");
                     }
                     conditionApiProperty.getConditionParameters().forEach(
-                            conditionParameter -> {
-                                if (conditionParameter.isEmpty()) {
-                                    throwDataValidationException(
-                                            "Empty 'conditionsParameter' - please supply a valid condition parameter.");
-                                }
-                                if (conditionParameter.size() > 1) {
-                                    throwDataValidationException("Too many name in one 'conditionsParameter' -"
-                                            + " please supply one name in one condition parameter.");
-                                }
-                                conditionParameter.forEach((key, value) -> {
-                                    if (Strings.isNullOrEmpty(key)) {
-                                        throwDataValidationException(
-                                                "Missing 'conditionsParameterName' - please supply a valid name.");
-                                    }
-                                });
-                            }
+                            CmHandleQueryRestParametersValidator::validateConditionParameter
                     );
                 }
         );
     }
 
+    private static void validateConditionParameter(final Map<String, String> conditionParameter) {
+        if (conditionParameter.isEmpty()) {
+            throwDataValidationException(
+                    "Empty 'conditionsParameter' - please supply a valid condition parameter.");
+        }
+        if (conditionParameter.size() > 1) {
+            throwDataValidationException("Too many name in one 'conditionsParameter' -"
+                    + " please supply one name in one condition parameter.");
+        }
+        conditionParameter.forEach((key, value) -> {
+            if (Strings.isNullOrEmpty(key)) {
+                throwDataValidationException(
+                        "Missing 'conditionsParameterName' - please supply a valid name.");
+            }
+        });
+    }
+
     /**
      * Validate module name condition properties.
      * @param conditionProperty name of data to be validated
index def99e2..41fcb29 100755 (executable)
@@ -26,7 +26,6 @@ import org.onap.cps.api.CpsDataService
 import org.onap.cps.spi.CpsAdminPersistenceService
 import org.onap.cps.spi.exceptions.DataValidationException
 import org.onap.cps.spi.model.Anchor
-import org.onap.cps.spi.model.CmHandleQueryParameters
 import spock.lang.Specification
 import java.time.OffsetDateTime
 
index 645829b..a9b04c1 100644 (file)
 package org.onap.cps.utils
 
 import org.onap.cps.spi.exceptions.DataValidationException
-import org.onap.cps.spi.model.CmHandleQueryParameters
+import org.onap.cps.spi.model.CmHandleQueryServiceParameters
 import org.onap.cps.spi.model.ConditionProperties
 import spock.lang.Specification
 
 class CmHandleQueryRestParametersValidatorSpec extends Specification {
     def 'CM Handle Query validation: empty query.'() {
         given: 'a cm handle query'
-            def cmHandleQueryParameters = new CmHandleQueryParameters()
+            def cmHandleQueryParameters = new CmHandleQueryServiceParameters()
         when: 'validator is invoked'
             CmHandleQueryRestParametersValidator.validateCmHandleQueryParameters(cmHandleQueryParameters)
         then: 'data validation exception is not thrown'
@@ -37,7 +37,7 @@ class CmHandleQueryRestParametersValidatorSpec extends Specification {
 
     def 'CM Handle Query validation: normal query.'() {
         given: 'a cm handle query'
-            def cmHandleQueryParameters = new CmHandleQueryParameters()
+            def cmHandleQueryParameters = new CmHandleQueryServiceParameters()
             def condition = new ConditionProperties()
             condition.conditionName = 'hasAllProperties'
             condition.conditionParameters = [[key1:'value1'],[key2:'value2']]
@@ -50,7 +50,7 @@ class CmHandleQueryRestParametersValidatorSpec extends Specification {
 
     def 'CM Handle Query validation: #scenario.'() {
         given: 'a cm handle query'
-            def cmHandleQueryParameters = new CmHandleQueryParameters()
+            def cmHandleQueryParameters = new CmHandleQueryServiceParameters()
             def condition = new ConditionProperties()
             condition.conditionName = conditionName
             condition.conditionParameters = conditionParameters