2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2022 Nordix Foundation
4 * ================================================================================
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 * SPDX-License-Identifier: Apache-2.0
18 * ============LICENSE_END=========================================================
21 package org.onap.cps.ncmp.api.impl
23 import org.onap.cps.cpspath.parser.PathParsingException
24 import org.onap.cps.ncmp.api.inventory.CmHandleQueries
25 import org.onap.cps.ncmp.api.inventory.InventoryPersistence
26 import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
27 import org.onap.cps.spi.FetchDescendantsOption
28 import org.onap.cps.spi.exceptions.DataInUseException
29 import org.onap.cps.spi.exceptions.DataValidationException
30 import org.onap.cps.spi.model.Anchor
31 import org.onap.cps.spi.model.CmHandleQueryServiceParameters
32 import org.onap.cps.spi.model.ConditionProperties
33 import org.onap.cps.spi.model.DataNode
34 import spock.lang.Specification
36 import java.util.stream.Collectors
38 class NetworkCmProxyCmHandlerQueryServiceSpec extends Specification {
40 def cmHandleQueries = Mock(CmHandleQueries)
41 def inventoryPersistence = Mock(InventoryPersistence)
43 def static someCmHandleDataNode = new DataNode(xpath: '/dmi-registry/cm-handles[@id=\'some-cmhandle-id\']', leaves: ['id':'some-cmhandle-id'])
44 def dmiRegistry = new DataNode(xpath: '/dmi-registry', childDataNodes: createDataNodeList(['PNFDemo1', 'PNFDemo2', 'PNFDemo3', 'PNFDemo4']))
46 def objectUnderTest = new NetworkCmProxyCmHandlerQueryServiceImpl(cmHandleQueries, inventoryPersistence)
48 def 'Retrieve cm handles with cpsPath when combined with no Module Query.'() {
49 given: 'a cmHandleWithCpsPath condition property'
50 def cmHandleQueryParameters = new CmHandleQueryServiceParameters()
51 def conditionProperties = createConditionProperties('cmHandleWithCpsPath', [['cpsPath' : '/some/cps/path']])
52 cmHandleQueryParameters.setCmHandleQueryParameters([conditionProperties])
53 and: 'cmHandleQueries returns a non null query result'
54 cmHandleQueries.queryCmHandleDataNodesByCpsPath('/some/cps/path', FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> [new DataNode(leaves: ['id':'some-cmhandle-id'])]
55 and: 'CmHandleQueries returns cmHandles with the relevant query result'
56 cmHandleQueries.combineCmHandleQueries(*_) >> ['PNFDemo1': new NcmpServiceCmHandle(cmHandleId: 'PNFDemo1'), 'PNFDemo3': new NcmpServiceCmHandle(cmHandleId: 'PNFDemo3')]
57 when: 'the query is executed for both cm handle ids and details'
58 def returnedCmHandlesJustIds = objectUnderTest.queryCmHandleIds(cmHandleQueryParameters)
59 def returnedCmHandlesWithData = objectUnderTest.queryCmHandles(cmHandleQueryParameters)
60 then: 'the correct expected cm handles ids are returned'
61 returnedCmHandlesJustIds == ['PNFDemo1', 'PNFDemo3'] as Set
62 and: 'the correct ncmp service cm handles are returned'
63 returnedCmHandlesWithData.stream().map(CmHandle -> CmHandle.cmHandleId).collect(Collectors.toSet()) == ['PNFDemo1', 'PNFDemo3'] as Set
66 def 'Retrieve cm handles with cpsPath where #scenario.'() {
67 given: 'a cmHandleWithCpsPath condition property'
68 def cmHandleQueryParameters = new CmHandleQueryServiceParameters()
69 def conditionProperties = createConditionProperties('cmHandleWithCpsPath', [['cpsPath' : '/some/cps/path']])
70 cmHandleQueryParameters.setCmHandleQueryParameters([conditionProperties])
71 and: 'cmHandleQueries throws a path parsing exception'
72 cmHandleQueries.queryCmHandleDataNodesByCpsPath('/some/cps/path', FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> { throw thrownException }
73 when: 'the query is executed for both cm handle ids and details'
74 objectUnderTest.queryCmHandleIds(cmHandleQueryParameters)
75 objectUnderTest.queryCmHandles(cmHandleQueryParameters)
76 then: 'a data validation exception is thrown'
77 thrown(expectedException)
78 where: 'the following data is used'
79 scenario | thrownException || expectedException
80 'a PathParsingException is thrown' | new PathParsingException('some message', 'some details') || DataValidationException
81 'any other Exception is thrown' | new DataInUseException('some message', 'some details') || DataInUseException
84 def 'Query cm handles with public properties when combined with empty modules query result.'() {
85 given: 'a public properties condition property'
86 def cmHandleQueryParameters = new CmHandleQueryServiceParameters()
87 def conditionProperties = createConditionProperties('hasAllProperties', [['some-property-key': 'some-property-value']])
88 cmHandleQueryParameters.setCmHandleQueryParameters([conditionProperties])
89 and: 'CmHandleQueries returns cmHandles with the relevant query result'
90 cmHandleQueries.combineCmHandleQueries(*_) >> ['PNFDemo1': new NcmpServiceCmHandle(cmHandleId: 'PNFDemo1'), 'PNFDemo3': new NcmpServiceCmHandle(cmHandleId: 'PNFDemo3')]
91 when: 'the query is executed for both cm handle ids and details'
92 def returnedCmHandlesJustIds = objectUnderTest.queryCmHandleIds(cmHandleQueryParameters)
93 def returnedCmHandlesWithData = objectUnderTest.queryCmHandles(cmHandleQueryParameters)
94 then: 'the correct expected cm handles ids are returned'
95 returnedCmHandlesJustIds == ['PNFDemo1', 'PNFDemo3'] as Set
96 and: 'the correct cm handle data objects are returned'
97 returnedCmHandlesWithData.stream().map(dataNode -> dataNode.cmHandleId).collect(Collectors.toSet()) == ['PNFDemo1', 'PNFDemo3'] as Set
100 def 'Retrieve cm handles with module names when #scenario from query.'() {
101 given: 'a modules condition property'
102 def cmHandleQueryParameters = new CmHandleQueryServiceParameters()
103 def conditionProperties = createConditionProperties('hasAllModules', [['moduleName': 'some-module-name']])
104 cmHandleQueryParameters.setCmHandleQueryParameters([conditionProperties])
105 and: 'null is returned from the state and public property queries'
106 cmHandleQueries.combineCmHandleQueries(*_) >> null
107 and: '#scenario from the modules query'
108 inventoryPersistence.queryAnchors(*_) >> returnedAnchors
109 and: 'the same cmHandles are returned from the persistence service layer'
110 returnedAnchors.size() * inventoryPersistence.getDataNode(*_) >> returnedCmHandles
111 when: 'the query is executed for both cm handle ids and details'
112 def returnedCmHandlesJustIds = objectUnderTest.queryCmHandleIds(cmHandleQueryParameters)
113 def returnedCmHandlesWithData = objectUnderTest.queryCmHandles(cmHandleQueryParameters)
114 then: 'the correct expected cm handles ids are returned'
115 returnedCmHandlesJustIds == expectedCmHandleIds as Set
116 and: 'the correct cm handle data objects are returned'
117 returnedCmHandlesWithData.stream().map(dataNode -> dataNode.cmHandleId).collect(Collectors.toSet()) == expectedCmHandleIds as Set
118 where: 'the following data is used'
119 scenario | returnedAnchors | returnedCmHandles || expectedCmHandleIds
120 'One anchor returned' | [new Anchor(name: 'some-cmhandle-id')] | someCmHandleDataNode || ['some-cmhandle-id']
121 'No anchors are returned' | [] | null || []
124 def 'Retrieve cm handles with combined queries when #scenario.'() {
125 given: 'all condition properties used'
126 def cmHandleQueryParameters = new CmHandleQueryServiceParameters()
127 def conditionPubProps = createConditionProperties('hasAllProperties', [['some-property-key': 'some-property-value']])
128 def conditionModules = createConditionProperties('hasAllModules', [['moduleName': 'some-module-name']])
129 def conditionState = createConditionProperties('cmHandleWithCpsPath', [['cpsPath' : '/some/cps/path']])
130 cmHandleQueryParameters.setCmHandleQueryParameters([conditionPubProps, conditionModules, conditionState])
131 and: 'cmHandles are returned from the state and public property combined queries'
132 cmHandleQueries.combineCmHandleQueries(*_) >> combinedQueryMap
133 and: 'cmHandles are returned from the module names query'
134 inventoryPersistence.queryAnchors(['some-module-name']) >> anchorsForModuleQuery
135 and: 'cmHandleQueries returns a datanode result'
136 2 * cmHandleQueries.queryCmHandleDataNodesByCpsPath(*_) >> [someCmHandleDataNode]
137 when: 'the query is executed for both cm handle ids and details'
138 def returnedCmHandlesJustIds = objectUnderTest.queryCmHandleIds(cmHandleQueryParameters)
139 def returnedCmHandlesWithData = objectUnderTest.queryCmHandles(cmHandleQueryParameters)
140 then: 'the correct expected cm handles ids are returned'
141 returnedCmHandlesJustIds == expectedCmHandleIds as Set
142 and: 'the correct cm handle data objects are returned'
143 returnedCmHandlesWithData.stream().map(dataNode -> dataNode.cmHandleId).collect(Collectors.toSet()) == expectedCmHandleIds as Set
144 where: 'the following data is used'
145 scenario | combinedQueryMap | anchorsForModuleQuery || expectedCmHandleIds
146 'combined and modules queries intersect' | ['PNFDemo1' : new NcmpServiceCmHandle(cmHandleId:'PNFDemo1')] | [new Anchor(name: 'PNFDemo1'), new Anchor(name: 'PNFDemo2')] || ['PNFDemo1']
147 'only module query results exist' | [:] | [new Anchor(name: 'PNFDemo1'), new Anchor(name: 'PNFDemo2')] || []
148 'only combined query results exist' | ['PNFDemo1' : new NcmpServiceCmHandle(cmHandleId:'PNFDemo1'), 'PNFDemo2' : new NcmpServiceCmHandle(cmHandleId:'PNFDemo2')] | [] || []
149 'neither queries return results' | [:] | [] || []
150 'none intersect' | ['PNFDemo1' : new NcmpServiceCmHandle(cmHandleId:'PNFDemo1')] | [new Anchor(name: 'PNFDemo2')] || []
153 def 'Retrieve cm handles when the query is empty.'() {
154 given: 'We use an empty query'
155 def cmHandleQueryParameters = new CmHandleQueryServiceParameters()
156 and: 'the inventory persistence returns the dmi registry datanode'
157 inventoryPersistence.getDataNode("/dmi-registry") >> dmiRegistry
158 when: 'the query is executed for both cm handle ids and details'
159 def returnedCmHandlesJustIds = objectUnderTest.queryCmHandleIds(cmHandleQueryParameters)
160 def returnedCmHandlesWithData = objectUnderTest.queryCmHandles(cmHandleQueryParameters)
161 then: 'the correct expected cm handles are returned'
162 returnedCmHandlesJustIds == ['PNFDemo1', 'PNFDemo2', 'PNFDemo3', 'PNFDemo4'] as Set
163 returnedCmHandlesWithData.stream().map(d -> d.cmHandleId).collect(Collectors.toSet()) == ['PNFDemo1', 'PNFDemo2', 'PNFDemo3', 'PNFDemo4'] as Set
166 def createConditionProperties(String conditionName, List<Map<String, String>> conditionParameters) {
167 return new ConditionProperties(conditionName : conditionName, conditionParameters : conditionParameters)
170 def static createDataNodeList(dataNodeIds) {
172 dataNodeIds.forEach(id -> {dataNodes.add(new DataNode(xpath: '/dmi-registry/cm-handles[@id=\'' + id + '\']', leaves: ['id':id]))})