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