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