Use attribute-axis in NCMP [#3] 26/140526/2
authoremaclee <lee.anjella.macabuhay@est.tech>
Thu, 20 Mar 2025 00:07:40 +0000 (00:07 +0000)
committeremaclee <lee.anjella.macabuhay@est.tech>
Thu, 20 Mar 2025 11:37:26 +0000 (11:37 +0000)
- uses queryleaf API on the methods 'getCmHandleReferences'

Issue-ID: CPS-2664
Change-Id: I7552b4cdfcfa5eb285b94c1dcebfa5ba8327508c
Signed-off-by: emaclee <lee.anjella.macabuhay@est.tech>
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleQueryService.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleQueryServiceImpl.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryServiceImpl.java
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleQueryServiceImplSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryServiceSpec.groovy
cps-ri/src/main/java/org/onap/cps/ri/CpsDataPersistenceServiceImpl.java
cps-service/src/main/java/org/onap/cps/impl/CpsQueryServiceImpl.java
cps-service/src/test/groovy/org/onap/cps/impl/CpsFacadeImplSpec.groovy
integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/QueryServiceIntegrationSpec.groovy
integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/QueryPerfTest.groovy

index 9cbc6b0..d6b9476 100644 (file)
@@ -120,4 +120,14 @@ public interface CmHandleQueryService {
     Collection<String> getCmHandleReferencesByDmiPluginIdentifier(String dmiPluginIdentifier,
                                                                   boolean outputAlternateId);
 
+    /**
+     * Retrieves all CM handle references from the NCMP Inventory.
+     * Each CM handle reference represents a unique configuration management handle
+     * that can be identified by either its standard cm handle id or an alternate id.
+     *
+     * @param outputAlternateId If {@code true}, returns alternate ids; if {@code false}, returns standard cm handle ids
+     * @return collection of cm handle references. Returns an empty collection if no references are found.
+     */
+    Collection<String> getAllCmHandleReferences(boolean outputAlternateId);
+
 }
index 74e8626..4a753bd 100644 (file)
@@ -145,6 +145,13 @@ public class CmHandleQueryServiceImpl implements CmHandleQueryService {
         return cmHandleReferences;
     }
 
+    @Override
+    public Collection<String> getAllCmHandleReferences(final boolean outputAlternateId) {
+        final String attributeName = outputAlternateId ? ALTERNATE_ID : "id";
+        final String cpsPath = String.format("%s/cm-handles/@%s", NCMP_DMI_REGISTRY_PARENT, attributeName);
+        return cpsQueryService.queryDataLeaf(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, cpsPath, String.class);
+    }
+
     private Collection<String> getCmHandleReferencesByTrustLevel(final TrustLevel targetTrustLevel,
                                                                  final boolean outputAlternateId) {
         final Collection<String> selectedCmHandleReferences = new HashSet<>();
@@ -224,7 +231,6 @@ public class CmHandleQueryServiceImpl implements CmHandleQueryService {
                 .collect(Collectors.joining(" or "));
     }
 
-
     private DataNode getCmHandleState(final String cmHandleId) {
         cpsValidator.validateNameCharacters(cmHandleId);
         final String xpath = NCMP_DMI_REGISTRY_PARENT + "/cm-handles[@id='" + cmHandleId + "']/state";
index c44234d..9ce0e04 100644 (file)
@@ -233,9 +233,7 @@ public class ParameterizedCmHandleQueryServiceImpl implements ParameterizedCmHan
     }
 
     private Collection<String> getAllCmHandleReferences(final boolean outputAlternateId) {
-        final DataNode dataNode = inventoryPersistence.getDataNode(NCMP_DMI_REGISTRY_PARENT, DIRECT_CHILDREN_ONLY)
-                .iterator().next();
-        return collectCmHandleReferencesFromDataNodes(dataNode.getChildDataNodes(), outputAlternateId);
+        return cmHandleQueryService.getAllCmHandleReferences(outputAlternateId);
     }
 
     private Collection<NcmpServiceCmHandle> getNcmpServiceCmHandles(final Collection<String> cmHandleIds) {
index 12e4d6b..57210c5 100644 (file)
 
 package org.onap.cps.ncmp.impl.inventory
 
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DATASPACE_NAME
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DMI_REGISTRY_PARENT
+import static org.onap.cps.api.parameters.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
+import static org.onap.cps.api.parameters.FetchDescendantsOption.OMIT_DESCENDANTS
+
 import com.hazelcast.config.Config
 import com.hazelcast.core.Hazelcast
 import com.hazelcast.instance.impl.HazelcastInstanceFactory
@@ -33,12 +39,6 @@ import org.onap.cps.ncmp.api.inventory.models.CmHandleState
 import org.onap.cps.api.model.DataNode
 import spock.lang.Specification
 
-import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DATASPACE_NAME
-import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR
-import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DMI_REGISTRY_PARENT
-import static org.onap.cps.api.parameters.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
-import static org.onap.cps.api.parameters.FetchDescendantsOption.OMIT_DESCENDANTS
-
 class CmHandleQueryServiceImplSpec extends Specification {
 
     def mockCpsQueryService = Mock(CpsQueryService)
@@ -221,18 +221,33 @@ class CmHandleQueryServiceImplSpec extends Specification {
             'output is for cm handle ids'   | false             || ['PNFDemo', 'PNFDemo2', 'PNFDemo4']
     }
 
+    def 'Get all cm handle references when #scenario'() {
+        given: 'the query service returns all references'
+            mockResponses()
+        when: 'the all cm hande references is retrieved with #scenario'
+            def result = objectUnderTest.getAllCmHandleReferences(outputAlternateId)
+        then: 'result contains all the correct cm handle references'
+            result.containsAll(expectedResult)
+        where:
+            scenario                    | outputAlternateId || expectedResult
+            'output is alternate ids'   | true              || ['alt-PNFDemo', 'alt-PNFDemo2', 'alt-PNFDemo3', 'alt-PNFDemo4', 'alt-PNFDemo5']
+            'output is cm handle ids'   | false             || ['PNFDemo', 'PNFDemo2', 'PNFDemo3', 'PNFDemo4', 'PNFDemo5']
+    }
+
     void mockResponses() {
 
-        mockCpsQueryService.queryDataNodes(_, _, '//public-properties[@name=\"Contact\" and @value=\"newemailforstore@bookstore.com\"]/ancestor::cm-handles', _) >> [pnfDemo, pnfDemo2, pnfDemo4]
-        mockCpsQueryService.queryDataNodes(_, _, '//public-properties[@name=\"wont_match\" and @value=\"wont_match\"]/ancestor::cm-handles', _) >> []
-        mockCpsQueryService.queryDataNodes(_, _, '//public-properties[@name=\"Contact2\" and @value=\"newemailforstore2@bookstore.com\"]/ancestor::cm-handles', _) >> [pnfDemo4]
-        mockCpsQueryService.queryDataNodes(_, _, '//public-properties[@name=\"Contact2\" and @value=\"\"]/ancestor::cm-handles', _) >> []
+        mockCpsQueryService.queryDataLeaf(_, _, '//public-properties[@name=\'Contact\' and @value=\'newemailforstore@bookstore.com\']/ancestor::cm-handles/@id', _) >> [pnfDemo.getLeaves().get('id'), pnfDemo2.getLeaves().get('id'), pnfDemo4.getLeaves().get('id')]
+        mockCpsQueryService.queryDataLeaf(_, _, '//public-properties[@name=\'wont_match\' and @value=\'wont_match\']/ancestor::cm-handles/@id', _) >> []
+        mockCpsQueryService.queryDataLeaf(_, _, '//public-properties[@name=\'Contact2\' and @value=\'newemailforstore2@bookstore.com\']/ancestor::cm-handles/@alternate-id', _) >> [pnfDemo4.getLeaves().get('alternate-id')]
+        mockCpsQueryService.queryDataLeaf(_, _, '//public-properties[@name=\'Contact\' and @value=\'newemailforstore@bookstore.com\']/ancestor::cm-handles/@alternate-id', _) >> [pnfDemo.getLeaves().get('alternate-id'), pnfDemo2.getLeaves().get('alternate-id'), pnfDemo4.getLeaves().get('alternate-id')]
+        mockCpsQueryService.queryDataLeaf(_, _, '//public-properties[@name=\'Contact2\' and @value=\'\']/ancestor::cm-handles/@id', _) >> []
         mockCpsQueryService.queryDataNodes(_, _, '//state[@cm-handle-state=\"READY\"]/ancestor::cm-handles', _) >> [pnfDemo, pnfDemo3]
         mockCpsQueryService.queryDataNodes(_, _, '//state[@cm-handle-state=\"LOCKED\"]/ancestor::cm-handles', _) >> [pnfDemo2, pnfDemo4]
         mockCpsQueryService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, '/dmi-registry/cm-handles[@dmi-service-name=\'my-dmi-plugin-identifier\']', OMIT_DESCENDANTS) >> [pnfDemo, pnfDemo2]
         mockCpsQueryService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, '/dmi-registry/cm-handles[@dmi-data-service-name=\'my-dmi-plugin-identifier\']', OMIT_DESCENDANTS) >> [pnfDemo, pnfDemo4]
         mockCpsQueryService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, '/dmi-registry/cm-handles[@dmi-model-service-name=\'my-dmi-plugin-identifier\']', OMIT_DESCENDANTS) >> [pnfDemo2, pnfDemo4]
 
+
         mockCpsQueryService.queryDataLeaf(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, '/dmi-registry/cm-handles[@dmi-service-name=\'my-dmi-plugin-identifier\']/@id', _) >> [pnfDemo.getLeaves().get('id'), pnfDemo2.getLeaves().get('id')]
         mockCpsQueryService.queryDataLeaf(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, '/dmi-registry/cm-handles[@dmi-data-service-name=\'my-dmi-plugin-identifier\']/@id', _) >> [pnfDemo.getLeaves().get('id'), pnfDemo4.getLeaves().get('id')]
         mockCpsQueryService.queryDataLeaf(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, '/dmi-registry/cm-handles[@dmi-model-service-name=\'my-dmi-plugin-identifier\']/@id', _) >> [pnfDemo2.getLeaves().get('id'), pnfDemo4.getLeaves().get('id')]
@@ -243,15 +258,23 @@ class CmHandleQueryServiceImplSpec extends Specification {
         mockCpsQueryService.queryDataLeaf(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, '/dmi-registry/cm-handles[@id=\'PNFDemo\']/@alternate-id', _) >> [pnfDemo.getLeaves().get('alternate-id')]
         mockCpsQueryService.queryDataLeaf(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, '/dmi-registry/cm-handles[@id=\'PNFDemo2\' or @id=\'PNFDemo4\' or @id=\'PNFDemo\']/@alternate-id', _) >> [pnfDemo2.getLeaves().get('alternate-id'), pnfDemo.getLeaves().get('alternate-id'), pnfDemo4.getLeaves().get('alternate-id')]
 
-        mockCpsQueryService.queryDataLeaf(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, '//public-properties[@name=\'Contact\' and @value=\'newemailforstore@bookstore.com\']/ancestor::cm-handles/@id',_) >> [pnfDemo.getLeaves().get('id'), pnfDemo2.getLeaves().get('id'), pnfDemo4.getLeaves().get('id')]
-        mockCpsQueryService.queryDataLeaf(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, '//public-properties[@name=\'Contact\' and @value=\'newemailforstore@bookstore.com\']/ancestor::cm-handles/@alternate-id',_) >> [pnfDemo.getLeaves().get('alternate-id'), pnfDemo2.getLeaves().get('alternate-id'), pnfDemo4.getLeaves().get('alternate-id')]
-        mockCpsQueryService.queryDataLeaf(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,'//public-properties[@name=\'Contact2\' and @value=\'newemailforstore2@bookstore.com\']/ancestor::cm-handles/@alternate-id', _) >> [pnfDemo4.getLeaves().get('alternate-id')]
-        mockCpsQueryService.queryDataLeaf(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,'//public-properties[@name=\'Contact2\' and @value=\'newemailforstore2@bookstore.com\']/ancestor::cm-handles/@id', _) >> [pnfDemo4.getLeaves().get('id')]
-        mockCpsQueryService.queryDataLeaf(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,'//public-properties[@name=\'Contact2\' and @value=\'\']/ancestor::cm-handles/@id', _) >> []
-        mockCpsQueryService.queryDataLeaf(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, '//public-properties[@name=\'wont_match\' and @value=\'wont_match\']/ancestor::cm-handles/@id', _) >> []
+        mockCpsQueryService.queryDataLeaf(_, _, '/dmi-registry/cm-handles/@alternate-id', _) >> getAllCmHandleReferences(true)
+        mockCpsQueryService.queryDataLeaf(_, _, '/dmi-registry/cm-handles/@id', _) >> getAllCmHandleReferences(false)
+
     }
 
     def static createDataNode(dataNodeId) {
         return new DataNode(xpath: '/dmi-registry/cm-handles[@id=\'' + dataNodeId + '\']', leaves: ['id':dataNodeId, 'alternate-id':'alt-' + dataNodeId])
     }
+
+    def static getAllCmHandleReferences(outputAlternateId) {
+        def sampleNodes = [pnfDemo, pnfDemo2, pnfDemo3, pnfDemo4, pnfDemo5]
+        return sampleNodes.collect { dataNode ->
+            if (outputAlternateId) {
+                return dataNode.getLeaves().get('alternate-id')
+            } else {
+                return dataNode.getLeaves().get('id')
+            }
+        }
+    }
 }
index 7ba2bdf..8bb4551 100644 (file)
@@ -156,8 +156,8 @@ class ParameterizedCmHandleQueryServiceSpec extends Specification {
     def 'Query cm handle references when the query is empty.'() {
         given: 'We use an empty query'
             def cmHandleQueryParameters = new CmHandleQueryServiceParameters()
-        and: 'the inventory persistence returns the dmi registry datanode with just ids'
-            mockInventoryPersistence.getDataNode(NCMP_DMI_REGISTRY_PARENT, FetchDescendantsOption.DIRECT_CHILDREN_ONLY) >> [dmiRegistry]
+        and: 'the inventory persistence returns the dmi registry datanode with just cm handle references'
+            cmHandleQueries.getAllCmHandleReferences(outputAlternateId) >> getCmHandleReferencesForDmiRegistry(outputAlternateId)
         when: 'the query is executed for both cm handle ids'
             def result = objectUnderTest.queryCmHandleReferenceIds(cmHandleQueryParameters, outputAlternateId)
         then: 'the correct expected cm handles are returned'
@@ -252,4 +252,14 @@ class ParameterizedCmHandleQueryServiceSpec extends Specification {
         dataNodeIds.each{ dataNodes << new DataNode(xpath: "/dmi-registry/cm-handles[@id='${it}']", leaves: ['id':it, 'alternate-id':'alt-' + it]) }
         return dataNodes
     }
+
+    def getCmHandleReferencesForDmiRegistry(outputAlternateId) {
+        def cmHandles = dmiRegistry.childDataNodes ?: []
+        def cmHandleReferences = []
+        def attributeName = outputAlternateId ? 'alternate-id' : 'id'
+        cmHandles.each { cmHandle ->
+            cmHandleReferences.add(cmHandle.leaves.get(attributeName))
+        }
+        return cmHandleReferences
+    }
 }
index a510d30..575f9d7 100644 (file)
@@ -24,6 +24,7 @@
 package org.onap.cps.ri;
 
 import static org.onap.cps.api.CpsQueryService.NO_LIMIT;
+import static org.onap.cps.api.parameters.FetchDescendantsOption.OMIT_DESCENDANTS;
 import static org.onap.cps.api.parameters.PaginationOption.NO_PAGINATION;
 
 import com.google.common.collect.ImmutableSet;
@@ -250,8 +251,8 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
         }
 
         final String attributeName = cpsPathQuery.getAttributeAxisAttributeName();
-        final List<DataNode> dataNodes = queryDataNodes(dataspaceName, anchorName, cpsPath,
-                FetchDescendantsOption.OMIT_DESCENDANTS, queryResultLimit);
+        final Collection<DataNode> dataNodes = queryDataNodes(dataspaceName, anchorName, cpsPath,
+                OMIT_DESCENDANTS, queryResultLimit);
         return dataNodes.stream()
                 .map(dataNode -> {
                     final Object attributeValue = dataNode.getLeaves().get(attributeName);
index 5abdd0f..d61caf2 100644 (file)
@@ -74,8 +74,8 @@ public class CpsQueryServiceImpl implements CpsQueryService {
     public <T> Set<T> queryDataLeaf(final String dataspaceName, final String anchorName, final String cpsPath,
                                     final int queryResultLimit, final Class<T> targetClass) {
         cpsValidator.validateNameCharacters(dataspaceName, anchorName);
-        return cpsDataPersistenceService.queryDataLeaf(dataspaceName, anchorName, cpsPath, queryResultLimit,
-                targetClass);
+        return cpsDataPersistenceService.queryDataLeaf(dataspaceName, anchorName, cpsPath,
+                queryResultLimit, targetClass);
     }
 
     @Override
index 4351631..36cee6d 100644 (file)
@@ -20,6 +20,9 @@
 
 package org.onap.cps.impl
 
+import static org.onap.cps.api.parameters.FetchDescendantsOption.OMIT_DESCENDANTS
+import static org.onap.cps.api.parameters.PaginationOption.NO_PAGINATION
+
 import org.onap.cps.api.CpsAnchorService
 import org.onap.cps.api.CpsDataService
 import org.onap.cps.api.CpsQueryService
@@ -29,9 +32,6 @@ import org.onap.cps.utils.DataMapper
 import org.onap.cps.utils.PrefixResolver
 import spock.lang.Specification
 
-import static org.onap.cps.api.parameters.FetchDescendantsOption.OMIT_DESCENDANTS
-import static org.onap.cps.api.parameters.PaginationOption.NO_PAGINATION
-
 class CpsFacadeImplSpec extends Specification {
 
     def mockCpsDataService = Mock(CpsDataService)
index 6ae14dd..aa80e7f 100644 (file)
 
 package org.onap.cps.integration.functional.cps
 
+import static org.onap.cps.api.parameters.FetchDescendantsOption.DIRECT_CHILDREN_ONLY
+import static org.onap.cps.api.parameters.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
+import static org.onap.cps.api.parameters.FetchDescendantsOption.OMIT_DESCENDANTS
+import static org.onap.cps.api.parameters.PaginationOption.NO_PAGINATION
+
 import java.time.OffsetDateTime
 import org.onap.cps.api.CpsQueryService
 import org.onap.cps.integration.base.FunctionalSpecBase
@@ -28,11 +33,6 @@ import org.onap.cps.api.parameters.FetchDescendantsOption
 import org.onap.cps.api.parameters.PaginationOption
 import org.onap.cps.api.exceptions.CpsPathException
 
-import static org.onap.cps.api.parameters.FetchDescendantsOption.DIRECT_CHILDREN_ONLY
-import static org.onap.cps.api.parameters.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
-import static org.onap.cps.api.parameters.FetchDescendantsOption.OMIT_DESCENDANTS
-import static org.onap.cps.api.parameters.PaginationOption.NO_PAGINATION
-
 class QueryServiceIntegrationSpec extends FunctionalSpecBase {
 
     CpsQueryService objectUnderTest
index 53e39ed..70639c3 100644 (file)
 
 package org.onap.cps.integration.performance.cps
 
-import org.onap.cps.api.CpsQueryService
-import org.onap.cps.integration.performance.base.CpsPerfTestBase
-import org.onap.cps.api.parameters.PaginationOption
-
 import static org.onap.cps.api.parameters.FetchDescendantsOption.DIRECT_CHILDREN_ONLY
 import static org.onap.cps.api.parameters.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
 import static org.onap.cps.api.parameters.FetchDescendantsOption.OMIT_DESCENDANTS
 
+import org.onap.cps.api.CpsQueryService
+import org.onap.cps.integration.performance.base.CpsPerfTestBase
+import org.onap.cps.api.parameters.PaginationOption
+
 class QueryPerfTest extends CpsPerfTestBase {
 
     CpsQueryService objectUnderTest