Bug-fix - CDS Processor-DB & Default Dictionary not working
[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.TextNode
26 import io.mockk.every
27 import io.mockk.spyk
28 import org.junit.Before
29 import org.junit.Test
30 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.ResourceAssignmentRuntimeService
31 import org.onap.ccsdk.cds.controllerblueprints.core.asJsonPrimitive
32 import org.onap.ccsdk.cds.controllerblueprints.core.asJsonType
33 import org.onap.ccsdk.cds.controllerblueprints.core.data.DataType
34 import org.onap.ccsdk.cds.controllerblueprints.core.data.EntrySchema
35 import org.onap.ccsdk.cds.controllerblueprints.core.data.PropertyDefinition
36 import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintMetadataUtils
37 import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
38 import org.onap.ccsdk.cds.controllerblueprints.resource.dict.ResourceAssignment
39 import kotlin.test.assertEquals
40
41 data class IpAddress(val port: String, val ip: String)
42 data class Host(val name: String, val ipAddress: IpAddress)
43 data class ExpectedResponseIp(val ip: String)
44 data class ExpectedResponseIpAddress(val ipAddress: IpAddress)
45
46 class ResourceAssignmentUtilsTest {
47     private lateinit var resourceAssignmentRuntimeService: ResourceAssignmentRuntimeService
48
49     private lateinit var inputMapToTestPrimitiveTypeWithValue: JsonNode
50     private lateinit var inputMapToTestPrimitiveTypeWithKeyValue: JsonNode
51     private lateinit var inputMapToTestCollectionOfPrimitiveType: JsonNode
52     private lateinit var inputMapToTestCollectionOfComplexTypeWithOneOutputKeyMapping: JsonNode
53     private lateinit var inputMapToTestCollectionOfComplexTypeWithAllOutputKeyMapping: JsonNode
54     private lateinit var inputMapToTestComplexTypeWithOneOutputKeyMapping: JsonNode
55     private lateinit var inputMapToTestComplexTypeWithAllOutputKeyMapping: JsonNode
56     private lateinit var expectedValueToTestPrimitiveType: JsonNode
57     private lateinit var expectedValueToTesCollectionOfPrimitiveType: JsonNode
58     private lateinit var expectedValueToTestCollectionOfComplexTypeWithOneOutputKeyMapping: JsonNode
59     private lateinit var expectedValueToTestComplexTypeWithOneOutputKeyMapping: JsonNode
60     private lateinit var expectedValueToTestComplexTypeWithAllOutputKeyMapping: JsonNode
61     private lateinit var expectedValueToTestCollectionOfComplexTypeWithAllOutputKeyMapping: JsonNode
62
63     @Before
64     fun setup() {
65
66         val bluePrintContext = BluePrintMetadataUtils.getBluePrintContext(
67                 "./../../../../components/model-catalog/blueprint-model/test-blueprint/baseconfiguration")
68
69         resourceAssignmentRuntimeService = spyk(ResourceAssignmentRuntimeService("1234", bluePrintContext))
70
71         //Init input map and expected values for tests
72         initInputMapAndExpectedValuesForPrimitiveType()
73         initInputMapAndExpectedValuesForCollection()
74         initInputMapAndExpectedValuesForComplexType()
75
76         val propertiesDefinition1 = PropertyDefinition().apply {
77             type = "string"
78             id = "port"
79         }
80
81         val propertiesDefinition2 = PropertyDefinition().apply {
82             type = "string"
83             id = "ip"
84         }
85
86         val propertiesDefinition3 = PropertyDefinition().apply {
87             type = "string"
88             id = "name"
89         }
90
91         val propertiesDefinition4 = PropertyDefinition().apply {
92             type = "ip-address"
93             id = "ipAddress"
94         }
95
96         var mapOfPropertiesIpAddress = mutableMapOf<String, PropertyDefinition>()
97         mapOfPropertiesIpAddress["port"] = propertiesDefinition1
98         mapOfPropertiesIpAddress["ip"] = propertiesDefinition2
99
100         var mapOfPropertiesHost = mutableMapOf<String, PropertyDefinition>()
101         mapOfPropertiesHost["name"] = propertiesDefinition3
102         mapOfPropertiesHost["ipAddress"] = propertiesDefinition4
103
104         val myDataTypeIpaddress = DataType().apply {
105             id = "ip-address"
106             properties = mapOfPropertiesIpAddress
107         }
108
109         val myDataTypeHost = DataType().apply {
110             id = "host"
111             properties = mapOfPropertiesHost
112         }
113
114         every { resourceAssignmentRuntimeService.bluePrintContext().dataTypeByName("ip-address") } returns myDataTypeIpaddress
115
116         every { resourceAssignmentRuntimeService.bluePrintContext().dataTypeByName("host") } returns myDataTypeHost
117
118         every { resourceAssignmentRuntimeService.setNodeTemplateAttributeValue(any(), any(), any()) } returns Unit
119     }
120
121     @Test
122     fun `generateResourceDataForAssignments - positive test`() {
123         //given a valid resource assignment
124         val validResourceAssignment = createResourceAssignmentForTest("valid_value")
125
126         //and a list containing that resource assignment
127         val resourceAssignmentList = listOf<ResourceAssignment>(validResourceAssignment)
128
129         //when the values of the resources are evaluated
130         val outcome = ResourceAssignmentUtils.generateResourceDataForAssignments(resourceAssignmentList)
131
132         //then the assignment should produce a valid result
133         val expected = "{\n" + "  \"pnf-id\" : \"valid_value\"\n" + "}"
134         assertEquals(expected, outcome, "unexpected outcome generated")
135     }
136
137     @Test
138     fun `generateResourceDataForAssignments - resource without value is not resolved as null`() {
139         //given a valid resource assignment
140         val resourceAssignmentWithNullValue = createResourceAssignmentForTest(null)
141
142         //and a list containing that resource assignment
143         val resourceAssignmentList = listOf<ResourceAssignment>(resourceAssignmentWithNullValue)
144
145         //when the values of the resources are evaluated
146         val outcome = ResourceAssignmentUtils.generateResourceDataForAssignments(resourceAssignmentList)
147
148         //then the assignment should produce a valid result
149         val expected = "{\n" + "  \"pnf-id\" : \"\${pnf-id}\"\n" + "}"
150         assertEquals(expected, outcome, "unexpected outcome generated")
151
152     }
153
154     private fun createResourceAssignmentForTest(resourceValue: String?): ResourceAssignment {
155         val valueForTest = if (resourceValue == null) null else TextNode(resourceValue)
156         val resourceAssignmentForTest = ResourceAssignment().apply {
157             name = "pnf-id"
158             dictionaryName = "pnf-id"
159             dictionarySource = "input"
160             property = PropertyDefinition().apply {
161                 type = "string"
162                 value = valueForTest
163             }
164         }
165         return resourceAssignmentForTest
166     }
167
168     @Test
169     fun parseResponseNodeTestForPrimitivesTypes(){
170         var outcome = prepareResponseNodeForTest("sample-value", "string", "",
171                 inputMapToTestPrimitiveTypeWithValue)
172         assertEquals(expectedValueToTestPrimitiveType, outcome, "Unexpected outcome returned for primitive type of simple String")
173
174         outcome = prepareResponseNodeForTest("sample-key-value", "string", "",
175                 inputMapToTestPrimitiveTypeWithKeyValue)
176         assertEquals(expectedValueToTestPrimitiveType, outcome, "Unexpected outcome returned for primitive type of key-value String")
177     }
178
179     @Test
180     fun parseResponseNodeTestForCollectionsOfString(){
181         var outcome = prepareResponseNodeForTest("listOfString", "list",
182                 "string", inputMapToTestCollectionOfPrimitiveType)
183         assertEquals(expectedValueToTesCollectionOfPrimitiveType, outcome, "unexpected outcome returned for list of String")
184
185         outcome = prepareResponseNodeForTest("mapOfString", "map", "string",
186                 inputMapToTestCollectionOfPrimitiveType)
187         assertEquals(expectedValueToTesCollectionOfPrimitiveType, outcome, "unexpected outcome returned for map of String")
188     }
189
190     @Test
191     fun parseResponseNodeTestForCollectionsOfComplexType(){
192         var outcome = prepareResponseNodeForTest("listOfMyDataTypeWithOneOutputKeyMapping", "list",
193                 "ip-address", inputMapToTestCollectionOfComplexTypeWithOneOutputKeyMapping)
194         assertEquals(expectedValueToTestCollectionOfComplexTypeWithOneOutputKeyMapping, outcome, "unexpected outcome returned for list of String")
195
196         outcome = prepareResponseNodeForTest("listOfMyDataTypeWithAllOutputKeyMapping", "list",
197                 "ip-address", inputMapToTestCollectionOfComplexTypeWithAllOutputKeyMapping)
198         assertEquals(expectedValueToTestCollectionOfComplexTypeWithAllOutputKeyMapping, outcome, "unexpected outcome returned for list of String")
199     }
200
201     @Test
202     fun `parseResponseNodeTestForComplexType find one output key mapping`(){
203         val outcome = prepareResponseNodeForTest("complexTypeOneKeys", "host",
204                 "", inputMapToTestComplexTypeWithOneOutputKeyMapping)
205         assertEquals(expectedValueToTestComplexTypeWithOneOutputKeyMapping, outcome, "Unexpected outcome returned for complex type")
206     }
207
208     @Test
209     fun `parseResponseNodeTestForComplexType find all output key mapping`(){
210         val outcome = prepareResponseNodeForTest("complexTypeAllKeys", "host",
211                 "", inputMapToTestComplexTypeWithAllOutputKeyMapping)
212         assertEquals(expectedValueToTestComplexTypeWithAllOutputKeyMapping, outcome, "Unexpected outcome returned for complex type")
213     }
214
215     private fun initInputMapAndExpectedValuesForPrimitiveType() {
216         inputMapToTestPrimitiveTypeWithValue = "1.2.3.1".asJsonType()
217         val keyValue = mutableMapOf<String, String>()
218         keyValue["value"]= "1.2.3.1"
219         inputMapToTestPrimitiveTypeWithKeyValue = keyValue.asJsonType()
220         expectedValueToTestPrimitiveType = TextNode("1.2.3.1")
221     }
222
223     private fun initInputMapAndExpectedValuesForCollection(){
224         val listOfIps = arrayListOf("1.2.3.1", "1.2.3.2", "1.2.3.3")
225         val arrayNodeForList1 = JacksonUtils.objectMapper.createArrayNode()
226         listOfIps.forEach {
227             val arrayChildNode = JacksonUtils.objectMapper.createObjectNode()
228             arrayChildNode.set("value", it.asJsonPrimitive())
229             arrayNodeForList1.add(arrayChildNode)
230         }
231         inputMapToTestCollectionOfPrimitiveType = arrayNodeForList1
232
233         expectedValueToTesCollectionOfPrimitiveType = arrayListOf(ExpectedResponseIp("1.2.3.1"),
234                 ExpectedResponseIp( "1.2.3.2"), ExpectedResponseIp("1.2.3.3")).asJsonType()
235
236
237         val listOfIpAddresses = arrayListOf(IpAddress("1111", "1.2.3.1").asJsonType(),
238                 IpAddress("2222", "1.2.3.2").asJsonType(), IpAddress("3333", "1.2.3.3").asJsonType())
239         val arrayNodeForList2 = JacksonUtils.objectMapper.createArrayNode()
240         listOfIpAddresses.forEach {
241             val arrayChildNode = JacksonUtils.objectMapper.createObjectNode()
242             arrayChildNode.set("value", it.asJsonType())
243             arrayNodeForList2.add(arrayChildNode)
244         }
245         inputMapToTestCollectionOfComplexTypeWithOneOutputKeyMapping = arrayNodeForList2
246
247         val arrayNodeForList3 = JacksonUtils.objectMapper.createArrayNode()
248         var childNode = JacksonUtils.objectMapper.createObjectNode()
249         childNode.set("port", "1111".asJsonPrimitive())
250         childNode.set("ip", "1.2.3.1".asJsonPrimitive())
251         arrayNodeForList3.add(childNode)
252         childNode = JacksonUtils.objectMapper.createObjectNode()
253         childNode.set("port", "2222".asJsonPrimitive())
254         childNode.set("ip", "1.2.3.2".asJsonPrimitive())
255         arrayNodeForList3.add(childNode)
256         childNode = JacksonUtils.objectMapper.createObjectNode()
257         childNode.set("port", "3333".asJsonPrimitive())
258         childNode.set("ip", "1.2.3.3".asJsonPrimitive())
259         arrayNodeForList3.add(childNode)
260         inputMapToTestCollectionOfComplexTypeWithAllOutputKeyMapping = arrayNodeForList3
261
262         expectedValueToTestCollectionOfComplexTypeWithOneOutputKeyMapping = arrayListOf(ExpectedResponseIpAddress(IpAddress("1111", "1.2.3.1")),
263                 ExpectedResponseIpAddress(IpAddress("2222", "1.2.3.2")), ExpectedResponseIpAddress(
264                 IpAddress("3333", "1.2.3.3"))).asJsonType()
265         expectedValueToTestCollectionOfComplexTypeWithAllOutputKeyMapping = arrayListOf(IpAddress("1111", "1.2.3.1"),
266                 IpAddress("2222", "1.2.3.2"),
267                 IpAddress("3333", "1.2.3.3")).asJsonType()
268     }
269
270     private fun initInputMapAndExpectedValuesForComplexType(){
271         val mapOfComplexType = mutableMapOf<String, JsonNode>()
272         mapOfComplexType["value"] = Host("my-ipAddress", IpAddress("1111", "1.2.3.1")).asJsonType()
273         mapOfComplexType["port"] = "8888".asJsonType()
274         mapOfComplexType["something"] = "1.2.3.2".asJsonType()
275         inputMapToTestComplexTypeWithOneOutputKeyMapping = mapOfComplexType.asJsonType()
276
277         val objectNode = JacksonUtils.objectMapper.createObjectNode()
278         expectedValueToTestComplexTypeWithOneOutputKeyMapping = objectNode.set("host", Host("my-ipAddress", IpAddress("1111", "1.2.3.1")).asJsonType())
279
280         val childNode1 = JacksonUtils.objectMapper.createObjectNode()
281         childNode1.set("name", "my-ipAddress".asJsonPrimitive())
282         childNode1.set("ipAddress", IpAddress("1111", "1.2.3.1").asJsonType())
283         childNode1.set("port", "8888".asJsonType())
284         childNode1.set("something", IpAddress("2222", "1.2.3.1").asJsonType())
285         inputMapToTestComplexTypeWithAllOutputKeyMapping = childNode1
286
287         val childNode2 = JacksonUtils.objectMapper.createObjectNode()
288         childNode2.set("name", "my-ipAddress".asJsonPrimitive())
289         childNode2.set("ipAddress", IpAddress("1111", "1.2.3.1").asJsonType())
290         expectedValueToTestComplexTypeWithAllOutputKeyMapping = childNode2
291     }
292
293     private fun prepareResponseNodeForTest(dictionary_source: String, sourceType: String, entrySchema: String,
294                                            response: Any): JsonNode {
295
296         val resourceAssignment = when (sourceType) {
297             "list", "map" -> {
298                 prepareRADataDictionaryCollection(dictionary_source, sourceType, entrySchema)
299             }
300             "string" -> {
301                 prepareRADataDictionaryOfPrimaryType(dictionary_source)
302             }
303             else -> {
304                 prepareRADataDictionaryComplexType(dictionary_source, sourceType, entrySchema)
305             }
306         }
307
308         val responseNode = checkNotNull(JacksonUtils.getJsonNode(response)) {
309             "Failed to get database query result into Json node."
310         }
311
312         val outputKeyMapping = prepareOutputKeyMapping(dictionary_source)
313
314         return ResourceAssignmentUtils.parseResponseNode(responseNode, resourceAssignment, resourceAssignmentRuntimeService, outputKeyMapping)
315     }
316
317     private fun prepareRADataDictionaryOfPrimaryType(dictionary_source: String): ResourceAssignment {
318         return ResourceAssignment().apply {
319             name = "ipAddress"
320             dictionaryName = "sample-ip"
321             dictionarySource = "$dictionary_source"
322             property = PropertyDefinition().apply {
323                 type = "string"
324             }
325         }
326     }
327
328     private fun prepareRADataDictionaryCollection(dictionary_source: String, sourceType: String, schema: String): ResourceAssignment {
329         return ResourceAssignment().apply {
330             name = "ipAddress-list"
331             dictionaryName = "sample-licenses"
332             dictionarySource = "$dictionary_source"
333             property = PropertyDefinition().apply {
334                 type = "$sourceType"
335                 entrySchema = EntrySchema().apply {
336                     type = "$schema"
337                 }
338             }
339         }
340     }
341
342     private fun prepareRADataDictionaryComplexType(dictionary_source: String, sourceType: String, schema: String): ResourceAssignment {
343         return ResourceAssignment().apply {
344             name = "ipAddress-complexType"
345             dictionaryName = "sample-licenses"
346             dictionarySource = "$dictionary_source"
347             property = PropertyDefinition().apply {
348                 type = "$sourceType"
349             }
350         }
351     }
352
353     private fun prepareOutputKeyMapping(dictionary_source: String): MutableMap<String, String> {
354         val outputMapping = mutableMapOf<String, String>()
355
356         when (dictionary_source) {
357             "sample-key-value", "sample-value" -> {
358                 //Primary Type
359                 if (dictionary_source=="sample-key-value")
360                     outputMapping["sample-ip"] = "value"
361             }
362             "listOfString", "mapOfString" -> {
363                 //List of string
364                 outputMapping["ip"] = "value"
365             }
366             "listOfMyDataTypeWithOneOutputKeyMapping", "listOfMyDataTypeWithAllOutputKeyMapping" -> {
367                 //List or map of complex Type
368                 if (dictionary_source == "listOfMyDataTypeWithOneOutputKeyMapping")
369                     outputMapping["ipAddress"] = "value"
370                 else {
371                     outputMapping["port"] = "port"
372                     outputMapping["ip"] = "ip"
373                 }
374             }
375             else -> {
376                 //Complex Type
377                 if (dictionary_source == "complexTypeOneKeys")
378                     outputMapping["host"] = "value"
379                 else {
380                     outputMapping["name"] = "name"
381                     outputMapping["ipAddress"] = "ipAddress"
382                 }
383
384             }
385         }
386         return outputMapping
387     }
388 }