Revert "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.BluePrintError
45 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintTypes
46 import org.onap.ccsdk.cds.controllerblueprints.core.asJsonPrimitive
47 import org.onap.ccsdk.cds.controllerblueprints.core.asJsonType
48 import org.onap.ccsdk.cds.controllerblueprints.core.data.Implementation
49 import org.onap.ccsdk.cds.controllerblueprints.core.data.LockAssignment
50 import org.onap.ccsdk.cds.controllerblueprints.core.normalizedPathName
51 import org.onap.ccsdk.cds.controllerblueprints.core.scripts.BluePrintScriptsServiceImpl
52 import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintContext
53 import org.onap.ccsdk.cds.controllerblueprints.core.service.DefaultBluePrintRuntimeService
54 import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
55 import org.springframework.beans.factory.annotation.Autowired
56 import org.springframework.test.context.ContextConfiguration
57 import org.springframework.test.context.junit4.SpringRunner
58 import kotlin.test.BeforeTest
59 import kotlin.test.assertEquals
60 import kotlin.test.assertNotNull
61
62 /**
63  * Unit test cases for abstract component function.
64  */
65 @RunWith(SpringRunner::class)
66 @ContextConfiguration(
67     classes = [
68         ComponentFunctionScriptingService::class,
69         BluePrintScriptsServiceImpl::class, DeprecatedBlueprintJythonService::class
70     ]
71 )
72 class AbstractComponentFunctionTest {
73
74     lateinit var bluePrintRuntimeService: DefaultBluePrintRuntimeService
75     lateinit var blueprintContext: BluePrintContext
76     lateinit var blueprintClusterService: BluePrintClusterService
77
78     @Autowired
79     lateinit var compSvc: ComponentFunctionScriptingService
80
81     @BeforeTest
82     fun init() {
83         bluePrintRuntimeService = mockk()
84         blueprintContext = mockk()
85         blueprintClusterService = mockk()
86         every { bluePrintRuntimeService.bluePrintContext() } returns blueprintContext
87
88         every { blueprintContext.rootPath } returns normalizedPathName("target")
89         every {
90             blueprintContext.nodeTemplateOperationImplementation(
91                 any(), any(), any()
92             )
93         } returns Implementation()
94
95         every { bluePrintRuntimeService.getBluePrintError() } returns BluePrintError()
96     }
97
98     @Test
99     fun testAbstractComponent() {
100         runBlocking {
101             val samp = SampleComponent()
102             val comp = samp as AbstractComponentFunction
103
104             comp.bluePrintRuntimeService = bluePrintRuntimeService
105             comp.stepName = "sample-step"
106             assertNotNull(comp, "failed to get kotlin instance")
107
108             val input = getMockedInput(bluePrintRuntimeService)
109
110             val output = comp.applyNB(input)
111
112             assertEquals(output.actionIdentifiers.actionName, "activate")
113             assertEquals(output.commonHeader.requestId, "1234")
114             assertEquals(output.stepData!!.name, "activate-restconf")
115             assertEquals(output.status.message, "success")
116         }
117     }
118
119     @Test
120     fun testComponentFunctionPayload() {
121         val sampleComponent = SampleComponent()
122         sampleComponent.workflowName = "sample-action"
123         sampleComponent.executionServiceInput = JacksonUtils.readValueFromClassPathFile(
124             "payload/requests/sample-execution-request.json", ExecutionServiceInput::class.java
125         )!!
126         val payload = sampleComponent.requestPayload()
127         assertNotNull(payload, "failed to get payload")
128         val data = sampleComponent.requestPayloadActionProperty("data")?.first()
129         assertNotNull(data, "failed to get payload request action data")
130     }
131
132     @Test
133     fun testAbstractScriptComponent() {
134         runBlocking {
135             val samp = SampleRestconfComponent(compSvc)
136             val comp = samp as AbstractComponentFunction
137
138             comp.bluePrintRuntimeService = bluePrintRuntimeService
139             comp.stepName = "sample-step"
140             assertNotNull(comp, "failed to get kotlin instance")
141
142             val input = getMockedInput(bluePrintRuntimeService)
143
144             val output = comp.applyNB(input)
145
146             assertEquals(output.actionIdentifiers.actionName, "activate")
147             assertEquals(output.commonHeader.requestId, "1234")
148             assertEquals(output.stepData!!.name, "activate-restconf")
149             assertEquals(output.status.message, "success")
150         }
151     }
152
153     @Test
154     fun testComponentScriptExecutorNodeType() {
155         val componentScriptExecutor = BluePrintTypes.nodeTypeComponentScriptExecutor()
156         assertNotNull(componentScriptExecutor.interfaces, "failed to get interface operations")
157     }
158
159     @Test
160     fun `prepareRequestNB should resolve lock properties`() {
161         val implementation = Implementation().apply {
162             this.lock = LockAssignment().apply {
163                 this.key = """ {"get_input": "lock-key"} """.asJsonPrimitive()
164             }
165         }
166         every {
167             blueprintContext.nodeTemplateOperationImplementation(any(), any(), any())
168         } returns implementation
169
170         every {
171             bluePrintRuntimeService.resolvePropertyAssignments(any(), any(), any())
172         } returns mutableMapOf(
173             "key" to "abc-123-def-456".asJsonType(),
174             "acquireTimeout" to implementation.lock!!.acquireTimeout
175         )
176
177         val component: AbstractComponentFunction = SampleComponent()
178         component.bluePrintRuntimeService = bluePrintRuntimeService
179         component.bluePrintClusterService = blueprintClusterService
180
181         runBlocking {
182             component.prepareRequestNB(getMockedInput(bluePrintRuntimeService))
183         }
184
185         val resolvedLock = component.implementation.lock!!
186
187         assertEquals("abc-123-def-456", resolvedLock.key.textValue())
188         // default value
189         assertEquals(180, resolvedLock.acquireTimeout.intValue())
190     }
191
192     @Test(expected = Exception::class)
193     fun `prepareRequestNB should throw exception if it fails to resolve lock key`() {
194         every {
195             blueprintContext.nodeTemplateOperationImplementation(any(), any(), any())
196         } returns Implementation().apply { this.lock = LockAssignment() }
197
198         every {
199             bluePrintRuntimeService.resolvePropertyAssignments(any(), any(), any())
200         } returns mutableMapOf(
201             "key" to "".asJsonType(),
202             "acquireTimeout" to Integer(360).asJsonType()
203         )
204
205         val component: AbstractComponentFunction = SampleComponent()
206         component.bluePrintRuntimeService = bluePrintRuntimeService
207         component.bluePrintClusterService = blueprintClusterService
208
209         runBlocking {
210             component.prepareRequestNB(getMockedInput(bluePrintRuntimeService))
211         }
212     }
213
214     @Test
215     fun `applyNB should catch exceptions and call recoverNB`() {
216         val exception = RuntimeException("Intentional test exception")
217         every {
218             bluePrintRuntimeService.resolvePropertyAssignments(any(), any(), any())
219         } throws exception
220         every {
221             blueprintContext.nodeTemplateOperationImplementation(any(), any(), any())
222         } returns Implementation().apply {
223             this.lock = LockAssignment().apply { this.key = "testing-lock".asJsonType() }
224         }
225
226         val component: AbstractComponentFunction = spyk(SampleComponent())
227         component.bluePrintRuntimeService = bluePrintRuntimeService
228         component.bluePrintClusterService = blueprintClusterService
229         val input = getMockedInput(bluePrintRuntimeService)
230
231         runBlocking { component.applyNB(input) }
232         verify { runBlocking { component.recoverNB(exception, input) } }
233     }
234
235     @Test
236     fun `applyNB - when lock is present use ClusterLock`() {
237
238         val lockName = "testing-lock"
239
240         every {
241             blueprintContext.nodeTemplateOperationImplementation(any(), any(), any())
242         } returns Implementation().apply {
243             this.lock = LockAssignment().apply { this.key = lockName.asJsonType() }
244         }
245
246         every {
247             bluePrintRuntimeService.resolvePropertyAssignments(any(), any(), any())
248         } returns mutableMapOf(
249             "key" to lockName.asJsonType(),
250             "acquireTimeout" to Integer(180).asJsonType()
251         )
252
253         val clusterLock: ClusterLock = mockk()
254
255         every { clusterLock.name() } returns lockName
256         every { runBlocking { clusterLock.tryLock(any()) } } returns true
257         every { runBlocking { clusterLock.unLock() } } returns Unit
258
259         every {
260             runBlocking { blueprintClusterService.clusterLock(any()) }
261         } returns clusterLock
262
263         val component: AbstractComponentFunction = SampleComponent()
264         component.bluePrintRuntimeService = bluePrintRuntimeService
265         component.bluePrintClusterService = blueprintClusterService
266
267         runBlocking {
268             component.applyNB(getMockedInput(bluePrintRuntimeService))
269         }
270
271         verify {
272             runBlocking { blueprintClusterService.clusterLock("$lockName@$CDS_LOCK_GROUP") }
273         }
274         verify { runBlocking { clusterLock.unLock() } }
275     }
276
277     /**
278      * Mocked input for abstract function test.
279      */
280     private fun getMockedInput(bluePrintRuntime: DefaultBluePrintRuntimeService):
281         ExecutionServiceInput {
282
283             val mapper = ObjectMapper()
284             val rootNode = mapper.createObjectNode()
285             rootNode.put("ip-address", "0.0.0.0")
286             rootNode.put("type", "rest")
287
288             val operationInputs = hashMapOf<String, JsonNode>()
289             operationInputs[BluePrintConstants.PROPERTY_CURRENT_NODE_TEMPLATE] =
290                 "activate-restconf".asJsonPrimitive()
291             operationInputs[BluePrintConstants.PROPERTY_CURRENT_INTERFACE] =
292                 "interfaceName".asJsonPrimitive()
293             operationInputs[BluePrintConstants.PROPERTY_CURRENT_OPERATION] =
294                 "operationName".asJsonPrimitive()
295             operationInputs["dynamic-properties"] = rootNode
296
297             val stepInputData = StepData().apply {
298                 name = "activate-restconf"
299                 properties = operationInputs
300             }
301             val executionServiceInput = ExecutionServiceInput().apply {
302                 commonHeader = CommonHeader().apply {
303                     requestId = "1234"
304                 }
305                 actionIdentifiers = ActionIdentifiers().apply {
306                     actionName = "activate"
307                 }
308                 payload = JacksonUtils.jsonNode("{}") as ObjectNode
309             }
310             executionServiceInput.stepData = stepInputData
311
312             every {
313                 bluePrintRuntime.resolveNodeTemplateInterfaceOperationInputs(
314                     "activate-restconf", "interfaceName", "operationName"
315                 )
316             } returns operationInputs
317
318             val operationOutputs = hashMapOf<String, JsonNode>()
319             every {
320                 bluePrintRuntime.resolveNodeTemplateInterfaceOperationOutputs(
321                     "activate-restconf", "interfaceName", "operationName"
322                 )
323             } returns operationOutputs
324             every { bluePrintRuntime.bluePrintContext() } returns blueprintContext
325
326             return executionServiceInput
327         }
328 }