Improve Remote Python Executor error handling and allow for structured response
[ccsdk/cds.git] / ms / blueprintsprocessor / functions / python-executor / src / test / kotlin / org / onap / ccsdk / cds / blueprintsprocessor / functions / python / executor / ComponentRemotePythonExecutorTest.kt
1 /*
2  *  Copyright © 2019 IBM.
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License");
5  *  you may not use this file except in compliance with the License.
6  *  You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License.
15  */
16
17 package org.onap.ccsdk.cds.blueprintsprocessor.functions.python.executor
18
19 import com.fasterxml.jackson.databind.JsonNode
20 import com.fasterxml.jackson.databind.ObjectMapper
21 import io.mockk.every
22 import io.mockk.mockk
23 import kotlinx.coroutines.runBlocking
24 import org.junit.Test
25 import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.*
26 import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.RemoteScriptExecutionService
27 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants
28 import org.onap.ccsdk.cds.controllerblueprints.core.asJsonPrimitive
29 import org.onap.ccsdk.cds.controllerblueprints.core.asJsonType
30 import org.onap.ccsdk.cds.controllerblueprints.core.putJsonElement
31 import org.onap.ccsdk.cds.controllerblueprints.core.service.DefaultBluePrintRuntimeService
32 import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintMetadataUtils
33 import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
34 import kotlin.test.assertEquals
35 import kotlin.test.assertNotNull
36
37
38 class ComponentRemotePythonExecutorTest {
39
40     @Test
41     fun testComponentRemotePythonExecutor() {
42         runBlocking {
43             val remoteScriptExecutionService = MockRemoteScriptExecutionService()
44
45             val componentRemotePythonExecutor = ComponentRemotePythonExecutor(remoteScriptExecutionService)
46
47             val executionServiceInput =
48                     JacksonUtils.readValueFromClassPathFile("payload/requests/sample-remote-python-request.json",
49                             ExecutionServiceInput::class.java)!!
50
51
52             val bluePrintRuntimeService = BluePrintMetadataUtils.getBluePrintRuntime("123456-1000",
53                     "./../../../../components/model-catalog/blueprint-model/test-blueprint/remote_scripts")
54
55             /** Load Workflow Inputs */
56             bluePrintRuntimeService.assignWorkflowInputs("execute-remote-python",
57                     executionServiceInput.payload.get("execute-remote-python-request"))
58
59             val stepMetaData: MutableMap<String, JsonNode> = hashMapOf()
60             stepMetaData.putJsonElement(BluePrintConstants.PROPERTY_CURRENT_NODE_TEMPLATE, "execute-remote-python")
61             stepMetaData.putJsonElement(BluePrintConstants.PROPERTY_CURRENT_INTERFACE, "ComponentRemotePythonExecutor")
62             stepMetaData.putJsonElement(BluePrintConstants.PROPERTY_CURRENT_OPERATION, "process")
63             componentRemotePythonExecutor.bluePrintRuntimeService = bluePrintRuntimeService
64             val stepInputData = StepData().apply {
65                 name = "execute-remote-python"
66                 properties = stepMetaData
67             }
68             executionServiceInput.stepData = stepInputData
69             componentRemotePythonExecutor.applyNB(executionServiceInput)
70         }
71     }
72
73     /**
74      * Test cases for python executor to work with the process NB of remote
75      * executor.
76      */
77     @Test
78     fun testComponentRemotePythonExecutorProcessNB() {
79         runBlocking {
80             val remoteScriptExecutionService = MockRemoteScriptExecutionService()
81             val componentRemotePythonExecutor = ComponentRemotePythonExecutor(remoteScriptExecutionService)
82             val bluePrintRuntime = mockk<DefaultBluePrintRuntimeService>("123456-1000")
83
84             every { bluePrintRuntime.setNodeTemplateAttributeValue(any(), any(), any()) } answers {}
85
86             val input = getMockedOutput(bluePrintRuntime)
87             componentRemotePythonExecutor.bluePrintRuntimeService = bluePrintRuntime
88             componentRemotePythonExecutor.applyNB(input)
89         }
90     }
91
92     /**
93      * Mocked input information for remote python executor.
94      */
95     fun getMockedOutput(svc: DefaultBluePrintRuntimeService):
96             ExecutionServiceInput {
97         val stepMetaData: MutableMap<String, JsonNode> = hashMapOf()
98
99         stepMetaData.putJsonElement(
100                 BluePrintConstants.PROPERTY_CURRENT_NODE_TEMPLATE,
101                 "execute-remote-python")
102         stepMetaData.putJsonElement(
103                 BluePrintConstants.PROPERTY_CURRENT_INTERFACE,
104                 "ComponentRemotePythonExecutor")
105         stepMetaData.putJsonElement(
106                 BluePrintConstants.PROPERTY_CURRENT_OPERATION, "process")
107
108         val mapper = ObjectMapper()
109         val rootNode = mapper.createObjectNode()
110         rootNode.put("ip-address", "0.0.0.0")
111         rootNode.put("type", "rest")
112
113         val operationalInputs: MutableMap<String, JsonNode> = hashMapOf()
114         operationalInputs.putJsonElement(
115                 BluePrintConstants.PROPERTY_CURRENT_NODE_TEMPLATE,
116                 "execute-remote-python")
117         operationalInputs.putJsonElement(
118                 BluePrintConstants.PROPERTY_CURRENT_INTERFACE,
119                 "ComponentRemotePythonExecutor")
120         operationalInputs.putJsonElement(
121                 BluePrintConstants.PROPERTY_CURRENT_OPERATION, "process")
122         operationalInputs.putJsonElement("endpoint-selector", "aai")
123         operationalInputs.putJsonElement("dynamic-properties", rootNode)
124         operationalInputs.putJsonElement("command", "./run.sh")
125         operationalInputs.putJsonElement("packages", "py")
126
127         every {
128             svc.resolveNodeTemplateInterfaceOperationInputs(
129                     "execute-remote-python",
130                     "ComponentRemotePythonExecutor", "process")
131         } returns operationalInputs
132
133         val stepInputData = StepData().apply {
134             name = "execute-remote-python"
135             properties = stepMetaData
136         }
137
138         val executionServiceInput = JacksonUtils
139                 .readValueFromClassPathFile(
140                         "payload/requests/sample-remote-python-request.json",
141                         ExecutionServiceInput::class.java)!!
142         executionServiceInput.stepData = stepInputData
143
144         val operationOutputs = hashMapOf<String, JsonNode>()
145         every {
146             svc.resolveNodeTemplateInterfaceOperationOutputs(
147                     "execute-remote-python",
148                     "ComponentRemotePythonExecutor", "process")
149         } returns operationOutputs
150         val bluePrintRuntimeService = BluePrintMetadataUtils
151                 .getBluePrintRuntime("123456-1000",
152                         "./../../../../components/model-" +
153                                 "catalog/blueprint-model/test-blueprint/" +
154                                 "remote_scripts")
155         every {
156             svc.resolveNodeTemplateArtifactDefinition(
157                     "execute-remote-python", "component-script")
158         } returns bluePrintRuntimeService.resolveNodeTemplateArtifactDefinition(
159                 "execute-remote-python", "component-script")
160         every {
161             svc.setNodeTemplateAttributeValue(
162                     "execute-remote-python", "prepare-environment-logs",
163                     "prepared successfully".asJsonPrimitive())
164         } returns Unit
165         every {
166             svc.setNodeTemplateAttributeValue(
167                     "execute-remote-python",
168                     "execute-command-logs", "N/A".asJsonPrimitive())
169         } returns Unit
170         every {
171             svc.setNodeTemplateAttributeValue(
172                     "execute-remote-python",
173                     "execute-command-logs",
174                     "processed successfully".asJsonPrimitive())
175         } returns Unit
176
177         every {
178             svc.resolveDSLExpression("aai")
179         } returns """{"url" : "http://xxx.com"}""".asJsonType()
180
181         every {
182             svc.bluePrintContext()
183         } returns bluePrintRuntimeService.bluePrintContext()
184         return executionServiceInput
185     }
186 }
187
188 class MockRemoteScriptExecutionService : RemoteScriptExecutionService {
189     override suspend fun init(selector: Any) {
190     }
191
192     override suspend fun prepareEnv(prepareEnvInput: PrepareRemoteEnvInput): RemoteScriptExecutionOutput {
193         assertEquals(prepareEnvInput.requestId, "123456-1000", "failed to match request id")
194         assertNotNull(prepareEnvInput.packages, "failed to get packages")
195
196         val remoteScriptExecutionOutput = mockk<RemoteScriptExecutionOutput>()
197         every { remoteScriptExecutionOutput.payload } returns "payload".asJsonPrimitive()
198         every { remoteScriptExecutionOutput.response } returns listOf("prepared successfully")
199         every { remoteScriptExecutionOutput.status } returns StatusType.SUCCESS
200         return remoteScriptExecutionOutput
201     }
202
203     override suspend fun executeCommand(remoteExecutionInput: RemoteScriptExecutionInput): RemoteScriptExecutionOutput {
204         assertEquals(remoteExecutionInput.requestId, "123456-1000", "failed to match request id")
205
206         val remoteScriptExecutionOutput = mockk<RemoteScriptExecutionOutput>()
207         every { remoteScriptExecutionOutput.payload } returns "payload".asJsonPrimitive()
208         every { remoteScriptExecutionOutput.response } returns listOf("processed successfully")
209         every { remoteScriptExecutionOutput.status } returns StatusType.SUCCESS
210         return remoteScriptExecutionOutput
211     }
212
213     override suspend fun close() {
214
215     }
216 }