/*- * ============LICENSE_START======================================================= * Copyright (C) 2019 Nordix Foundation. * Modifications Copyright (c) 2019 IBM, 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.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.utils import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.node.TextNode import io.mockk.every import io.mockk.spyk import org.junit.Before import org.junit.Test import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.ResourceAssignmentRuntimeService import org.onap.ccsdk.cds.controllerblueprints.core.asJsonPrimitive import org.onap.ccsdk.cds.controllerblueprints.core.asJsonType import org.onap.ccsdk.cds.controllerblueprints.core.data.DataType import org.onap.ccsdk.cds.controllerblueprints.core.data.EntrySchema import org.onap.ccsdk.cds.controllerblueprints.core.data.PropertyDefinition import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintMetadataUtils import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils import org.onap.ccsdk.cds.controllerblueprints.resource.dict.ResourceAssignment import kotlin.test.assertEquals data class IpAddress(val port: String, val ip: String) data class Host(val name: String, val ipAddress: IpAddress) data class ExpectedResponseIp(val ip: String) data class ExpectedResponseIpAddress(val ipAddress: IpAddress) class ResourceAssignmentUtilsTest { private lateinit var resourceAssignmentRuntimeService: ResourceAssignmentRuntimeService private lateinit var inputMapToTestPrimitiveTypeWithValue: JsonNode private lateinit var inputMapToTestPrimitiveTypeWithKeyValue: JsonNode private lateinit var inputMapToTestCollectionOfPrimitiveType: JsonNode private lateinit var inputMapToTestCollectionOfComplexTypeWithOneOutputKeyMapping: JsonNode private lateinit var inputMapToTestCollectionOfComplexTypeWithAllOutputKeyMapping: JsonNode private lateinit var inputMapToTestComplexTypeWithOneOutputKeyMapping: JsonNode private lateinit var inputMapToTestComplexTypeWithAllOutputKeyMapping: JsonNode private lateinit var expectedValueToTestPrimitiveType: JsonNode private lateinit var expectedValueToTesCollectionOfPrimitiveType: JsonNode private lateinit var expectedValueToTestCollectionOfComplexTypeWithOneOutputKeyMapping: JsonNode private lateinit var expectedValueToTestComplexTypeWithOneOutputKeyMapping: JsonNode private lateinit var expectedValueToTestComplexTypeWithAllOutputKeyMapping: JsonNode private lateinit var expectedValueToTestCollectionOfComplexTypeWithAllOutputKeyMapping: JsonNode @Before fun setup() { val bluePrintContext = BluePrintMetadataUtils.getBluePrintContext( "./../../../../components/model-catalog/blueprint-model/test-blueprint/baseconfiguration" ) resourceAssignmentRuntimeService = spyk(ResourceAssignmentRuntimeService("1234", bluePrintContext)) // Init input map and expected values for tests initInputMapAndExpectedValuesForPrimitiveType() initInputMapAndExpectedValuesForCollection() initInputMapAndExpectedValuesForComplexType() val propertiesDefinition1 = PropertyDefinition().apply { type = "string" id = "port" } val propertiesDefinition2 = PropertyDefinition().apply { type = "string" id = "ip" } val propertiesDefinition3 = PropertyDefinition().apply { type = "string" id = "name" } val propertiesDefinition4 = PropertyDefinition().apply { type = "ip-address" id = "ipAddress" } var mapOfPropertiesIpAddress = mutableMapOf() mapOfPropertiesIpAddress["port"] = propertiesDefinition1 mapOfPropertiesIpAddress["ip"] = propertiesDefinition2 var mapOfPropertiesHost = mutableMapOf() mapOfPropertiesHost["name"] = propertiesDefinition3 mapOfPropertiesHost["ipAddress"] = propertiesDefinition4 val myDataTypeIpaddress = DataType().apply { id = "ip-address" properties = mapOfPropertiesIpAddress } val myDataTypeHost = DataType().apply { id = "host" properties = mapOfPropertiesHost } every { resourceAssignmentRuntimeService.bluePrintContext().dataTypeByName("ip-address") } returns myDataTypeIpaddress every { resourceAssignmentRuntimeService.bluePrintContext().dataTypeByName("host") } returns myDataTypeHost every { resourceAssignmentRuntimeService.setNodeTemplateAttributeValue(any(), any(), any()) } returns Unit } @Test fun `generateResourceDataForAssignments - positive test`() { // given a valid resource assignment val validResourceAssignment = createResourceAssignmentForTest("valid_value") // and a list containing that resource assignment val resourceAssignmentList = listOf(validResourceAssignment) // when the values of the resources are evaluated val outcome = ResourceAssignmentUtils.generateResourceDataForAssignments(resourceAssignmentList) // then the assignment should produce a valid result val expected = "{\n" + " \"pnf-id\" : \"valid_value\"\n" + "}" assertEquals(expected, outcome.replace("\r\n", "\n"), "unexpected outcome generated") } @Test fun `generateResourceDataForAssignments - resource without value is not resolved as null`() { // given a valid resource assignment val resourceAssignmentWithNullValue = createResourceAssignmentForTest(null) // and a list containing that resource assignment val resourceAssignmentList = listOf(resourceAssignmentWithNullValue) // when the values of the resources are evaluated val outcome = ResourceAssignmentUtils.generateResourceDataForAssignments(resourceAssignmentList) // then the assignment should produce a valid result val expected = "{\n" + " \"pnf-id\" : \"\${pnf-id}\"\n" + "}" assertEquals(expected, outcome.replace("\r\n", "\n"), "unexpected outcome generated") } private fun createResourceAssignmentForTest(resourceValue: String?): ResourceAssignment { val valueForTest = if (resourceValue == null) null else TextNode(resourceValue) val resourceAssignmentForTest = ResourceAssignment().apply { name = "pnf-id" dictionaryName = "pnf-id" dictionarySource = "input" property = PropertyDefinition().apply { type = "string" value = valueForTest } } return resourceAssignmentForTest } @Test fun parseResponseNodeTestForPrimitivesTypes() { var outcome = prepareResponseNodeForTest( "sample-value", "string", "", inputMapToTestPrimitiveTypeWithValue ) assertEquals( expectedValueToTestPrimitiveType, outcome, "Unexpected outcome returned for primitive type of simple String" ) outcome = prepareResponseNodeForTest( "sample-key-value", "string", "", inputMapToTestPrimitiveTypeWithKeyValue ) assertEquals( expectedValueToTestPrimitiveType, outcome, "Unexpected outcome returned for primitive type of key-value String" ) } @Test fun parseResponseNodeTestForCollectionsOfString() { var outcome = prepareResponseNodeForTest( "listOfString", "list", "string", inputMapToTestCollectionOfPrimitiveType ) assertEquals( expectedValueToTesCollectionOfPrimitiveType, outcome, "unexpected outcome returned for list of String" ) outcome = prepareResponseNodeForTest( "mapOfString", "map", "string", inputMapToTestCollectionOfPrimitiveType ) assertEquals( expectedValueToTesCollectionOfPrimitiveType, outcome, "unexpected outcome returned for map of String" ) } @Test fun parseResponseNodeTestForCollectionsOfComplexType() { var outcome = prepareResponseNodeForTest( "listOfMyDataTypeWithOneOutputKeyMapping", "list", "ip-address", inputMapToTestCollectionOfComplexTypeWithOneOutputKeyMapping ) assertEquals( expectedValueToTestCollectionOfComplexTypeWithOneOutputKeyMapping, outcome, "unexpected outcome returned for list of String" ) outcome = prepareResponseNodeForTest( "listOfMyDataTypeWithAllOutputKeyMapping", "list", "ip-address", inputMapToTestCollectionOfComplexTypeWithAllOutputKeyMapping ) assertEquals( expectedValueToTestCollectionOfComplexTypeWithAllOutputKeyMapping, outcome, "unexpected outcome returned for list of String" ) } @Test fun `parseResponseNodeTestForComplexType find one output key mapping`() { val outcome = prepareResponseNodeForTest( "complexTypeOneKeys", "host", "", inputMapToTestComplexTypeWithOneOutputKeyMapping ) assertEquals( expectedValueToTestComplexTypeWithOneOutputKeyMapping, outcome, "Unexpected outcome returned for complex type" ) } @Test fun `parseResponseNodeTestForComplexType find all output key mapping`() { val outcome = prepareResponseNodeForTest( "complexTypeAllKeys", "host", "", inputMapToTestComplexTypeWithAllOutputKeyMapping ) assertEquals( expectedValueToTestComplexTypeWithAllOutputKeyMapping, outcome, "Unexpected outcome returned for complex type" ) } private fun initInputMapAndExpectedValuesForPrimitiveType() { inputMapToTestPrimitiveTypeWithValue = "1.2.3.1".asJsonType() val keyValue = mutableMapOf() keyValue["value"] = "1.2.3.1" inputMapToTestPrimitiveTypeWithKeyValue = keyValue.asJsonType() expectedValueToTestPrimitiveType = TextNode("1.2.3.1") } private fun initInputMapAndExpectedValuesForCollection() { val listOfIps = arrayListOf("1.2.3.1", "1.2.3.2", "1.2.3.3") val arrayNodeForList1 = JacksonUtils.objectMapper.createArrayNode() listOfIps.forEach { val arrayChildNode = JacksonUtils.objectMapper.createObjectNode() arrayChildNode.set("value", it.asJsonPrimitive()) arrayNodeForList1.add(arrayChildNode) } inputMapToTestCollectionOfPrimitiveType = arrayNodeForList1 expectedValueToTesCollectionOfPrimitiveType = arrayListOf( ExpectedResponseIp("1.2.3.1"), ExpectedResponseIp("1.2.3.2"), ExpectedResponseIp("1.2.3.3") ).asJsonType() val listOfIpAddresses = arrayListOf( IpAddress("1111", "1.2.3.1").asJsonType(), IpAddress("2222", "1.2.3.2").asJsonType(), IpAddress("3333", "1.2.3.3").asJsonType() ) val arrayNodeForList2 = JacksonUtils.objectMapper.createArrayNode() listOfIpAddresses.forEach { val arrayChildNode = JacksonUtils.objectMapper.createObjectNode() arrayChildNode.set("value", it.asJsonType()) arrayNodeForList2.add(arrayChildNode) } inputMapToTestCollectionOfComplexTypeWithOneOutputKeyMapping = arrayNodeForList2 val arrayNodeForList3 = JacksonUtils.objectMapper.createArrayNode() var childNode = JacksonUtils.objectMapper.createObjectNode() childNode.set("port", "1111".asJsonPrimitive()) childNode.set("ip", "1.2.3.1".asJsonPrimitive()) arrayNodeForList3.add(childNode) childNode = JacksonUtils.objectMapper.createObjectNode() childNode.set("port", "2222".asJsonPrimitive()) childNode.set("ip", "1.2.3.2".asJsonPrimitive()) arrayNodeForList3.add(childNode) childNode = JacksonUtils.objectMapper.createObjectNode() childNode.set("port", "3333".asJsonPrimitive()) childNode.set("ip", "1.2.3.3".asJsonPrimitive()) arrayNodeForList3.add(childNode) inputMapToTestCollectionOfComplexTypeWithAllOutputKeyMapping = arrayNodeForList3 expectedValueToTestCollectionOfComplexTypeWithOneOutputKeyMapping = arrayListOf( ExpectedResponseIpAddress(IpAddress("1111", "1.2.3.1")), ExpectedResponseIpAddress(IpAddress("2222", "1.2.3.2")), ExpectedResponseIpAddress( IpAddress("3333", "1.2.3.3") ) ).asJsonType() expectedValueToTestCollectionOfComplexTypeWithAllOutputKeyMapping = arrayListOf( IpAddress("1111", "1.2.3.1"), IpAddress("2222", "1.2.3.2"), IpAddress("3333", "1.2.3.3") ).asJsonType() } private fun initInputMapAndExpectedValuesForComplexType() { val mapOfComplexType = mutableMapOf() mapOfComplexType["value"] = Host("my-ipAddress", IpAddress("1111", "1.2.3.1")).asJsonType() mapOfComplexType["port"] = "8888".asJsonType() mapOfComplexType["something"] = "1.2.3.2".asJsonType() inputMapToTestComplexTypeWithOneOutputKeyMapping = mapOfComplexType.asJsonType() val objectNode = JacksonUtils.objectMapper.createObjectNode() expectedValueToTestComplexTypeWithOneOutputKeyMapping = objectNode.set("host", Host("my-ipAddress", IpAddress("1111", "1.2.3.1")).asJsonType()) val childNode1 = JacksonUtils.objectMapper.createObjectNode() childNode1.set("name", "my-ipAddress".asJsonPrimitive()) childNode1.set("ipAddress", IpAddress("1111", "1.2.3.1").asJsonType()) childNode1.set("port", "8888".asJsonType()) childNode1.set("something", IpAddress("2222", "1.2.3.1").asJsonType()) inputMapToTestComplexTypeWithAllOutputKeyMapping = childNode1 val childNode2 = JacksonUtils.objectMapper.createObjectNode() childNode2.set("name", "my-ipAddress".asJsonPrimitive()) childNode2.set("ipAddress", IpAddress("1111", "1.2.3.1").asJsonType()) expectedValueToTestComplexTypeWithAllOutputKeyMapping = childNode2 } private fun prepareResponseNodeForTest( dictionary_source: String, sourceType: String, entrySchema: String, response: Any ): JsonNode { val resourceAssignment = when (sourceType) { "list", "map" -> { prepareRADataDictionaryCollection(dictionary_source, sourceType, entrySchema) } "string" -> { prepareRADataDictionaryOfPrimaryType(dictionary_source) } else -> { prepareRADataDictionaryComplexType(dictionary_source, sourceType, entrySchema) } } val responseNode = checkNotNull(JacksonUtils.getJsonNode(response)) { "Failed to get database query result into Json node." } val outputKeyMapping = prepareOutputKeyMapping(dictionary_source) return ResourceAssignmentUtils.parseResponseNode( responseNode, resourceAssignment, resourceAssignmentRuntimeService, outputKeyMapping ) } private fun prepareRADataDictionaryOfPrimaryType(dictionary_source: String): ResourceAssignment { return ResourceAssignment().apply { name = "ipAddress" dictionaryName = "sample-ip" dictionarySource = "$dictionary_source" property = PropertyDefinition().apply { type = "string" } } } private fun prepareRADataDictionaryCollection( dictionary_source: String, sourceType: String, schema: String ): ResourceAssignment { return ResourceAssignment().apply { name = "ipAddress-list" dictionaryName = "sample-licenses" dictionarySource = "$dictionary_source" property = PropertyDefinition().apply { type = "$sourceType" entrySchema = EntrySchema().apply { type = "$schema" } } } } private fun prepareRADataDictionaryComplexType( dictionary_source: String, sourceType: String, schema: String ): ResourceAssignment { return ResourceAssignment().apply { name = "ipAddress-complexType" dictionaryName = "sample-licenses" dictionarySource = "$dictionary_source" property = PropertyDefinition().apply { type = "$sourceType" } } } private fun prepareOutputKeyMapping(dictionary_source: String): MutableMap { val outputMapping = mutableMapOf() when (dictionary_source) { "sample-key-value", "sample-value" -> { // Primary Type if (dictionary_source == "sample-key-value") outputMapping["sample-ip"] = "value" } "listOfString", "mapOfString" -> { // List of string outputMapping["ip"] = "value" } "listOfMyDataTypeWithOneOutputKeyMapping", "listOfMyDataTypeWithAllOutputKeyMapping" -> { // List or map of complex Type if (dictionary_source == "listOfMyDataTypeWithOneOutputKeyMapping") outputMapping["ipAddress"] = "value" else { outputMapping["port"] = "port" outputMapping["ip"] = "ip" } } else -> { // Complex Type if (dictionary_source == "complexTypeOneKeys") outputMapping["host"] = "value" else { outputMapping["name"] = "name" outputMapping["ipAddress"] = "ipAddress" } } } return outputMapping } }