import java.util.Map;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
+import org.onap.cps.cpspath.parser.CpsPathUtil;
import org.onap.cps.ncmp.api.inventory.models.TrustLevel;
import org.onap.cps.ncmp.impl.inventory.models.CmHandleState;
import org.onap.cps.ncmp.impl.inventory.models.ModelledDmiServiceLeaves;
@Override
public List<DataNode> queryCmHandleAncestorsByCpsPath(final String cpsPath,
final FetchDescendantsOption fetchDescendantsOption) {
+ if (CpsPathUtil.getCpsPathQuery(cpsPath).getXpathPrefix().endsWith("/cm-handles")) {
+ return queryNcmpRegistryByCpsPath(cpsPath, fetchDescendantsOption);
+ }
return queryNcmpRegistryByCpsPath(cpsPath + ANCESTOR_CM_HANDLES, fetchDescendantsOption);
}
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2022-2023 Nordix Foundation
+ * Copyright (C) 2022-2024 Nordix Foundation
* Modifications Copyright (C) 2023 TechMahindra Ltd.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
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'
+ def cmHandleDataNode = new DataNode(xpath: "/dmi-registry/cm-handles[@id='ch-1']", leaves: ['id': 'ch-1'])
+ def cpsPath = "//state[@cm-handle-state='LOCKED']"
+ and: 'cps data service returns a valid data node for cm handle ancestor'
mockCpsDataPersistenceService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
cpsPath + '/ancestor::cm-handles', INCLUDE_ALL_DESCENDANTS)
>> Arrays.asList(cmHandleDataNode)
assert result.contains(cmHandleDataNode)
}
+ def 'Retrieve cm handle by cps path querying cm handle directly'() {
+ given: 'a cm handle to query based on the cps path'
+ def cmHandleDataNode = new DataNode(xpath: "/dmi-registry/cm-handles[@id='ch-2']", leaves: ['id': 'ch-2'])
+ def cpsPath = "//cm-handles[@alternate-id='1']"
+ and: 'cps data service returns a valid data node'
+ mockCpsDataPersistenceService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
+ cpsPath, INCLUDE_ALL_DESCENDANTS)
+ >> Arrays.asList(cmHandleDataNode)
+ when: 'get cm handles by cps path is invoked'
+ def result = objectUnderTest.queryCmHandleAncestorsByCpsPath(cpsPath, INCLUDE_ALL_DESCENDANTS)
+ then: 'the returned result is a list of data nodes returned by cps data service'
+ assert result.contains(cmHandleDataNode)
+ }
+
def 'Get all cm handles by dmi plugin identifier'() {
given: 'the DataNodes queried for a given cpsPath are returned from the persistence service.'
mockResponses()
cpsPathQuery.setNormalizedXpath(normalizedXpathBuilder.toString());
cpsPathQuery.setContainerNames(containerNames);
cpsPathQuery.setBooleanOperators(booleanOperators);
- if (cpsPathQuery.hasAncestorAxis() && cpsPathQuery.getXpathPrefix()
- .endsWith("/" + cpsPathQuery.getAncestorSchemaNodeIdentifier())) {
- cpsPathQuery.setAncestorSchemaNodeIdentifier("");
- }
return cpsPathQuery;
}
'/test[@name2="value2" and @name1="value1"]' || 'name2' | 'name1'
}
- def 'Ancestor axis matching prefix'() {
- when: 'building a cps path query'
- def result = parseXPathAndBuild(xpath)
- then: 'ancestor axis is removed when same as prefix'
- assert result.hasAncestorAxis() == expectAncestorAxis
- where: 'the following xpaths are used'
- xpath || expectAncestorAxis
- '//abc/def/ancestor::abc' || true
- '//abc/def/ancestor::def' || false
- '//abc/def/ancestor::ef' || true
- }
-
- def parseXPathAndBuild(xpath) {
- def cpsPathBuilder = CpsPathUtil.getCpsPathBuilder(xpath)
- cpsPathBuilder.build()
- }
-
}
'ancestor with parent list' | '//books/ancestor::bookstore/categories' || ["/bookstore/categories[@code='1']", "/bookstore/categories[@code='2']", "/bookstore/categories[@code='3']", "/bookstore/categories[@code='4']", "/bookstore/categories[@code='5']"]
'ancestor with parent list element' | '//books/ancestor::bookstore/categories[@code="2"]' || ["/bookstore/categories[@code='2']"]
'ancestor combined with text condition' | '//books/title[text()="Matilda"]/ancestor::bookstore' || ["/bookstore"]
- 'ancestor same as target type' | '//books/title[text()="Matilda"]/ancestor::books' || ["/bookstore/categories[@code='1']/books[@title='Matilda']"]
}
def 'Cps Path query across anchors with #scenario descendants.'() {
'ch-3': ['M1', 'M3']
]
when: 'a POST request is made to register the CM Handles'
- def requestBody = '{"dmiPlugin":"'+DMI1_URL+'","createdCmHandles":[{"cmHandle":"ch-1"},{"cmHandle":"ch-2"},{"cmHandle":"ch-3"}]}'
+ def requestBody = '{"dmiPlugin":"'+DMI1_URL+'","createdCmHandles":[{"cmHandle":"ch-1","alternateId":"alt-1"},{"cmHandle":"ch-2","alternateId":"alt-2"},{"cmHandle":"ch-3","alternateId":"alt-3"}]}'
mvc.perform(post('/ncmpInventory/v1/ch').contentType(MediaType.APPLICATION_JSON).content(requestBody))
.andExpect(status().is2xxSuccessful())
then: 'CM-handles go to READY state'
'M3' || ['ch-3']
}
+ def 'Search for CM Handles using Cps Path Query.'() {
+ given: 'a JSON request body containing search parameter'
+ def requestBodyWithSearchCondition = """{
+ "cmHandleQueryParameters": [
+ {
+ "conditionName": "cmHandleWithCpsPath",
+ "conditionParameters": [ {"cpsPath" : "%s"} ]
+ }
+ ]
+ }""".formatted(cpsPath)
+ expect: "a search for cps path ${cpsPath} returns expected CM handles"
+ mvc.perform(post('/ncmp/v1/ch/id-searches').contentType(MediaType.APPLICATION_JSON).content(requestBodyWithSearchCondition))
+ .andExpect(status().is2xxSuccessful())
+ .andExpect(jsonPath('$[*]', containsInAnyOrder(expectedCmHandles.toArray())))
+ .andExpect(jsonPath('$', hasSize(expectedCmHandles.size())));
+ where:
+ scenario | cpsPath || expectedCmHandles
+ 'All Ready CM handles' | "//state[@cm-handle-state='READY']" || ['ch-1', 'ch-2', 'ch-3']
+ 'Having Alternate ID alt-3' | "//cm-handles[@alternate-id='alt-3']" || ['ch-3']
+ }
+
def 'De-register CM handles using REST API.'() {
when: 'a POST request is made to deregister the CM Handle'
def requestBody = '{"dmiPlugin":"'+DMI1_URL+'", "removedCmHandles": ["ch-1", "ch-2", "ch-3"]}'