Query CmHandles using CPS path
[cps.git] / cps-ncmp-service / src / test / groovy / org / onap / cps / ncmp / api / impl / NetworkCmProxyCmHandlerQueryServiceSpec.groovy
1 /*
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
8  *
9  *        http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  *
17  *  SPDX-License-Identifier: Apache-2.0
18  *  ============LICENSE_END=========================================================
19  */
20
21 package org.onap.cps.ncmp.api.impl
22
23 import org.onap.cps.cpspath.parser.PathParsingException
24 import org.onap.cps.ncmp.api.NetworkCmProxyCmHandlerQueryService
25 import org.onap.cps.ncmp.api.inventory.InventoryPersistence
26 import org.onap.cps.ncmp.api.inventory.CmHandleQueries
27 import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
28 import org.onap.cps.spi.FetchDescendantsOption
29 import org.onap.cps.spi.exceptions.DataInUseException
30 import org.onap.cps.spi.exceptions.DataValidationException
31 import org.onap.cps.spi.model.Anchor
32 import org.onap.cps.spi.model.CmHandleQueryServiceParameters
33 import org.onap.cps.spi.model.ConditionProperties
34 import org.onap.cps.spi.model.DataNode
35 import spock.lang.Specification
36
37 import java.util.stream.Collectors
38
39 class NetworkCmProxyCmHandlerQueryServiceSpec extends Specification {
40
41     def cmHandleQueries = Mock(CmHandleQueries)
42     def inventoryPersistence = Mock(InventoryPersistence)
43
44     def static someCmHandleDataNode = new DataNode(xpath: '/dmi-registry/cm-handles[@id=\'some-cmhandle-id\']', leaves: ['id':'some-cmhandle-id'])
45     def dmiRegistry = new DataNode(xpath: '/dmi-registry', childDataNodes: createDataNodeList(['PNFDemo1', 'PNFDemo2', 'PNFDemo3', 'PNFDemo4']))
46
47     def objectUnderTest = new NetworkCmProxyCmHandlerQueryServiceImpl(cmHandleQueries, inventoryPersistence)
48
49     def 'Retrieve cm handles with cpsPath when combined with no Module Query.'() {
50         given: 'a cmHandleWithCpsPath condition property'
51             def cmHandleQueryParameters = new CmHandleQueryServiceParameters()
52             def conditionProperties = createConditionProperties('cmHandleWithCpsPath', [['cpsPath' : '/some/cps/path']])
53             cmHandleQueryParameters.setCmHandleQueryParameters([conditionProperties])
54         and: 'cmHandleQueries returns a non null query result'
55             cmHandleQueries.getCmHandleDataNodesByCpsPath('/some/cps/path', FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> [new DataNode(leaves: ['id':'some-cmhandle-id'])]
56         and: 'CmHandleQueries returns cmHandles with the relevant query result'
57             cmHandleQueries.combineCmHandleQueries(*_) >> ['PNFDemo1': new NcmpServiceCmHandle(cmHandleId: 'PNFDemo1'), 'PNFDemo3': new NcmpServiceCmHandle(cmHandleId: 'PNFDemo3')]
58         when: 'the query is executed for both cm handle ids and details'
59             def returnedCmHandlesJustIds = objectUnderTest.queryCmHandleIds(cmHandleQueryParameters)
60             def returnedCmHandlesWithData = objectUnderTest.queryCmHandles(cmHandleQueryParameters)
61         then: 'the correct expected cm handles ids are returned'
62             returnedCmHandlesJustIds == ['PNFDemo1', 'PNFDemo3'] as Set
63         and: 'the correct ncmp service cm handles are returned'
64             returnedCmHandlesWithData.stream().map(CmHandle -> CmHandle.cmHandleId).collect(Collectors.toSet()) == ['PNFDemo1', 'PNFDemo3'] as Set
65     }
66
67     def 'Retrieve cm handles with cpsPath where #scenario.'() {
68         given: 'a cmHandleWithCpsPath condition property'
69             def cmHandleQueryParameters = new CmHandleQueryServiceParameters()
70             def conditionProperties = createConditionProperties('cmHandleWithCpsPath', [['cpsPath' : '/some/cps/path']])
71             cmHandleQueryParameters.setCmHandleQueryParameters([conditionProperties])
72         and: 'cmHandleQueries throws a path parsing exception'
73             cmHandleQueries.getCmHandleDataNodesByCpsPath('/some/cps/path', FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> { throw thrownException }
74         when: 'the query is executed for both cm handle ids and details'
75             objectUnderTest.queryCmHandleIds(cmHandleQueryParameters)
76             objectUnderTest.queryCmHandles(cmHandleQueryParameters)
77         then: 'a data validation exception is thrown'
78             thrown(expectedException)
79         where: 'the following data is used'
80             scenario                           | thrownException                                          || expectedException
81             'a PathParsingException is thrown' | new PathParsingException('some message', 'some details') || DataValidationException
82             'any other Exception is thrown'    | new DataInUseException('some message', 'some details')   || DataInUseException
83     }
84
85     def 'Query cm handles with public properties when combined with empty modules query result.'() {
86         given: 'a public properties condition property'
87             def cmHandleQueryParameters = new CmHandleQueryServiceParameters()
88             def conditionProperties = createConditionProperties('hasAllProperties', [['some-property-key': 'some-property-value']])
89             cmHandleQueryParameters.setCmHandleQueryParameters([conditionProperties])
90         and: 'CmHandleQueries returns cmHandles with the relevant query result'
91             cmHandleQueries.combineCmHandleQueries(*_) >> ['PNFDemo1': new NcmpServiceCmHandle(cmHandleId: 'PNFDemo1'), 'PNFDemo3': new NcmpServiceCmHandle(cmHandleId: 'PNFDemo3')]
92         when: 'the query is executed for both cm handle ids and details'
93             def returnedCmHandlesJustIds = objectUnderTest.queryCmHandleIds(cmHandleQueryParameters)
94             def returnedCmHandlesWithData = objectUnderTest.queryCmHandles(cmHandleQueryParameters)
95         then: 'the correct expected cm handles ids are returned'
96             returnedCmHandlesJustIds == ['PNFDemo1', 'PNFDemo3'] as Set
97         and: 'the correct cm handle data objects are returned'
98             returnedCmHandlesWithData.stream().map(dataNode -> dataNode.cmHandleId).collect(Collectors.toSet()) == ['PNFDemo1', 'PNFDemo3'] as Set
99     }
100
101     def 'Retrieve cm handles with module names when #scenario from query.'() {
102         given: 'a modules condition property'
103             def cmHandleQueryParameters = new CmHandleQueryServiceParameters()
104             def conditionProperties = createConditionProperties('hasAllModules', [['moduleName': 'some-module-name']])
105             cmHandleQueryParameters.setCmHandleQueryParameters([conditionProperties])
106         and: 'null is returned from the state and public property queries'
107             cmHandleQueries.combineCmHandleQueries(*_) >> null
108         and: '#scenario from the modules query'
109             inventoryPersistence.queryAnchors(*_) >> returnedAnchors
110         and: 'the same cmHandles are returned from the persistence service layer'
111             returnedAnchors.size() * inventoryPersistence.getDataNode(*_) >> returnedCmHandles
112         when: 'the query is executed for both cm handle ids and details'
113             def returnedCmHandlesJustIds = objectUnderTest.queryCmHandleIds(cmHandleQueryParameters)
114             def returnedCmHandlesWithData = objectUnderTest.queryCmHandles(cmHandleQueryParameters)
115         then: 'the correct expected cm handles ids are returned'
116             returnedCmHandlesJustIds == expectedCmHandleIds as Set
117         and: 'the correct cm handle data objects are returned'
118             returnedCmHandlesWithData.stream().map(dataNode -> dataNode.cmHandleId).collect(Collectors.toSet()) == expectedCmHandleIds as Set
119         where: 'the following data is used'
120             scenario                  | returnedAnchors                        | returnedCmHandles    || expectedCmHandleIds
121             'One anchor returned'     | [new Anchor(name: 'some-cmhandle-id')] | someCmHandleDataNode || ['some-cmhandle-id']
122             'No anchors are returned' | []                                     | null                 || []
123     }
124
125     def 'Retrieve cm handles with combined queries when #scenario.'() {
126         given: 'all condition properties used'
127             def cmHandleQueryParameters = new CmHandleQueryServiceParameters()
128             def conditionPubProps = createConditionProperties('hasAllProperties', [['some-property-key': 'some-property-value']])
129             def conditionModules = createConditionProperties('hasAllModules', [['moduleName': 'some-module-name']])
130             def conditionState = createConditionProperties('cmHandleWithCpsPath', [['cpsPath' : '/some/cps/path']])
131             cmHandleQueryParameters.setCmHandleQueryParameters([conditionPubProps, conditionModules, conditionState])
132         and: 'cmHandles are returned from the state and public property combined queries'
133             cmHandleQueries.combineCmHandleQueries(*_) >> combinedQueryMap
134         and: 'cmHandles are returned from the module names query'
135             inventoryPersistence.queryAnchors(['some-module-name']) >> anchorsForModuleQuery
136         and: 'cmHandleQueries returns a datanode result'
137             2 * cmHandleQueries.getCmHandleDataNodesByCpsPath(*_) >> [someCmHandleDataNode]
138         when: 'the query is executed for both cm handle ids and details'
139             def returnedCmHandlesJustIds = objectUnderTest.queryCmHandleIds(cmHandleQueryParameters)
140             def returnedCmHandlesWithData = objectUnderTest.queryCmHandles(cmHandleQueryParameters)
141         then: 'the correct expected cm handles ids are returned'
142             returnedCmHandlesJustIds == expectedCmHandleIds as Set
143         and: 'the correct cm handle data objects are returned'
144             returnedCmHandlesWithData.stream().map(dataNode -> dataNode.cmHandleId).collect(Collectors.toSet()) == expectedCmHandleIds as Set
145         where: 'the following data is used'
146             scenario                                 | combinedQueryMap                                                                                                           | anchorsForModuleQuery                                        || expectedCmHandleIds
147             'combined and modules queries intersect' | ['PNFDemo1' : new NcmpServiceCmHandle(cmHandleId:'PNFDemo1')]                                                              | [new Anchor(name: 'PNFDemo1'), new Anchor(name: 'PNFDemo2')] || ['PNFDemo1']
148             'only module query results exist'        | [:]                                                                                                                        | [new Anchor(name: 'PNFDemo1'), new Anchor(name: 'PNFDemo2')] || []
149             'only combined query results exist'      | ['PNFDemo1' : new NcmpServiceCmHandle(cmHandleId:'PNFDemo1'), 'PNFDemo2' : new NcmpServiceCmHandle(cmHandleId:'PNFDemo2')] | []                                                           || []
150             'neither queries return results'         | [:]                                                                                                                        | []                                                           || []
151             'none intersect'                         | ['PNFDemo1' : new NcmpServiceCmHandle(cmHandleId:'PNFDemo1')]                                                              | [new Anchor(name: 'PNFDemo2')]                               || []
152     }
153
154     def 'Retrieve cm handles when the query is empty.'() {
155         given: 'We use an empty query'
156             def cmHandleQueryParameters = new CmHandleQueryServiceParameters()
157         and: 'the inventory persistence returns the dmi registry datanode'
158             inventoryPersistence.getDataNode("/dmi-registry") >> dmiRegistry
159         and: 'the inventory persistence returns anchors for get anchors'
160             inventoryPersistence.getAnchors() >> [new Anchor(name: 'PNFDemo1'), new Anchor(name: 'PNFDemo2'), new Anchor(name: 'PNFDemo3'), new Anchor(name: 'PNFDemo4')]
161         when: 'the query is executed for both cm handle ids and details'
162             def returnedCmHandlesJustIds = objectUnderTest.queryCmHandleIds(cmHandleQueryParameters)
163             def returnedCmHandlesWithData = objectUnderTest.queryCmHandles(cmHandleQueryParameters)
164         then: 'the correct expected cm handles are returned'
165             returnedCmHandlesJustIds == ['PNFDemo1', 'PNFDemo2', 'PNFDemo3', 'PNFDemo4'] as Set
166             returnedCmHandlesWithData.stream().map(d -> d.cmHandleId).collect(Collectors.toSet()) == ['PNFDemo1', 'PNFDemo2', 'PNFDemo3', 'PNFDemo4'] as Set
167     }
168
169     def createConditionProperties(String conditionName, List<Map<String, String>> conditionParameters) {
170         return new ConditionProperties(conditionName : conditionName, conditionParameters : conditionParameters)
171     }
172
173     def static createDataNodeList(dataNodeIds) {
174         def dataNodes =[]
175         dataNodeIds.forEach(id -> {dataNodes.add(new DataNode(xpath: '/dmi-registry/cm-handles[@id=\'' + id + '\']', leaves: ['id':id]))})
176         return dataNodes
177     }
178 }