2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2021 Pantheon.tech
4 * Modification Copyright (C) 2021 highstreet technologies GmbH
5 * Modification Copyright (C) 2021-2022 Nordix Foundation
6 * Modification Copyright (C) 2021 Bell Canada.
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
19 * SPDX-License-Identifier: Apache-2.0
20 * ============LICENSE_END=========================================================
23 package org.onap.cps.ncmp.rest.controller
25 import org.onap.cps.TestUtils
26 import org.onap.cps.spi.model.ModuleReference
28 import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.PATCH
29 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete
30 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
31 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch
32 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post
33 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put
34 import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.CREATE
35 import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.UPDATE
36 import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.DELETE
38 import org.onap.cps.ncmp.api.NetworkCmProxyDataService
39 import org.spockframework.spring.SpringBean
40 import org.springframework.beans.factory.annotation.Autowired
41 import org.springframework.beans.factory.annotation.Value
42 import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
43 import org.springframework.http.HttpStatus
44 import org.springframework.http.MediaType
45 import org.springframework.test.web.servlet.MockMvc
46 import spock.lang.Specification
48 @WebMvcTest(NetworkCmProxyController)
49 class NetworkCmProxyControllerSpec extends Specification {
55 NetworkCmProxyDataService mockNetworkCmProxyDataService = Mock()
57 @Value('${rest.api.ncmp-base-path}/v1')
60 def jsonString = '{"some-key":"some-value"}'
62 def 'Get Resource Data from pass-through operational.' () {
63 given: 'resource data url'
64 def getUrl = "$ncmpBasePathV1/ch/testCmHandle/data/ds/ncmp-datastore:passthrough-operational" +
65 "?resourceIdentifier=parent/child&options=(a=1,b=2)"
66 when: 'get data resource request is performed'
67 def response = mvc.perform(
69 .contentType(MediaType.APPLICATION_JSON)
70 .accept(MediaType.APPLICATION_JSON_VALUE)
71 ).andReturn().response
72 then: 'the NCMP data service is called with getResourceDataOperationalForCmHandle'
73 1 * mockNetworkCmProxyDataService.getResourceDataOperationalForCmHandle('testCmHandle',
77 and: 'response status is Ok'
78 response.status == HttpStatus.OK.value()
81 def 'Get Resource Data from pass-through running with #scenario value in resource identifier param.' () {
82 given: 'resource data url'
83 def getUrl = "$ncmpBasePathV1/ch/testCmHandle/data/ds/ncmp-datastore:passthrough-running" +
84 "?resourceIdentifier=" + resourceIdentifier + "&options=(a=1,b=2)"
85 and: 'ncmp service returns json object'
86 mockNetworkCmProxyDataService.getResourceDataPassThroughRunningForCmHandle('testCmHandle',
89 '(a=1,b=2)') >> '{valid-json}'
90 when: 'get data resource request is performed'
91 def response = mvc.perform(
93 .contentType(MediaType.APPLICATION_JSON)
94 .accept(MediaType.APPLICATION_JSON_VALUE)
95 ).andReturn().response
96 then: 'response status is Ok'
97 response.status == HttpStatus.OK.value()
98 and: 'response contains valid object body'
99 response.getContentAsString() == '{valid-json}'
100 where: 'tokens are used in the resource identifier parameter'
101 scenario | resourceIdentifier
102 '/' | 'id/with/slashes'
107 '? needs to be encoded as %3F' | 'idWith%3F'
110 def 'Update resource data from pass-through running.' () {
111 given: 'update resource data url'
112 def updateUrl = "$ncmpBasePathV1/ch/testCmHandle/data/ds/ncmp-datastore:passthrough-running" +
113 "?resourceIdentifier=parent/child"
114 when: 'update data resource request is performed'
115 def response = mvc.perform(
117 .contentType(MediaType.APPLICATION_JSON_VALUE)
118 .accept(MediaType.APPLICATION_JSON_VALUE).content(jsonString)
119 ).andReturn().response
120 then: 'ncmp service method to update resource is called'
121 1 * mockNetworkCmProxyDataService.writeResourceDataPassThroughRunningForCmHandle('testCmHandle',
122 'parent/child', UPDATE, jsonString, 'application/json;charset=UTF-8')
123 and: 'the response status is OK'
124 response.status == HttpStatus.OK.value()
127 def 'Create Resource Data from pass-through running with #scenario.' () {
128 given: 'resource data url'
129 def url = "$ncmpBasePathV1/ch/testCmHandle/data/ds/ncmp-datastore:passthrough-running" +
130 "?resourceIdentifier=parent/child"
131 def requestBody = '{"some-key":"some-value"}'
132 when: 'create resource request is performed'
133 def response = mvc.perform(
135 .contentType(MediaType.APPLICATION_JSON_VALUE)
136 .accept(MediaType.APPLICATION_JSON_VALUE).content(requestBody)
137 ).andReturn().response
138 then: 'ncmp service method to create resource called'
139 1 * mockNetworkCmProxyDataService.writeResourceDataPassThroughRunningForCmHandle('testCmHandle',
140 'parent/child', CREATE, requestBody, 'application/json;charset=UTF-8')
141 and: 'resource is created'
142 response.status == HttpStatus.CREATED.value()
145 def 'Get module references for the given dataspace and cm handle.' () {
146 given: 'get module references url'
147 def getUrl = "$ncmpBasePathV1/ch/some-cmhandle/modules"
148 when: 'get module resource request is performed'
149 def response =mvc.perform(get(getUrl)).andReturn().response
150 then: 'ncmp service method to get yang resource module references is called'
151 mockNetworkCmProxyDataService.getYangResourcesModuleReferences('some-cmhandle')
152 >> [new ModuleReference(moduleName: 'some-name1',revision: '2021-10-03')]
153 and: 'response contains an array with the module name and revision'
154 response.getContentAsString() == '[{"moduleName":"some-name1","revision":"2021-10-03"}]'
155 and: 'response returns an OK http code'
156 response.status == HttpStatus.OK.value()
159 def 'Retrieve cm handles.'() {
160 given: 'an endpoint and json data'
161 def searchesEndpoint = "$ncmpBasePathV1/ch/searches"
162 String jsonString = TestUtils.getResourceFileContent('cmhandle-search.json')
163 and: 'the service method is invoked with module names and returns two cm handle ids'
164 mockNetworkCmProxyDataService.executeCmHandleHasAllModulesSearch(['module1', 'module2']) >> ['some-cmhandle-id1', 'some-cmhandle-id2']
165 when: 'the searches api is invoked'
166 def response = mvc.perform(post(searchesEndpoint)
167 .contentType(MediaType.APPLICATION_JSON)
168 .content(jsonString)).andReturn().response
169 then: 'response status returns OK'
170 response.status == HttpStatus.OK.value()
171 and: 'the expected response content is returned'
172 response.contentAsString == '{"cmHandles":[{"cmHandleId":"some-cmhandle-id1"},{"cmHandleId":"some-cmhandle-id2"}]}'
175 def 'Call execute cm handle searches with unrecognized condition name.'() {
176 given: 'an endpoint and json data'
177 def searchesEndpoint = "$ncmpBasePathV1/ch/searches"
178 String jsonString = TestUtils.getResourceFileContent('invalid-cmhandle-search.json')
179 when: 'the searches api is invoked'
180 def response = mvc.perform(post(searchesEndpoint)
181 .contentType(MediaType.APPLICATION_JSON)
182 .content(jsonString)).andReturn().response
183 then: 'an empty cm handle identifier is returned'
184 response.contentAsString == '{"cmHandles":[]}'
187 def 'Patch resource data in pass-through running datastore.' () {
188 given: 'patch resource data url'
189 def url = "$ncmpBasePathV1/ch/testCmHandle/data/ds/ncmp-datastore:passthrough-running" +
190 "?resourceIdentifier=parent/child"
191 when: 'patch data resource request is performed'
192 def response = mvc.perform(
194 .contentType(MediaType.APPLICATION_JSON)
195 .accept(MediaType.APPLICATION_JSON).content(jsonString)
196 ).andReturn().response
197 then: 'ncmp service method to update resource is called'
198 1 * mockNetworkCmProxyDataService.writeResourceDataPassThroughRunningForCmHandle('testCmHandle',
199 'parent/child', PATCH, jsonString, 'application/json;charset=UTF-8')
200 and: 'the response status is OK'
201 response.status == HttpStatus.OK.value()
204 def 'Delete resource data in pass-through running datastore.' () {
205 given: 'delete resource data url'
206 def url = "$ncmpBasePathV1/ch/testCmHandle/data/ds/ncmp-datastore:passthrough-running" +
207 "?resourceIdentifier=parent/child"
208 when: 'delete data resource request is performed'
209 def response = mvc.perform(
210 delete(url).contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)).andReturn().response
211 then: 'the ncmp service method to delete resource is called (with null as body)'
212 1 * mockNetworkCmProxyDataService.writeResourceDataPassThroughRunningForCmHandle('testCmHandle',
213 'parent/child', DELETE, null, 'application/json;charset=UTF-8')
214 and: 'the response is No Content'
215 response.status == HttpStatus.NO_CONTENT.value()