Renaming Files having BluePrint to have Blueprint
[ccsdk/cds.git] / ms / blueprintsprocessor / modules / services / execution-service / src / test / kotlin / org / onap / ccsdk / cds / blueprintsprocessor / services / execution / scripts / AbstractComponentFunctionTest.kt
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP - CDS
4  * ================================================================================
5  * Copyright (C) 2019 Huawei Technologies Co., Ltd. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.ccsdk.cds.blueprintsprocessor.services.execution.scripts
22
23 import com.fasterxml.jackson.databind.JsonNode
24 import com.fasterxml.jackson.databind.ObjectMapper
25 import com.fasterxml.jackson.databind.node.ObjectNode
26 import io.mockk.every
27 import io.mockk.mockk
28 import io.mockk.spyk
29 import io.mockk.verify
30 import kotlinx.coroutines.runBlocking
31 import org.junit.Test
32 import org.junit.runner.RunWith
33 import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ActionIdentifiers
34 import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.CommonHeader
35 import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput
36 import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.StepData
37 import org.onap.ccsdk.cds.blueprintsprocessor.core.service.BlueprintClusterService
38 import org.onap.ccsdk.cds.blueprintsprocessor.core.service.CDS_LOCK_GROUP
39 import org.onap.ccsdk.cds.blueprintsprocessor.core.service.ClusterLock
40 import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.AbstractComponentFunction
41 import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.ComponentFunctionScriptingService
42 import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.nodeTypeComponentScriptExecutor
43 import org.onap.ccsdk.cds.controllerblueprints.core.BlueprintConstants
44 import org.onap.ccsdk.cds.controllerblueprints.core.BlueprintTypes
45 import org.onap.ccsdk.cds.controllerblueprints.core.asJsonPrimitive
46 import org.onap.ccsdk.cds.controllerblueprints.core.asJsonType
47 import org.onap.ccsdk.cds.controllerblueprints.core.data.Implementation
48 import org.onap.ccsdk.cds.controllerblueprints.core.data.LockAssignment
49 import org.onap.ccsdk.cds.controllerblueprints.core.normalizedPathName
50 import org.onap.ccsdk.cds.controllerblueprints.core.scripts.BlueprintScriptsServiceImpl
51 import org.onap.ccsdk.cds.controllerblueprints.core.service.BlueprintContext
52 import org.onap.ccsdk.cds.controllerblueprints.core.service.DefaultBlueprintRuntimeService
53 import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
54 import org.springframework.beans.factory.annotation.Autowired
55 import org.springframework.test.context.ContextConfiguration
56 import org.springframework.test.context.junit4.SpringRunner
57 import kotlin.test.BeforeTest
58 import kotlin.test.assertEquals
59 import kotlin.test.assertNotNull
60
61 /**
62  * Unit test cases for abstract component function.
63  */
64 @RunWith(SpringRunner::class)
65 @ContextConfiguration(
66     classes = [
67         ComponentFunctionScriptingService::class,
68         BlueprintScriptsServiceImpl::class, DeprecatedBlueprintJythonService::class
69     ]
70 )
71 class AbstractComponentFunctionTest {
72
73     lateinit var bluePrintRuntimeService: DefaultBlueprintRuntimeService
74     lateinit var blueprintContext: BlueprintContext
75     lateinit var blueprintClusterService: BlueprintClusterService
76
77     @Autowired
78     lateinit var compSvc: ComponentFunctionScriptingService
79
80     @BeforeTest
81     fun init() {
82         bluePrintRuntimeService = mockk()
83         blueprintContext = mockk()
84         blueprintClusterService = mockk()
85         every { bluePrintRuntimeService.bluePrintContext() } returns blueprintContext
86
87         every { blueprintContext.rootPath } returns normalizedPathName("target")
88         every {
89             blueprintContext.nodeTemplateOperationImplementation(
90                 any(), any(), any()
91             )
92         } returns Implementation()
93     }
94
95     @Test
96     fun testAbstractComponent() {
97         runBlocking {
98             val samp = SampleComponent()
99             val comp = samp as AbstractComponentFunction
100
101             comp.bluePrintRuntimeService = bluePrintRuntimeService
102             comp.stepName = "sample-step"
103             assertNotNull(comp, "failed to get kotlin instance")
104
105             val input = getMockedInput(bluePrintRuntimeService)
106
107             val output = comp.applyNB(input)
108
109             assertEquals(output.actionIdentifiers.actionName, "activate")
110             assertEquals(output.commonHeader.requestId, "1234")
111             assertEquals(output.stepData!!.name, "activate-restconf")
112             assertEquals(output.status.message, "success")
113         }
114     }
115
116     @Test
117     fun testComponentFunctionPayload() {
118         val sampleComponent = SampleComponent()
119         sampleComponent.workflowName = "sample-action"
120         sampleComponent.executionServiceInput = JacksonUtils.readValueFromClassPathFile(
121             "payload/requests/sample-execution-request.json", ExecutionServiceInput::class.java
122         )!!
123         val payload = sampleComponent.requestPayload()
124         assertNotNull(payload, "failed to get payload")
125         val data = sampleComponent.requestPayloadActionProperty("data")?.first()
126         assertNotNull(data, "failed to get payload request action data")
127     }
128
129     @Test
130     fun testAbstractScriptComponent() {
131         runBlocking {
132             val samp = SampleRestconfComponent(compSvc)
133             val comp = samp as AbstractComponentFunction
134
135             comp.bluePrintRuntimeService = bluePrintRuntimeService
136             comp.stepName = "sample-step"
137             assertNotNull(comp, "failed to get kotlin instance")
138
139             val input = getMockedInput(bluePrintRuntimeService)
140
141             val output = comp.applyNB(input)
142
143             assertEquals(output.actionIdentifiers.actionName, "activate")
144             assertEquals(output.commonHeader.requestId, "1234")
145             assertEquals(output.stepData!!.name, "activate-restconf")
146             assertEquals(output.status.message, "success")
147         }
148     }
149
150     @Test
151     fun testComponentScriptExecutorNodeType() {
152         val componentScriptExecutor = BlueprintTypes.nodeTypeComponentScriptExecutor()
153         assertNotNull(componentScriptExecutor.interfaces, "failed to get interface operations")
154     }
155
156     @Test
157     fun `prepareRequestNB should resolve lock properties`() {
158         val implementation = Implementation().apply {
159             this.lock = LockAssignment().apply {
160                 this.key = """ {"get_input": "lock-key"} """.asJsonPrimitive()
161             }
162         }
163         every {
164             blueprintContext.nodeTemplateOperationImplementation(any(), any(), any())
165         } returns implementation
166
167         every {
168             bluePrintRuntimeService.resolvePropertyAssignments(any(), any(), any())
169         } returns mutableMapOf(
170             "key" to "abc-123-def-456".asJsonType(),
171             "acquireTimeout" to implementation.lock!!.acquireTimeout
172         )
173
174         val component: AbstractComponentFunction = SampleComponent()
175         component.bluePrintRuntimeService = bluePrintRuntimeService
176         component.bluePrintClusterService = blueprintClusterService
177
178         runBlocking {
179             component.prepareRequestNB(getMockedInput(bluePrintRuntimeService))
180         }
181
182         val resolvedLock = component.implementation.lock!!
183
184         assertEquals("abc-123-def-456", resolvedLock.key.textValue())
185         // default value
186         assertEquals(180, resolvedLock.acquireTimeout.intValue())
187     }
188
189     @Test(expected = Exception::class)
190     fun `prepareRequestNB should throw exception if it fails to resolve lock key`() {
191         every {
192             blueprintContext.nodeTemplateOperationImplementation(any(), any(), any())
193         } returns Implementation().apply { this.lock = LockAssignment() }
194
195         every {
196             bluePrintRuntimeService.resolvePropertyAssignments(any(), any(), any())
197         } returns mutableMapOf(
198             "key" to "".asJsonType(),
199             "acquireTimeout" to Integer(360).asJsonType()
200         )
201
202         val component: AbstractComponentFunction = SampleComponent()
203         component.bluePrintRuntimeService = bluePrintRuntimeService
204         component.bluePrintClusterService = blueprintClusterService
205
206         runBlocking {
207             component.prepareRequestNB(getMockedInput(bluePrintRuntimeService))
208         }
209     }
210
211     @Test
212     fun `applyNB should catch exceptions and call recoverNB`() {
213         val exception = RuntimeException("Intentional test exception")
214         every {
215             bluePrintRuntimeService.resolvePropertyAssignments(any(), any(), any())
216         } throws exception
217         every {
218             blueprintContext.nodeTemplateOperationImplementation(any(), any(), any())
219         } returns Implementation().apply {
220             this.lock = LockAssignment().apply { this.key = "testing-lock".asJsonType() }
221         }
222
223         val component: AbstractComponentFunction = spyk(SampleComponent())
224         component.bluePrintRuntimeService = bluePrintRuntimeService
225         component.bluePrintClusterService = blueprintClusterService
226         val input = getMockedInput(bluePrintRuntimeService)
227
228         runBlocking { component.applyNB(input) }
229         verify { runBlocking { component.recoverNB(exception, input) } }
230     }
231
232     @Test
233     fun `applyNB - when lock is present use ClusterLock`() {
234
235         val lockName = "testing-lock"
236
237         every {
238             blueprintContext.nodeTemplateOperationImplementation(any(), any(), any())
239         } returns Implementation().apply {
240             this.lock = LockAssignment().apply { this.key = lockName.asJsonType() }
241         }
242
243         every {
244             bluePrintRuntimeService.resolvePropertyAssignments(any(), any(), any())
245         } returns mutableMapOf(
246             "key" to lockName.asJsonType(),
247             "acquireTimeout" to Integer(180).asJsonType()
248         )
249
250         val clusterLock: ClusterLock = mockk()
251
252         every { clusterLock.name() } returns lockName
253         every { runBlocking { clusterLock.tryLock(any()) } } returns true
254         every { runBlocking { clusterLock.unLock() } } returns Unit
255
256         every {
257             runBlocking { blueprintClusterService.clusterLock(any()) }
258         } returns clusterLock
259
260         val component: AbstractComponentFunction = SampleComponent()
261         component.bluePrintRuntimeService = bluePrintRuntimeService
262         component.bluePrintClusterService = blueprintClusterService
263
264         runBlocking {
265             component.applyNB(getMockedInput(bluePrintRuntimeService))
266         }
267
268         verify {
269             runBlocking { blueprintClusterService.clusterLock("$lockName@$CDS_LOCK_GROUP") }
270         }
271         verify { runBlocking { clusterLock.unLock() } }
272     }
273
274     /**
275      * Mocked input for abstract function test.
276      */
277     private fun getMockedInput(bluePrintRuntime: DefaultBlueprintRuntimeService):
278         ExecutionServiceInput {
279
280             val mapper = ObjectMapper()
281             val rootNode = mapper.createObjectNode()
282             rootNode.put("ip-address", "0.0.0.0")
283             rootNode.put("type", "rest")
284
285             val operationInputs = hashMapOf<String, JsonNode>()
286             operationInputs[BlueprintConstants.PROPERTY_CURRENT_NODE_TEMPLATE] =
287                 "activate-restconf".asJsonPrimitive()
288             operationInputs[BlueprintConstants.PROPERTY_CURRENT_INTERFACE] =
289                 "interfaceName".asJsonPrimitive()
290             operationInputs[BlueprintConstants.PROPERTY_CURRENT_OPERATION] =
291                 "operationName".asJsonPrimitive()
292             operationInputs["dynamic-properties"] = rootNode
293
294             val stepInputData = StepData().apply {
295                 name = "activate-restconf"
296                 properties = operationInputs
297             }
298             val executionServiceInput = ExecutionServiceInput().apply {
299                 commonHeader = CommonHeader().apply {
300                     requestId = "1234"
301                 }
302                 actionIdentifiers = ActionIdentifiers().apply {
303                     actionName = "activate"
304                 }
305                 payload = JacksonUtils.jsonNode("{}") as ObjectNode
306             }
307             executionServiceInput.stepData = stepInputData
308
309             every {
310                 bluePrintRuntime.resolveNodeTemplateInterfaceOperationInputs(
311                     "activate-restconf", "interfaceName", "operationName"
312                 )
313             } returns operationInputs
314
315             val operationOutputs = hashMapOf<String, JsonNode>()
316             every {
317                 bluePrintRuntime.resolveNodeTemplateInterfaceOperationOutputs(
318                     "activate-restconf", "interfaceName", "operationName"
319                 )
320             } returns operationOutputs
321             every { bluePrintRuntime.bluePrintContext() } returns blueprintContext
322
323             return executionServiceInput
324         }
325 }