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