Merge "Add Kafka message lib consumer services"
[ccsdk/cds.git] / ms / blueprintsprocessor / functions / resource-resolution / src / test / kotlin / org / onap / ccsdk / cds / blueprintsprocessor / functions / resource / resolution / utils / ResourceAssignmentUtilsTest.kt
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2019 Nordix Foundation.
4  * Modifications Copyright (c) 2019 IBM, Bell Canada.
5  * ================================================================================
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * SPDX-License-Identifier: Apache-2.0
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.utils
23
24 import com.fasterxml.jackson.databind.JsonNode
25 import com.fasterxml.jackson.databind.node.NullNode
26 import com.fasterxml.jackson.databind.node.TextNode
27 import io.mockk.every
28 import io.mockk.spyk
29 import org.junit.Before
30 import org.junit.Test
31 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.ResourceAssignmentRuntimeService
32 import org.onap.ccsdk.cds.controllerblueprints.core.asJsonPrimitive
33 import org.onap.ccsdk.cds.controllerblueprints.core.asJsonType
34 import org.onap.ccsdk.cds.controllerblueprints.core.data.DataType
35 import org.onap.ccsdk.cds.controllerblueprints.core.data.EntrySchema
36 import org.onap.ccsdk.cds.controllerblueprints.core.data.PropertyDefinition
37 import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintMetadataUtils
38 import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
39 import org.onap.ccsdk.cds.controllerblueprints.resource.dict.ResourceAssignment
40 import kotlin.test.assertEquals
41
42 data class IpAddress(val port: String, val ip: String)
43 data class Host(val name: String, val ipAddress: IpAddress)
44 data class ExpectedResponseIp(val ip: String)
45 data class ExpectedResponsePort(val port: String)
46
47 class ResourceAssignmentUtilsTest {
48     private lateinit var resourceAssignmentRuntimeService: ResourceAssignmentRuntimeService
49
50     @Before
51     fun setup() {
52
53         val bluePrintContext = BluePrintMetadataUtils.getBluePrintContext(
54                 "./../../../../components/model-catalog/blueprint-model/test-blueprint/baseconfiguration")
55
56         resourceAssignmentRuntimeService = spyk(ResourceAssignmentRuntimeService("1234", bluePrintContext))
57
58         val propertiesDefinition1 = PropertyDefinition().apply {
59             type = "string"
60             id = "port"
61         }
62
63         val propertiesDefinition2 = PropertyDefinition().apply {
64             type = "string"
65             id = "ip"
66         }
67
68         val propertiesDefinition3 = PropertyDefinition().apply {
69             type = "string"
70             id = "name"
71         }
72
73         val propertiesDefinition4 = PropertyDefinition().apply {
74             type = "ip-address"
75             id = "ipAddress"
76         }
77
78         var mapOfPropertiesIpAddress = mutableMapOf<String, PropertyDefinition>()
79         mapOfPropertiesIpAddress["port"] = propertiesDefinition1
80         mapOfPropertiesIpAddress["ip"] = propertiesDefinition2
81
82         var mapOfPropertiesHost = mutableMapOf<String, PropertyDefinition>()
83         mapOfPropertiesHost["name"] = propertiesDefinition3
84         mapOfPropertiesHost["ipAddress"] = propertiesDefinition4
85
86         val myDataTypeIpaddress = DataType().apply {
87             id = "ip-address"
88             properties = mapOfPropertiesIpAddress
89         }
90
91         val myDataTypeHost = DataType().apply {
92             id = "host"
93             properties = mapOfPropertiesHost
94         }
95
96         every { resourceAssignmentRuntimeService.bluePrintContext().dataTypeByName("ip-address") } returns myDataTypeIpaddress
97
98         every { resourceAssignmentRuntimeService.bluePrintContext().dataTypeByName("host") } returns myDataTypeHost
99
100         every { resourceAssignmentRuntimeService.setNodeTemplateAttributeValue(any(), any(), any()) } returns Unit
101     }
102
103     @Test
104     fun `generateResourceDataForAssignments - positive test`() {
105         //given a valid resource assignment
106         val validResourceAssignment = createResourceAssignmentForTest("valid_value")
107
108         //and a list containing that resource assignment
109         val resourceAssignmentList = listOf<ResourceAssignment>(validResourceAssignment)
110
111         //when the values of the resources are evaluated
112         val outcome = ResourceAssignmentUtils.generateResourceDataForAssignments(resourceAssignmentList)
113
114         //then the assignment should produce a valid result
115         val expected = "{\n" + "  \"pnf-id\" : \"valid_value\"\n" + "}"
116         assertEquals(expected, outcome, "unexpected outcome generated")
117     }
118
119     @Test
120     fun `generateResourceDataForAssignments - resource without value is not resolved as null`() {
121         //given a valid resource assignment
122         val resourceAssignmentWithNullValue = createResourceAssignmentForTest(null)
123
124         //and a list containing that resource assignment
125         val resourceAssignmentList = listOf<ResourceAssignment>(resourceAssignmentWithNullValue)
126
127         //when the values of the resources are evaluated
128         val outcome = ResourceAssignmentUtils.generateResourceDataForAssignments(resourceAssignmentList)
129
130         //then the assignment should produce a valid result
131         val expected = "{\n" + "  \"pnf-id\" : \"\${pnf-id}\"\n" + "}"
132         assertEquals(expected, outcome, "unexpected outcome generated")
133
134     }
135
136     private fun createResourceAssignmentForTest(resourceValue: String?): ResourceAssignment {
137         val valueForTest = if (resourceValue == null) null else TextNode(resourceValue)
138         val resourceAssignmentForTest = ResourceAssignment().apply {
139             name = "pnf-id"
140             dictionaryName = "pnf-id"
141             dictionarySource = "input"
142             property = PropertyDefinition().apply {
143                 type = "string"
144                 value = valueForTest
145             }
146         }
147         return resourceAssignmentForTest
148     }
149
150     @Test
151     fun parseResponseNodeTestForPrimitivesTypes(){
152         // Input values for primitive type
153         val keyValue = mutableMapOf<String, String>()
154         keyValue["value"]= "1.2.3.1"
155         val expectedPrimitiveType = TextNode("1.2.3.1")
156
157         var outcome = prepareResponseNodeForTest("sample-value", "string",
158                 "", "1.2.3.1".asJsonPrimitive())
159         assertEquals(expectedPrimitiveType, outcome, "Unexpected outcome returned for primitive type of simple String")
160         outcome = prepareResponseNodeForTest("sample-key-value", "string", "", keyValue)
161         assertEquals(expectedPrimitiveType, outcome, "Unexpected outcome returned for primitive type of key-value String")
162     }
163
164     @Test
165     fun parseResponseNodeTestForCollectionsOfString(){
166         // Input values for collection type
167         val mapOfString = mutableMapOf<String, String>()
168         mapOfString["value1"] = "1.2.3.1"
169         mapOfString["port"] = "8888"
170         mapOfString["value2"] = "1.2.3.2"
171         val arrayOfKeyValue = arrayListOf(ExpectedResponseIp("1.2.3.1"),
172                 ExpectedResponsePort( "8888"), ExpectedResponseIp("1.2.3.2"))
173
174         val mutableMapKeyValue = mutableMapOf<String, String>()
175         mutableMapKeyValue["value1"] = "1.2.3.1"
176         mutableMapKeyValue["port"] = "8888"
177
178         //List
179         val expectedListOfString = arrayOfKeyValue.asJsonType()
180         var outcome = prepareResponseNodeForTest("listOfString", "list",
181                 "string", mapOfString.asJsonType())
182         assertEquals(expectedListOfString, outcome, "unexpected outcome returned for list of String")
183
184         //Map
185         val expectedMapOfString = mutableMapOf<String, JsonNode>()
186         expectedMapOfString["ip"] = "1.2.3.1".asJsonPrimitive()
187         expectedMapOfString["port"] = "8888".asJsonPrimitive()
188
189         val arrayNode = JacksonUtils.objectMapper.createArrayNode()
190         expectedMapOfString.map {
191             val arrayChildNode = JacksonUtils.objectMapper.createObjectNode()
192             arrayChildNode.set(it.key, it.value)
193             arrayNode.add(arrayChildNode)
194         }
195         val arrayChildNode1 = JacksonUtils.objectMapper.createObjectNode()
196         arrayChildNode1.set("ip", NullNode.getInstance())
197         arrayNode.add(arrayChildNode1)
198         outcome = prepareResponseNodeForTest("mapOfString", "map", "string",
199                 mutableMapKeyValue.asJsonType())
200         assertEquals(arrayNode, outcome, "unexpected outcome returned for map of String")
201     }
202
203     @Test
204     fun parseResponseNodeTestForCollectionsOfJsonNode(){
205         // Input values for collection type
206         val mapOfString = mutableMapOf<String, JsonNode>()
207         mapOfString["value1"] = "1.2.3.1".asJsonPrimitive()
208         mapOfString["port"] = "8888".asJsonPrimitive()
209         mapOfString["value2"] = "1.2.3.2".asJsonPrimitive()
210         val arrayOfKeyValue = arrayListOf(ExpectedResponseIp("1.2.3.1"),
211                 ExpectedResponsePort( "8888"), ExpectedResponseIp("1.2.3.2"))
212
213         val mutableMapKeyValue = mutableMapOf<String, JsonNode>()
214         mutableMapKeyValue["value1"] = "1.2.3.1".asJsonPrimitive()
215         mutableMapKeyValue["port"] = "8888".asJsonPrimitive()
216
217         //List
218         val expectedListOfString = arrayOfKeyValue.asJsonType()
219         var outcome = prepareResponseNodeForTest("listOfString", "list",
220                 "string", mapOfString.asJsonType())
221         assertEquals(expectedListOfString, outcome, "unexpected outcome returned for list of String")
222
223         //Map
224         val expectedMapOfString = mutableMapOf<String, JsonNode>()
225         expectedMapOfString["ip"] = "1.2.3.1".asJsonPrimitive()
226         expectedMapOfString["port"] = "8888".asJsonPrimitive()
227         val arrayNode = JacksonUtils.objectMapper.createArrayNode()
228         expectedMapOfString.map {
229             val arrayChildNode = JacksonUtils.objectMapper.createObjectNode()
230             arrayChildNode.set(it.key, it.value)
231             arrayNode.add(arrayChildNode)
232         }
233         val arrayChildNode1 = JacksonUtils.objectMapper.createObjectNode()
234         arrayChildNode1.set("ip", NullNode.getInstance())
235         arrayNode.add(arrayChildNode1)
236         outcome = prepareResponseNodeForTest("mapOfString", "map",
237                 "string", mutableMapKeyValue.asJsonType())
238         assertEquals(arrayNode, outcome, "unexpected outcome returned for map of String")
239     }
240
241     @Test
242     fun parseResponseNodeTestForCollectionsOfComplexType(){
243         // Input values for collection type
244         val mapOfComplexType = mutableMapOf<String, JsonNode>()
245         mapOfComplexType["value1"] = IpAddress("1111", "1.2.3.1").asJsonType()
246         mapOfComplexType["value2"] = IpAddress("2222", "1.2.3.2").asJsonType()
247         mapOfComplexType["value3"] = IpAddress("3333", "1.2.3.3").asJsonType()
248
249         //List
250         val arrayNode = JacksonUtils.objectMapper.createArrayNode()
251         mapOfComplexType.map {
252             val arrayChildNode = JacksonUtils.objectMapper.createObjectNode()
253             arrayChildNode.set("ipAddress", it.value)
254             arrayNode.add(arrayChildNode)
255         }
256         var outcome = prepareResponseNodeForTest("listOfMyDataType", "list",
257                 "ip-address", mapOfComplexType.asJsonType())
258         assertEquals(arrayNode, outcome, "unexpected outcome returned for list of String")
259     }
260
261     @Test
262     fun `parseResponseNodeTestForComplexType find one output key mapping`(){
263         // Input values for complex type
264         val objectNode = JacksonUtils.objectMapper.createObjectNode()
265
266         // Input values for collection type
267         val mapOfComplexType = mutableMapOf<String, JsonNode>()
268         mapOfComplexType["value"] = Host("my-ipAddress", IpAddress("1111", "1.2.3.1")).asJsonType()
269         mapOfComplexType["port"] = "8888".asJsonType()
270         mapOfComplexType["something"] = "1.2.3.2".asJsonType()
271
272         val expectedComplexType = objectNode.set("ipAddress", Host("my-ipAddress", IpAddress("1111", "1.2.3.1")).asJsonType())
273         val outcome = prepareResponseNodeForTest("complexTypeOneKeys", "host",
274                 "", mapOfComplexType.asJsonType())
275         assertEquals(expectedComplexType, outcome, "Unexpected outcome returned for complex type")
276     }
277
278     @Test
279     fun `parseResponseNodeTestForComplexType find all output key mapping`(){
280         // Input values for complex type
281         val objectNode = JacksonUtils.objectMapper.createObjectNode()
282
283         // Input values for collection type
284         val mapOfComplexType = mutableMapOf<String, JsonNode>()
285         mapOfComplexType["name"] = "my-ipAddress".asJsonType()
286         mapOfComplexType["ipAddress"] = IpAddress("1111", "1.2.3.1").asJsonType()
287
288         val expectedComplexType = Host("my-ipAddress", IpAddress("1111", "1.2.3.1")).asJsonType()
289         val outcome = prepareResponseNodeForTest("complexTypeAllKeys", "host",
290                 "", mapOfComplexType.asJsonType())
291         assertEquals(expectedComplexType, outcome, "Unexpected outcome returned for complex type")
292     }
293
294     private fun prepareResponseNodeForTest(dictionary_source: String, sourceType: String, entrySchema: String,
295                                            response: Any): JsonNode {
296
297         val resourceAssignment = when (sourceType) {
298             "list", "map" -> {
299                 prepareRADataDictionaryCollection(dictionary_source, sourceType, entrySchema)
300             }
301             "string" -> {
302                 prepareRADataDictionaryOfPrimaryType(dictionary_source)
303             }
304             else -> {
305                 prepareRADataDictionaryComplexType(dictionary_source, sourceType, entrySchema)
306             }
307         }
308
309         val responseNode = checkNotNull(JacksonUtils.getJsonNode(response)) {
310             "Failed to get database query result into Json node."
311         }
312
313         val outputKeyMapping = prepareOutputKeyMapping(dictionary_source)
314
315         return ResourceAssignmentUtils.parseResponseNode(responseNode, resourceAssignment, resourceAssignmentRuntimeService, outputKeyMapping)
316     }
317
318     private fun prepareRADataDictionaryOfPrimaryType(dictionary_source: String): ResourceAssignment {
319         return ResourceAssignment().apply {
320             name = "ipAddress"
321             dictionaryName = "sample-ip"
322             dictionarySource = "$dictionary_source"
323             property = PropertyDefinition().apply {
324                 type = "string"
325             }
326         }
327     }
328
329     private fun prepareRADataDictionaryCollection(dictionary_source: String, sourceType: String, schema: String): ResourceAssignment {
330         return ResourceAssignment().apply {
331             name = "ipAddress-list"
332             dictionaryName = "sample-licenses"
333             dictionarySource = "$dictionary_source"
334             property = PropertyDefinition().apply {
335                 type = "$sourceType"
336                 entrySchema = EntrySchema().apply {
337                     type = "$schema"
338                 }
339             }
340         }
341     }
342
343     private fun prepareRADataDictionaryComplexType(dictionary_source: String, sourceType: String, schema: String): ResourceAssignment {
344         return ResourceAssignment().apply {
345             name = "ipAddress-complexType"
346             dictionaryName = "sample-licenses"
347             dictionarySource = "$dictionary_source"
348             property = PropertyDefinition().apply {
349                 type = "$sourceType"
350             }
351         }
352     }
353
354     private fun prepareOutputKeyMapping(dictionary_source: String): MutableMap<String, String> {
355         val outputMapping = mutableMapOf<String, String>()
356
357         when (dictionary_source) {
358             "listOfString", "mapOfString" -> {
359                 //List of string
360                 outputMapping["value1"] = "ip"
361                 outputMapping["port"] = "port"
362                 outputMapping["value2"] = "ip"
363             }
364             "listOfMyDataType", "mapOfMyDataType" -> {
365                 //List or map of complex Type
366                 outputMapping["value1"] = "ipAddress"
367                 outputMapping["value2"] = "ipAddress"
368                 outputMapping["value3"] = "ipAddress"
369             }
370             "sample-key-value", "sample-value" -> {
371                 //Primary Type
372                 if (dictionary_source=="sample-key-value")
373                     outputMapping["sample-ip"] = "value"
374             }
375             else -> {
376                 //Complex Type
377                 if (dictionary_source == "complexTypeOneKeys")
378                     outputMapping["value"] = "ipAddress"
379                 else {
380                     outputMapping["name"] = "name"
381                     outputMapping["ipAddress"] = "ipAddress"
382                 }
383
384             }
385         }
386         return outputMapping
387     }
388 }