1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
|
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2021-2024 Nordix Foundation
* Modifications Copyright (C) 2022 Bell Canada
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
* ============LICENSE_END=========================================================
*/
package org.onap.cps.ncmp.api.impl.operations
import static org.onap.cps.ncmp.api.impl.operations.OperationType.READ
import static org.onap.cps.ncmp.api.impl.operations.RequiredDmiService.MODEL
import com.fasterxml.jackson.core.JsonProcessingException
import com.fasterxml.jackson.databind.ObjectMapper
import org.onap.cps.ncmp.api.impl.config.DmiProperties
import org.onap.cps.spi.model.ModuleReference
import org.onap.cps.utils.JsonObjectMapper
import org.spockframework.spring.SpringBean
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.test.context.ContextConfiguration
import spock.lang.Shared
@SpringBootTest
@ContextConfiguration(classes = [DmiProperties, DmiModelOperations])
class DmiModelOperationsSpec extends DmiOperationsBaseSpec {
@Shared
def newModuleReferences = [new ModuleReference('mod1','A'), new ModuleReference('mod2','X')]
@Autowired
DmiModelOperations objectUnderTest
@SpringBean
JsonObjectMapper spiedJsonObjectMapper = Spy(new JsonObjectMapper(new ObjectMapper()))
def NO_AUTH_HEADER = null
def 'Retrieving module references.'() {
given: 'a cm handle'
mockYangModelCmHandleRetrieval([])
and: 'a positive response from DMI service when it is called with the expected parameters'
def moduleReferencesAsLisOfMaps = [[moduleName: 'mod1', revision: 'A'], [moduleName: 'mod2', revision: 'X']]
def expectedUrl = "${dmiServiceName}/dmi/v1/ch/${cmHandleId}/modules"
def responseFromDmi = new ResponseEntity([schemas: moduleReferencesAsLisOfMaps], HttpStatus.OK)
mockDmiRestClient.synchronousPostOperationWithJsonData(MODEL, expectedUrl, '{"cmHandleProperties":{},"moduleSetTag":""}', READ, NO_AUTH_HEADER) >> responseFromDmi
when: 'get module references is called'
def result = objectUnderTest.getModuleReferences(yangModelCmHandle)
then: 'the result consists of expected module references'
assert result == [new ModuleReference(moduleName: 'mod1', revision: 'A'), new ModuleReference(moduleName: 'mod2', revision: 'X')]
}
def 'Retrieving module references edge case: #scenario.'() {
given: 'a cm handle'
mockYangModelCmHandleRetrieval([])
and: 'any response from DMI service when it is called with the expected parameters'
// TODO (toine): production code ignores any error code from DMI, this should be improved in future
def responseFromDmi = new ResponseEntity(bodyAsMap, HttpStatus.NO_CONTENT)
mockDmiRestClient.synchronousPostOperationWithJsonData(*_) >> responseFromDmi
when: 'get module references is called'
def result = objectUnderTest.getModuleReferences(yangModelCmHandle)
then: 'the result is empty'
assert result == []
where: 'the DMI response body has the following content'
scenario | bodyAsMap
'no modules' | [schemas:[]]
'modules null' | [schemas:null]
'no schema' | [something:'else']
'no body' | null
}
def 'Retrieving module references, DMI property handling: #scenario.'() {
given: 'a cm handle'
mockYangModelCmHandleRetrieval(dmiProperties)
and: 'a positive response from DMI service when it is called with tha expected parameters'
def responseFromDmi = new ResponseEntity<String>(HttpStatus.OK)
mockDmiRestClient.synchronousPostOperationWithJsonData(MODEL, "${dmiServiceName}/dmi/v1/ch/${cmHandleId}/modules",
'{"cmHandleProperties":' + expectedAdditionalPropertiesInRequest + ',"moduleSetTag":""}', READ, NO_AUTH_HEADER) >> responseFromDmi
when: 'a get module references is called'
def result = objectUnderTest.getModuleReferences(yangModelCmHandle)
then: 'the result is the response from DMI service'
assert result == []
where: 'the following DMI properties are used'
scenario | dmiProperties || expectedAdditionalPropertiesInRequest
'with properties' | [yangModelCmHandleProperty] || '{"prop1":"val1"}'
'without properties' | [] || '{}'
}
def 'Retrieving yang resources.'() {
given: 'a cm handle'
mockYangModelCmHandleRetrieval([])
and: 'a positive response from DMI service when it is called with the expected parameters'
def responseFromDmi = new ResponseEntity([[moduleName: 'mod1', revision: 'A', yangSource: 'some yang source'],
[moduleName: 'mod2', revision: 'C', yangSource: 'other yang source']], HttpStatus.OK)
def expectedModuleReferencesInRequest = '{"name":"mod1","revision":"A"},{"name":"mod2","revision":"X"}'
mockDmiRestClient.synchronousPostOperationWithJsonData(MODEL, "${dmiServiceName}/dmi/v1/ch/${cmHandleId}/moduleResources",
'{"data":{"modules":[' + expectedModuleReferencesInRequest + ']},"cmHandleProperties":{}}', READ, NO_AUTH_HEADER) >> responseFromDmi
when: 'get new yang resources from DMI service'
def result = objectUnderTest.getNewYangResourcesFromDmi(yangModelCmHandle, newModuleReferences)
then: 'the result has the 2 expected yang (re)sources (order is not guaranteed)'
assert result.size() == 2
assert result.get('mod1') == 'some yang source'
assert result.get('mod2') == 'other yang source'
}
def 'Retrieving yang resources, edge case: scenario.'() {
given: 'a cm handle'
mockYangModelCmHandleRetrieval([])
and: 'a positive response from DMI service when it is called with tha expected parameters'
// TODO (toine): production code ignores any error code from DMI, this should be improved in future
def responseFromDmi = new ResponseEntity(responseFromDmiBody, HttpStatus.NO_CONTENT)
mockDmiRestClient.synchronousPostOperationWithJsonData(*_) >> responseFromDmi
when: 'get new yang resources from DMI service'
def result = objectUnderTest.getNewYangResourcesFromDmi(yangModelCmHandle, newModuleReferences)
then: 'the result is empty'
assert result == [:]
where: 'the DMI response body has the following content'
scenario | responseFromDmiBody
'empty array' | []
'null array' | null
}
def 'Retrieving yang resources, DMI property handling #scenario.'() {
given: 'a cm handle'
mockYangModelCmHandleRetrieval(dmiProperties)
and: 'a positive response from DMI service when it is called with the expected moduleSetTag, modules and properties'
def responseFromDmi = new ResponseEntity<>([[moduleName: 'mod1', revision: 'A', yangSource: 'some yang source']], HttpStatus.OK)
mockDmiRestClient.synchronousPostOperationWithJsonData(MODEL, "${dmiServiceName}/dmi/v1/ch/${cmHandleId}/moduleResources",
'{"data":{"modules":[{"name":"mod1","revision":"A"},{"name":"mod2","revision":"X"}]},"cmHandleProperties":' + expectedAdditionalPropertiesInRequest + '}',
READ, NO_AUTH_HEADER) >> responseFromDmi
when: 'get new yang resources from DMI service'
def result = objectUnderTest.getNewYangResourcesFromDmi(yangModelCmHandle, newModuleReferences)
then: 'the result is the response from DMI service'
assert result == [mod1:'some yang source']
where: 'the following DMI properties are used'
scenario | dmiProperties || expectedAdditionalPropertiesInRequest
'with module references and properties' | [yangModelCmHandleProperty] || '{"prop1":"val1"}'
'without properties' | [] || '{}'
}
def 'Retrieving yang resources #scenario'() {
given: 'a cm handle'
mockYangModelCmHandleRetrieval([], moduleSetTag)
and: 'a positive response from DMI service when it is called with the expected moduleSetTag'
def responseFromDmi = new ResponseEntity<>([[moduleName: 'mod1', revision: 'A', yangSource: 'some yang source']], HttpStatus.OK)
mockDmiRestClient.synchronousPostOperationWithJsonData(MODEL, "${dmiServiceName}/dmi/v1/ch/${cmHandleId}/moduleResources",
'{' + expectedModuleSetTagInRequest + '"data":{"modules":[{"name":"mod1","revision":"A"},{"name":"mod2","revision":"X"}]},"cmHandleProperties":{}}',
READ, NO_AUTH_HEADER) >> responseFromDmi
when: 'get new yang resources from DMI service'
def result = objectUnderTest.getNewYangResourcesFromDmi(yangModelCmHandle, newModuleReferences)
then: 'the result is the response from DMI service'
assert result == [mod1:'some yang source']
where: 'the following Module Set Tags are used'
scenario | moduleSetTag || expectedModuleSetTagInRequest
'Without module set tag' | '' || ''
'With module set tag' | 'moduleSetTag1' || '"moduleSetTag":"moduleSetTag1",'
}
def 'Retrieving yang resources from DMI with no module references.'() {
given: 'a cm handle'
mockYangModelCmHandleRetrieval([])
when: 'a get new yang resources from DMI is called with no module references'
def result = objectUnderTest.getNewYangResourcesFromDmi(yangModelCmHandle, [])
then: 'no resources are returned'
assert result == [:]
and: 'no request is sent to DMI'
0 * mockDmiRestClient.synchronousPostOperationWithJsonData(*_)
}
def 'Retrieving yang resources from DMI with null DMI properties.'() {
given: 'a cm handle'
mockYangModelCmHandleRetrieval(null)
when: 'a get new yang resources from DMI is called'
objectUnderTest.getNewYangResourcesFromDmi(yangModelCmHandle, [new ModuleReference('mod1', 'A')])
then: 'a null pointer is thrown (we might need to address this later)'
thrown(NullPointerException)
}
def 'Retrieving module references with Json processing exception.'() {
given: 'a cm handle'
mockYangModelCmHandleRetrieval([])
and: 'a Json processing exception occurs'
spiedJsonObjectMapper.asJsonString(_) >> {throw (new JsonProcessingException('parsing error'))}
when: 'a DMI operation is executed'
objectUnderTest.getModuleReferences(yangModelCmHandle)
then: 'an ncmp exception is thrown'
def exceptionThrown = thrown(JsonProcessingException)
and: 'the message indicates a parsing error'
exceptionThrown.message.toLowerCase().contains('parsing error')
}
}
|