From 048aad79ece5b709e65155e2d0c8675b7c2c84a2 Mon Sep 17 00:00:00 2001 From: Brinda Santh Date: Wed, 14 Aug 2019 19:10:04 -0400 Subject: Add Imperative workflow execution service. Workflow implementation based on multiple steps in blueprint model. Change-Id: I21eaf5d08621ae6eac2fa0a5db2aca0291928d52 Issue-ID: CCSDK-1619 Signed-off-by: Brinda Santh --- .../workflow/ImperativeWorkflowExecutionService.kt | 143 +++++++++++++++++++++ .../workflow/NodeTemplateExecutionService.kt | 6 +- .../BluePrintWorkflowExecutionServiceImplTest.kt | 11 ++ .../services/workflow/BlueprintServiceLogicTest.kt | 7 + .../ImperativeWorkflowExecutionServiceTest.kt | 99 ++++++++++++++ .../workflow/NodeTemplateExecutionServiceTest.kt | 22 +++- .../workflow/mock/MockComponentFunction.kt | 12 ++ .../execution-input/imperative-test-input.json | 18 +++ .../core/GraphExtensionFunctions.kt | 7 + .../core/service/BluePrintWorkflowService.kt | 25 ++-- .../core/utils/BluePrintMetadataUtils.kt | 14 +- .../core/service/BluePrintRuntimeServiceTest.kt | 13 +- .../core/service/BluePrintWorkflowServiceTest.kt | 24 ++-- 13 files changed, 359 insertions(+), 42 deletions(-) create mode 100644 ms/blueprintsprocessor/modules/services/workflow-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/ImperativeWorkflowExecutionService.kt create mode 100644 ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/ImperativeWorkflowExecutionServiceTest.kt create mode 100644 ms/blueprintsprocessor/modules/services/workflow-service/src/test/resources/execution-input/imperative-test-input.json diff --git a/ms/blueprintsprocessor/modules/services/workflow-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/ImperativeWorkflowExecutionService.kt b/ms/blueprintsprocessor/modules/services/workflow-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/ImperativeWorkflowExecutionService.kt new file mode 100644 index 000000000..e7e5fe68a --- /dev/null +++ b/ms/blueprintsprocessor/modules/services/workflow-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/ImperativeWorkflowExecutionService.kt @@ -0,0 +1,143 @@ +/* + * Copyright © 2019 IBM. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onap.ccsdk.cds.blueprintsprocessor.services.workflow + +import kotlinx.coroutines.CompletableDeferred +import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput +import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceOutput +import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants +import org.onap.ccsdk.cds.controllerblueprints.core.asGraph +import org.onap.ccsdk.cds.controllerblueprints.core.data.EdgeLabel +import org.onap.ccsdk.cds.controllerblueprints.core.data.Graph +import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintWorkflowExecutionService +import org.onap.ccsdk.cds.controllerblueprints.core.logger +import org.onap.ccsdk.cds.controllerblueprints.core.service.* +import org.springframework.beans.factory.config.ConfigurableBeanFactory +import org.springframework.context.annotation.Scope +import org.springframework.stereotype.Service + +@Service("imperativeWorkflowExecutionService") +class ImperativeWorkflowExecutionService( + private val bluePrintWorkFlowService: BluePrintWorkFlowService) + : BluePrintWorkflowExecutionService { + + override suspend fun executeBluePrintWorkflow(bluePrintRuntimeService: BluePrintRuntimeService<*>, + executionServiceInput: ExecutionServiceInput, + properties: MutableMap): ExecutionServiceOutput { + + val bluePrintContext = bluePrintRuntimeService.bluePrintContext() + + val workflowName = executionServiceInput.actionIdentifiers.actionName + + val graph = bluePrintContext.workflowByName(workflowName).asGraph() + + val deferredOutput = CompletableDeferred() + bluePrintWorkFlowService.executeWorkflow(graph, bluePrintRuntimeService, executionServiceInput, deferredOutput) + return deferredOutput.await() + } +} + +@Service +@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) +open class ImperativeBluePrintWorkflowService(private val nodeTemplateExecutionService: NodeTemplateExecutionService) + : AbstractBluePrintWorkFlowService() { + val log = logger(ImperativeBluePrintWorkflowService::class) + + lateinit var bluePrintRuntimeService: BluePrintRuntimeService<*> + lateinit var executionServiceInput: ExecutionServiceInput + lateinit var deferredExecutionServiceOutput: CompletableDeferred + + override suspend fun executeWorkflow(graph: Graph, bluePrintRuntimeService: BluePrintRuntimeService<*>, + input: ExecutionServiceInput, + output: CompletableDeferred) { + this.graph = graph + this.bluePrintRuntimeService = bluePrintRuntimeService + this.executionServiceInput = input + this.deferredExecutionServiceOutput = output + this.workflowId = bluePrintRuntimeService.id() + val startMessage = WorkflowExecuteMessage(input, output) + workflowActor.send(startMessage) + } + + override suspend fun initializeWorkflow(input: ExecutionServiceInput): EdgeLabel { + return EdgeLabel.SUCCESS + } + + override suspend fun prepareWorkflowOutput(): ExecutionServiceOutput { + return ExecutionServiceOutput().apply { + commonHeader = executionServiceInput.commonHeader + actionIdentifiers = executionServiceInput.actionIdentifiers + } + } + + override suspend fun prepareNodeExecutionMessage(node: Graph.Node) + : NodeExecuteMessage { + val deferredOutput = CompletableDeferred() + return NodeExecuteMessage(node, executionServiceInput, deferredOutput) + } + + override suspend fun prepareNodeSkipMessage(node: Graph.Node) + : NodeSkipMessage { + val deferredOutput = CompletableDeferred() + return NodeSkipMessage(node, executionServiceInput, deferredOutput) + } + + override suspend fun executeNode(node: Graph.Node, nodeInput: ExecutionServiceInput, + deferredNodeOutput: CompletableDeferred, + deferredNodeStatus: CompletableDeferred) { + try { + val nodeTemplateName = node.id + /** execute node template */ + val executionServiceOutput = nodeTemplateExecutionService + .executeNodeTemplate(bluePrintRuntimeService, nodeTemplateName, nodeInput) + val edgeStatus = when (executionServiceOutput.status.message) { + BluePrintConstants.STATUS_FAILURE -> EdgeLabel.FAILURE + else -> EdgeLabel.SUCCESS + } + /** set deferred output and status */ + deferredNodeOutput.complete(executionServiceOutput) + deferredNodeStatus.complete(edgeStatus) + } catch (e: Exception) { + log.error("failed in executeNode($node)", e) + deferredNodeOutput.completeExceptionally(e) + deferredNodeStatus.complete(EdgeLabel.FAILURE) + } + } + + override suspend fun skipNode(node: Graph.Node, nodeInput: ExecutionServiceInput, + deferredNodeOutput: CompletableDeferred, + deferredNodeStatus: CompletableDeferred) { + val executionServiceOutput = ExecutionServiceOutput().apply { + commonHeader = nodeInput.commonHeader + actionIdentifiers = nodeInput.actionIdentifiers + } + deferredNodeOutput.complete(executionServiceOutput) + deferredNodeStatus.complete(EdgeLabel.SUCCESS) + } + + override suspend fun cancelNode(node: Graph.Node, nodeInput: ExecutionServiceInput, + deferredNodeOutput: CompletableDeferred, + deferredNodeStatus: CompletableDeferred) { + TODO("not implemented") + } + + override suspend fun restartNode(node: Graph.Node, nodeInput: ExecutionServiceInput, + deferredNodeOutput: CompletableDeferred, + deferredNodeStatus: CompletableDeferred) { + TODO("not implemented") + } +} \ No newline at end of file diff --git a/ms/blueprintsprocessor/modules/services/workflow-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/NodeTemplateExecutionService.kt b/ms/blueprintsprocessor/modules/services/workflow-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/NodeTemplateExecutionService.kt index af7846340..89732e300 100644 --- a/ms/blueprintsprocessor/modules/services/workflow-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/NodeTemplateExecutionService.kt +++ b/ms/blueprintsprocessor/modules/services/workflow-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/NodeTemplateExecutionService.kt @@ -23,13 +23,13 @@ import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.StepData import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.AbstractComponentFunction import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants import org.onap.ccsdk.cds.controllerblueprints.core.putJsonElement +import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintDependencyService import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintRuntimeService import org.slf4j.LoggerFactory -import org.springframework.context.ApplicationContext import org.springframework.stereotype.Service @Service -open class NodeTemplateExecutionService(private val applicationContext: ApplicationContext) { +open class NodeTemplateExecutionService { private val log = LoggerFactory.getLogger(NodeTemplateExecutionService::class.java)!! @@ -48,7 +48,7 @@ open class NodeTemplateExecutionService(private val applicationContext: Applicat "interface($interfaceName) operation($operationName)") // Get the Component Instance - val plugin = applicationContext.getBean(componentName, AbstractComponentFunction::class.java) + val plugin = BluePrintDependencyService.instance(componentName) // Set the Blueprint Service plugin.bluePrintRuntimeService = bluePrintRuntimeService plugin.stepName = nodeTemplateName diff --git a/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/BluePrintWorkflowExecutionServiceImplTest.kt b/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/BluePrintWorkflowExecutionServiceImplTest.kt index c15c054db..3c740725e 100644 --- a/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/BluePrintWorkflowExecutionServiceImplTest.kt +++ b/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/BluePrintWorkflowExecutionServiceImplTest.kt @@ -17,6 +17,7 @@ package org.onap.ccsdk.cds.blueprintsprocessor.services.workflow import kotlinx.coroutines.runBlocking +import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput @@ -24,9 +25,11 @@ import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceOutp import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintWorkflowExecutionService +import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintDependencyService import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintMetadataUtils import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils import org.springframework.beans.factory.annotation.Autowired +import org.springframework.context.ApplicationContext import org.springframework.test.context.ContextConfiguration import org.springframework.test.context.junit4.SpringRunner import kotlin.test.assertEquals @@ -38,9 +41,17 @@ import kotlin.test.assertNotNull @ContextConfiguration(classes = [WorkflowServiceConfiguration::class]) class BluePrintWorkflowExecutionServiceImplTest { + @Autowired + lateinit var applicationContext: ApplicationContext + @Autowired lateinit var bluePrintWorkflowExecutionService: BluePrintWorkflowExecutionService + @Before + fun init() { + BluePrintDependencyService.inject(applicationContext) + } + @Test fun testBluePrintWorkflowExecutionService() { runBlocking { diff --git a/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/BlueprintServiceLogicTest.kt b/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/BlueprintServiceLogicTest.kt index 4352277b7..12fd9c7c4 100644 --- a/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/BlueprintServiceLogicTest.kt +++ b/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/BlueprintServiceLogicTest.kt @@ -18,6 +18,7 @@ package org.onap.ccsdk.cds.blueprintsprocessor.services.workflow import kotlinx.coroutines.runBlocking +import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput @@ -25,6 +26,7 @@ import org.onap.ccsdk.cds.blueprintsprocessor.services.workflow.executor.Compone import org.onap.ccsdk.cds.blueprintsprocessor.services.workflow.mock.PrototypeComponentFunction import org.onap.ccsdk.cds.blueprintsprocessor.services.workflow.mock.SingletonComponentFunction import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants +import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintDependencyService import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintMetadataUtils import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonReactorUtils import org.springframework.beans.factory.annotation.Autowired @@ -44,6 +46,11 @@ class BlueprintServiceLogicTest { @Autowired lateinit var dgWorkflowExecutionService: DGWorkflowExecutionService + @Before + fun init() { + BluePrintDependencyService.inject(applicationContext) + } + @Test fun testExecuteGraphWithSingleComponent() { runBlocking { diff --git a/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/ImperativeWorkflowExecutionServiceTest.kt b/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/ImperativeWorkflowExecutionServiceTest.kt new file mode 100644 index 000000000..301fc34c0 --- /dev/null +++ b/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/ImperativeWorkflowExecutionServiceTest.kt @@ -0,0 +1,99 @@ +/* + * Copyright © 2019 IBM. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onap.ccsdk.cds.blueprintsprocessor.services.workflow + +import io.mockk.every +import io.mockk.mockkObject +import io.mockk.unmockkAll +import kotlinx.coroutines.runBlocking +import org.junit.After +import org.junit.Before +import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput +import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.nodeTypeComponentScriptExecutor +import org.onap.ccsdk.cds.blueprintsprocessor.services.workflow.mock.MockComponentFunction +import org.onap.ccsdk.cds.blueprintsprocessor.services.workflow.mock.mockNodeTemplateComponentScriptExecutor +import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintTypes +import org.onap.ccsdk.cds.controllerblueprints.core.dsl.serviceTemplate +import org.onap.ccsdk.cds.controllerblueprints.core.normalizedPathName +import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintContext +import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintDependencyService +import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintMetadataUtils +import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils +import kotlin.test.Test +import kotlin.test.assertNotNull + +class ImperativeWorkflowExecutionServiceTest { + + @Before + fun init() { + mockkObject(BluePrintDependencyService) + every { BluePrintDependencyService.applicationContext.getBean(any()) } returns MockComponentFunction() + } + + @After + fun afterTests() { + unmockkAll() + } + + @Test + fun testImperativeExecutionService() { + runBlocking { + val serviceTemplate = serviceTemplate("imperative-test", "1.0.0", + "brindasanth@onap.com", "tosca") { + + topologyTemplate { + nodeTemplate(mockNodeTemplateComponentScriptExecutor("resolve-config", + "cba.wt.imperative.test.ResolveConfig")) + nodeTemplate(mockNodeTemplateComponentScriptExecutor("activate-config", + "cba.wt.imperative.test.ActivateConfig")) + nodeTemplate(mockNodeTemplateComponentScriptExecutor("activate-config-rollback", + "cba.wt.imperative.test.ActivateConfigRollback")) + nodeTemplate(mockNodeTemplateComponentScriptExecutor("activate-licence", + "cba.wt.imperative.test.ActivateLicence")) + + workflow("test-wf", "Test Imperative flow") { + step("resolve-config", "resolve-config", "") { + success("activate-config") + } + step("activate-config", "activate-config", "") { + success("activate-licence") + failure("activate-config-rollback") + } + step("activate-config-rollback", "activate-config-rollback", "") + step("activate-licence", "activate-licence", "") + } + } + nodeType(BluePrintTypes.nodeTypeComponentScriptExecutor()) + } + + val bluePrintContext = BluePrintContext(serviceTemplate) + bluePrintContext.rootPath = normalizedPathName(".") + bluePrintContext.entryDefinition = "cba.imperative.test.ImperativeTestDefinitions.kt" + val bluePrintRuntimeService = BluePrintMetadataUtils.getBluePrintRuntime("12345", bluePrintContext) + + val executionServiceInput = JacksonUtils + .readValueFromClassPathFile("execution-input/imperative-test-input.json", + ExecutionServiceInput::class.java)!! + + val bluePrintWorkFlowService = ImperativeBluePrintWorkflowService(NodeTemplateExecutionService()) + val imperativeWorkflowExecutionService = ImperativeWorkflowExecutionService(bluePrintWorkFlowService) + val output = imperativeWorkflowExecutionService + .executeBluePrintWorkflow(bluePrintRuntimeService, executionServiceInput, hashMapOf()) + assertNotNull(output) + } + } +} \ No newline at end of file diff --git a/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/NodeTemplateExecutionServiceTest.kt b/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/NodeTemplateExecutionServiceTest.kt index 05cd99785..24d96629e 100644 --- a/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/NodeTemplateExecutionServiceTest.kt +++ b/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/NodeTemplateExecutionServiceTest.kt @@ -15,14 +15,20 @@ */ package org.onap.ccsdk.cds.blueprintsprocessor.services.workflow +import io.mockk.every +import io.mockk.mockkObject +import io.mockk.unmockkAll import kotlinx.coroutines.runBlocking +import org.junit.After +import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput +import org.onap.ccsdk.cds.blueprintsprocessor.services.workflow.mock.MockComponentFunction import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants +import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintDependencyService import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintMetadataUtils import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils -import org.springframework.beans.factory.annotation.Autowired import org.springframework.test.context.ContextConfiguration import org.springframework.test.context.junit4.SpringRunner import kotlin.test.assertEquals @@ -32,8 +38,16 @@ import kotlin.test.assertNotNull @ContextConfiguration(classes = [WorkflowServiceConfiguration::class]) class NodeTemplateExecutionServiceTest { - @Autowired - lateinit var nodeTemplateExecutionService: NodeTemplateExecutionService + @Before + fun init() { + mockkObject(BluePrintDependencyService) + every { BluePrintDependencyService.applicationContext.getBean(any()) } returns MockComponentFunction() + } + + @After + fun afterTests() { + unmockkAll() + } @Test fun testExecuteNodeTemplate() { @@ -49,7 +63,7 @@ class NodeTemplateExecutionServiceTest { bluePrintRuntimeService.assignWorkflowInputs("resource-assignment", input) val nodeTemplate = "resource-assignment" - + val nodeTemplateExecutionService = NodeTemplateExecutionService() val executionServiceOutput = nodeTemplateExecutionService .executeNodeTemplate(bluePrintRuntimeService, nodeTemplate, executionServiceInput) diff --git a/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/mock/MockComponentFunction.kt b/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/mock/MockComponentFunction.kt index 5dc5b9dba..44751b5b5 100644 --- a/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/mock/MockComponentFunction.kt +++ b/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/mock/MockComponentFunction.kt @@ -19,6 +19,8 @@ package org.onap.ccsdk.cds.blueprintsprocessor.services.workflow.mock import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.AbstractComponentFunction +import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.nodeTemplateComponentScriptExecutor +import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintTypes import org.onap.ccsdk.cds.controllerblueprints.core.asJsonPrimitive import org.slf4j.LoggerFactory import org.springframework.beans.factory.config.ConfigurableBeanFactory @@ -27,6 +29,16 @@ import org.springframework.context.annotation.Configuration import org.springframework.context.annotation.Scope import org.springframework.stereotype.Component +fun mockNodeTemplateComponentScriptExecutor(id: String, script: String) = BluePrintTypes.nodeTemplateComponentScriptExecutor(id, + "mock($id) component function") { + definedOperation("") { + inputs { + type("kotlin") + scriptClassReference(script) + } + } +} + @Configuration open class MockComponentConfiguration { diff --git a/ms/blueprintsprocessor/modules/services/workflow-service/src/test/resources/execution-input/imperative-test-input.json b/ms/blueprintsprocessor/modules/services/workflow-service/src/test/resources/execution-input/imperative-test-input.json new file mode 100644 index 000000000..188e84083 --- /dev/null +++ b/ms/blueprintsprocessor/modules/services/workflow-service/src/test/resources/execution-input/imperative-test-input.json @@ -0,0 +1,18 @@ +{ + "commonHeader": { + "originatorId": "System", + "requestId": "1234", + "subRequestId": "1234-12234" + }, + "actionIdentifiers": { + "blueprintName": "imperative-test", + "blueprintVersion": "1.0.0", + "actionName": "test-wf", + "mode": "sync" + }, + "payload": { + "test-wf-request": { + "hostname": "localhost" + } + } +} \ No newline at end of file diff --git a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/GraphExtensionFunctions.kt b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/GraphExtensionFunctions.kt index 235c48b66..793bdc455 100644 --- a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/GraphExtensionFunctions.kt +++ b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/GraphExtensionFunctions.kt @@ -18,10 +18,17 @@ package org.onap.ccsdk.cds.controllerblueprints.core import org.onap.ccsdk.cds.controllerblueprints.core.data.EdgeLabel import org.onap.ccsdk.cds.controllerblueprints.core.data.Graph +import org.onap.ccsdk.cds.controllerblueprints.core.data.Workflow +import org.onap.ccsdk.cds.controllerblueprints.core.utils.WorkflowGraphUtils import java.util.regex.Pattern private val graphTokenSeparators = Pattern.compile("[->/]") +/** Convert Blueprint workflow to graph data structure */ +fun Workflow.asGraph(): Graph { + return WorkflowGraphUtils.workFlowToGraph(this) +} + fun String.toGraph(): Graph { if (!startsWith('[') || !endsWith(']')) { throw IllegalArgumentException("Expected string starting '[' and ending with ']' but it was '$") diff --git a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BluePrintWorkflowService.kt b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BluePrintWorkflowService.kt index 019f31805..91c2bcbbb 100644 --- a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BluePrintWorkflowService.kt +++ b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BluePrintWorkflowService.kt @@ -29,9 +29,9 @@ import kotlin.coroutines.CoroutineContext interface BluePrintWorkFlowService { - /** Executes imperative workflow for the bluePrintRuntimeService [bluePrintRuntimeService] and workflow - * input [input], response will be retrieve from output [output]*/ - suspend fun executeWorkflow(bluePrintRuntimeService: BluePrintRuntimeService<*>, + /** Executes imperative workflow graph [graph] for the bluePrintRuntimeService [bluePrintRuntimeService] + * and workflow input [input], response will be retrieve from output [output]*/ + suspend fun executeWorkflow(graph: Graph, bluePrintRuntimeService: BluePrintRuntimeService<*>, input: In, output: CompletableDeferred) suspend fun initializeWorkflow(input: In): EdgeLabel @@ -89,8 +89,9 @@ enum class EdgeAction(val id: String) { } /** Abstract workflow service implementation */ -abstract class AbstractBluePrintWorkFlowService(private val graph: Graph) - : CoroutineScope, BluePrintWorkFlowService { +abstract class AbstractBluePrintWorkFlowService : CoroutineScope, BluePrintWorkFlowService { + + lateinit var graph: Graph private val log = logger(AbstractBluePrintWorkFlowService::class) @@ -101,8 +102,6 @@ abstract class AbstractBluePrintWorkFlowService(private val graph: Grap final override val coroutineContext: CoroutineContext get() = job + CoroutineName("Wf") - val root = graph.startNodes() - fun cancel() { log.info("Received workflow($workflowId) cancel request") job.cancel() @@ -121,7 +120,7 @@ abstract class AbstractBluePrintWorkFlowService(private val graph: Grap // Prepare Workflow and Populate the Initial store initializeWorkflow(workflowExecuteMessage.input) - val startNode = root.first() + val startNode = graph.startNodes().first() // Prepare first node message and Send NodeExecuteMessage // Start node doesn't wait for any nodes, so we can pass Execute message directly val nodeExecuteMessage = prepareNodeExecutionMessage(startNode) @@ -325,16 +324,12 @@ abstract class AbstractBluePrintWorkFlowService(private val graph: Grap } } - - override suspend fun executeWorkflow(bluePrintRuntimeService: BluePrintRuntimeService<*>, input: In, output: CompletableDeferred) { + override suspend fun executeWorkflow(graph: Graph, bluePrintRuntimeService: BluePrintRuntimeService<*>, + input: In, output: CompletableDeferred) { log.info("Executing Graph : $graph") + this.graph = graph this.workflowId = bluePrintRuntimeService.id() - validateWorkflow() val startMessage = WorkflowExecuteMessage(input, output) workflowActor.send(startMessage) } - - open fun validateWorkflow() { - //check(!graph.findCycles().isNotEmpty()) { "Graph is cyclic, Cycle is not supported" } - } } \ No newline at end of file diff --git a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/utils/BluePrintMetadataUtils.kt b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/utils/BluePrintMetadataUtils.kt index 669ab3fef..55424ada8 100644 --- a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/utils/BluePrintMetadataUtils.kt +++ b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/utils/BluePrintMetadataUtils.kt @@ -61,7 +61,7 @@ class BluePrintMetadataUtils { // Verify if the environment directory exists if (envDir.exists() && envDir.isDirectory) { //Find all available environment files - envDir.listFiles() + envDir.listFiles()!! .filter { it.name.endsWith(".properties") } .forEach { val istream = it.inputStream() @@ -96,14 +96,20 @@ class BluePrintMetadataUtils { return toscaMetaData } - fun getBluePrintRuntime(id: String, blueprintBasePath: String): BluePrintRuntimeService> { - + fun getBluePrintRuntime(id: String, blueprintBasePath: String) + : BluePrintRuntimeService> { val bluePrintContext: BluePrintContext = getBluePrintContext(blueprintBasePath) + return getBluePrintRuntime(id, bluePrintContext) + } + fun getBluePrintRuntime(id: String, bluePrintContext: BluePrintContext) + : BluePrintRuntimeService> { + checkNotEmpty(bluePrintContext.rootPath) { "blueprint context root path is missing." } + checkNotEmpty(bluePrintContext.entryDefinition) { "blueprint context entry definition is missing." } + val blueprintBasePath = bluePrintContext.rootPath val bluePrintRuntimeService = DefaultBluePrintRuntimeService(id, bluePrintContext) bluePrintRuntimeService.put(BluePrintConstants.PROPERTY_BLUEPRINT_BASE_PATH, blueprintBasePath.asJsonPrimitive()) bluePrintRuntimeService.put(BluePrintConstants.PROPERTY_BLUEPRINT_PROCESS_ID, id.asJsonPrimitive()) - return bluePrintRuntimeService } diff --git a/ms/controllerblueprints/modules/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BluePrintRuntimeServiceTest.kt b/ms/controllerblueprints/modules/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BluePrintRuntimeServiceTest.kt index 4c207fbe1..9103af3fa 100644 --- a/ms/controllerblueprints/modules/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BluePrintRuntimeServiceTest.kt +++ b/ms/controllerblueprints/modules/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BluePrintRuntimeServiceTest.kt @@ -17,16 +17,17 @@ package org.onap.ccsdk.cds.controllerblueprints.core.service -import org.slf4j.LoggerFactory import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.node.NullNode import org.junit.Test import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants import org.onap.ccsdk.cds.controllerblueprints.core.asJsonPrimitive import org.onap.ccsdk.cds.controllerblueprints.core.data.PropertyDefinition +import org.onap.ccsdk.cds.controllerblueprints.core.normalizedPathName import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintMetadataUtils import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintRuntimeUtils import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils +import org.slf4j.LoggerFactory import kotlin.test.assertEquals import kotlin.test.assertNotNull @@ -36,7 +37,7 @@ import kotlin.test.assertNotNull * @author Brinda Santh */ class BluePrintRuntimeServiceTest { - private val log= LoggerFactory.getLogger(this::class.toString()) + private val log = LoggerFactory.getLogger(this::class.toString()) @Test fun `test Resolve NodeTemplate Properties`() { @@ -167,11 +168,15 @@ class BluePrintRuntimeServiceTest { } private fun getBluePrintRuntimeService(): BluePrintRuntimeService> { - val blueprintBasePath: String = ("./../../../../components/model-catalog/blueprint-model/test-blueprint/baseconfiguration") + val blueprintBasePath = normalizedPathName("./../../../../components/model-catalog/blueprint-model/test-blueprint/baseconfiguration") val blueprintRuntime = BluePrintMetadataUtils.getBluePrintRuntime("1234", blueprintBasePath) + val checkProcessId = blueprintRuntime.get(BluePrintConstants.PROPERTY_BLUEPRINT_PROCESS_ID) val checkBasePath = blueprintRuntime.get(BluePrintConstants.PROPERTY_BLUEPRINT_BASE_PATH) - assertEquals(blueprintBasePath.asJsonPrimitive(), checkBasePath, "Failed to get base path after runtime creation") + assertEquals("1234".asJsonPrimitive(), + checkProcessId, "Failed to get process id after runtime creation") + assertEquals(blueprintBasePath.asJsonPrimitive(), + checkBasePath, "Failed to get base path after runtime creation") return blueprintRuntime } diff --git a/ms/controllerblueprints/modules/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BluePrintWorkflowServiceTest.kt b/ms/controllerblueprints/modules/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BluePrintWorkflowServiceTest.kt index 7cb64922c..62cb10851 100644 --- a/ms/controllerblueprints/modules/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BluePrintWorkflowServiceTest.kt +++ b/ms/controllerblueprints/modules/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BluePrintWorkflowServiceTest.kt @@ -33,11 +33,11 @@ class BluePrintWorkflowServiceTest { runBlocking { val graph = "[START>A/SUCCESS, A>B/SUCCESS, B>C/SUCCESS, C>D/SUCCESS, D>E/SUCCESS, E>END/SUCCESS]" .toGraph() - val simpleWorkflow = TestBluePrintWorkFlowService(graph) + val simpleWorkflow = TestBluePrintWorkFlowService() simpleWorkflow.simulatedState = prepareSimulation(arrayListOf("A", "B", "C", "D", "E"), null) val deferredOutput = CompletableDeferred() val input = "123456" - simpleWorkflow.executeWorkflow(mockBluePrintRuntimeService(), input, deferredOutput) + simpleWorkflow.executeWorkflow(graph, mockBluePrintRuntimeService(), input, deferredOutput) val response = deferredOutput.await() assertNotNull(response, "failed to get response") } @@ -48,11 +48,11 @@ class BluePrintWorkflowServiceTest { runBlocking { val graph = "[START>A/SUCCESS, A>B/SUCCESS, A>C/FAILURE, B>D/SUCCESS, C>D/SUCCESS, D>END/SUCCESS]" .toGraph() - val simpleWorkflow = TestBluePrintWorkFlowService(graph) + val simpleWorkflow = TestBluePrintWorkFlowService() simpleWorkflow.simulatedState = prepareSimulation(arrayListOf("A", "B", "C", "D", "E"), null) val deferredOutput = CompletableDeferred() val input = "123456" - simpleWorkflow.executeWorkflow(mockBluePrintRuntimeService(), input, deferredOutput) + simpleWorkflow.executeWorkflow(graph, mockBluePrintRuntimeService(), input, deferredOutput) val response = deferredOutput.await() assertNotNull(response, "failed to get response") } @@ -64,12 +64,12 @@ class BluePrintWorkflowServiceTest { // Failure Flow val failurePatGraph = "[START>A/SUCCESS, A>B/SUCCESS, A>C/FAILURE, B>D/SUCCESS, C>D/SUCCESS, D>END/SUCCESS]" .toGraph() - val failurePathWorkflow = TestBluePrintWorkFlowService(failurePatGraph) + val failurePathWorkflow = TestBluePrintWorkFlowService() failurePathWorkflow.simulatedState = prepareSimulation(arrayListOf("B", "C", "D", "E"), arrayListOf("A")) val failurePathWorkflowDeferredOutput = CompletableDeferred() val failurePathWorkflowInput = "123456" - failurePathWorkflow.executeWorkflow(mockBluePrintRuntimeService(), failurePathWorkflowInput, failurePathWorkflowDeferredOutput) + failurePathWorkflow.executeWorkflow(failurePatGraph, mockBluePrintRuntimeService(), failurePathWorkflowInput, failurePathWorkflowDeferredOutput) val failurePathResponse = failurePathWorkflowDeferredOutput.await() assertNotNull(failurePathResponse, "failed to get response") } @@ -80,11 +80,11 @@ class BluePrintWorkflowServiceTest { runBlocking { val graph = "[START>A/SUCCESS, A>B/SUCCESS, A>C/FAILURE, C>D/SUCCESS, D>E/SUCCESS, B>E/SUCCESS, E>END/SUCCESS]" .toGraph() - val simpleWorkflow = TestBluePrintWorkFlowService(graph) + val simpleWorkflow = TestBluePrintWorkFlowService() simpleWorkflow.simulatedState = prepareSimulation(arrayListOf("A", "B", "C", "D", "E"), null) val deferredOutput = CompletableDeferred() val input = "123456" - simpleWorkflow.executeWorkflow(mockBluePrintRuntimeService(), input, deferredOutput) + simpleWorkflow.executeWorkflow(graph, mockBluePrintRuntimeService(), input, deferredOutput) val response = deferredOutput.await() assertNotNull(response, "failed to get response") } @@ -95,11 +95,11 @@ class BluePrintWorkflowServiceTest { runBlocking { val graph = "[START>A/SUCCESS, A>B/SUCCESS, A>C/SUCCESS, B>D/SUCCESS, C>D/SUCCESS, D>END/SUCCESS]" .toGraph() - val simpleWorkflow = TestBluePrintWorkFlowService(graph) + val simpleWorkflow = TestBluePrintWorkFlowService() simpleWorkflow.simulatedState = prepareSimulation(arrayListOf("A", "B", "C", "D"), null) val deferredOutput = CompletableDeferred() val input = "123456" - simpleWorkflow.executeWorkflow(mockBluePrintRuntimeService(), input, deferredOutput) + simpleWorkflow.executeWorkflow(graph, mockBluePrintRuntimeService(), input, deferredOutput) val response = deferredOutput.await() assertNotNull(response, "failed to get response") } @@ -123,8 +123,8 @@ class BluePrintWorkflowServiceTest { } } -class TestBluePrintWorkFlowService(graph: Graph) - : AbstractBluePrintWorkFlowService(graph) { +class TestBluePrintWorkFlowService + : AbstractBluePrintWorkFlowService() { lateinit var simulatedState: MutableMap -- cgit 1.2.3-korg