2 * Copyright © 2019 IBM.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package org.onap.ccsdk.cds.controllerblueprints.core.service
21 import kotlinx.coroutines.CompletableDeferred
22 import kotlinx.coroutines.async
23 import kotlinx.coroutines.awaitAll
24 import kotlinx.coroutines.coroutineScope
25 import kotlinx.coroutines.runBlocking
26 import kotlinx.coroutines.withTimeout
28 import org.onap.ccsdk.cds.controllerblueprints.core.BlueprintException
29 import org.onap.ccsdk.cds.controllerblueprints.core.BlueprintProcessorException
30 import org.onap.ccsdk.cds.controllerblueprints.core.data.EdgeLabel
31 import org.onap.ccsdk.cds.controllerblueprints.core.data.Graph
32 import org.onap.ccsdk.cds.controllerblueprints.core.logger
33 import org.onap.ccsdk.cds.controllerblueprints.core.toGraph
34 import kotlin.test.assertNotNull
36 class BlueprintWorkflowServiceTest {
39 fun testSimpleFlow() {
41 val graph = "[START>A/SUCCESS, A>B/SUCCESS, B>C/SUCCESS, C>D/SUCCESS, D>E/SUCCESS, E>END/SUCCESS]"
43 val simpleWorkflow = TestBlueprintWorkFlowService()
44 simpleWorkflow.simulatedState = prepareSimulation(arrayListOf("A", "B", "C", "D", "E"), null)
46 val response = simpleWorkflow.executeWorkflow(graph, mockBlueprintRuntimeService(), input)
47 assertNotNull(response, "failed to get response")
52 fun testMultipleFlows() {
55 val wfs = listOf("12345", "12346").map {
57 val graph = "[START>A/SUCCESS, A>B/SUCCESS, B>C/SUCCESS, C>D/SUCCESS, D>END/SUCCESS]"
59 val simpleWorkflow = TestBlueprintWorkFlowService()
60 simpleWorkflow.simulatedState = prepareSimulation(arrayListOf("A", "B", "C", "D"), null)
61 val response = simpleWorkflow.executeWorkflow(graph, mockBlueprintRuntimeService(it), it)
62 assertNotNull(response, "failed to get response")
71 fun testMissingEdgeForBFailureState() {
73 val graph = "[START>A/SUCCESS, A>B/SUCCESS, B>C/SUCCESS, C>D/SUCCESS, D>END/SUCCESS]"
75 val simpleWorkflow = TestBlueprintWorkFlowService()
76 simpleWorkflow.simulatedState = prepareSimulation(arrayListOf("A", "C", "D", "E"), arrayListOf("B"))
78 val response = simpleWorkflow.executeWorkflow(graph, mockBlueprintRuntimeService(), input)
79 assertNotNull(response, "failed to get response")
84 fun testBExceptionFlow() {
86 val graph = "[START>A/SUCCESS, A>B/SUCCESS, B>C/SUCCESS, C>D/SUCCESS, D>END/SUCCESS]"
88 val simpleWorkflow = TestBlueprintWorkFlowService()
89 simpleWorkflow.simulatedState = prepareSimulation(arrayListOf("A", "C", "D", "E"), null)
91 val response = simpleWorkflow.executeWorkflow(graph, mockBlueprintRuntimeService(), input)
92 assertNotNull(response, "failed to get response")
97 fun testTimeoutExceptionFlow() {
99 val graph = "[START>A/SUCCESS, A>TO/SUCCESS, TO>C/SUCCESS, C>D/SUCCESS, D>END/SUCCESS]"
101 val simpleWorkflow = TestBlueprintWorkFlowService()
102 simpleWorkflow.simulatedState = prepareSimulation(arrayListOf("A", "TO", "C", "D", "E"), null)
104 val response = simpleWorkflow.executeWorkflow(graph, mockBlueprintRuntimeService(), input)
105 assertNotNull(response, "failed to get response")
110 fun testConditionalFlow() {
112 val graph = "[START>A/SUCCESS, A>B/SUCCESS, A>C/FAILURE, B>D/SUCCESS, C>D/SUCCESS, D>END/SUCCESS]"
114 val simpleWorkflow = TestBlueprintWorkFlowService()
115 simpleWorkflow.simulatedState = prepareSimulation(arrayListOf("A", "B", "C", "D", "E"), null)
117 val response = simpleWorkflow.executeWorkflow(graph, mockBlueprintRuntimeService(), input)
118 assertNotNull(response, "failed to get response")
123 fun testBothConditionalFlow() {
126 val failurePatGraph = "[START>A/SUCCESS, A>B/SUCCESS, A>C/FAILURE, B>D/SUCCESS, C>D/SUCCESS, D>END/SUCCESS]"
128 val failurePathWorkflow = TestBlueprintWorkFlowService()
129 failurePathWorkflow.simulatedState = prepareSimulation(
130 arrayListOf("B", "C", "D", "E"),
133 val failurePathWorkflowInput = "123456"
134 val failurePathResponse = failurePathWorkflow.executeWorkflow(failurePatGraph, mockBlueprintRuntimeService(), failurePathWorkflowInput)
135 assertNotNull(failurePathResponse, "failed to get response")
140 fun testMultipleSkipFlow() {
142 val graph = "[START>A/SUCCESS, A>B/SUCCESS, A>C/FAILURE, C>D/SUCCESS, D>E/SUCCESS, B>E/SUCCESS, E>END/SUCCESS]"
144 val simpleWorkflow = TestBlueprintWorkFlowService()
145 simpleWorkflow.simulatedState = prepareSimulation(arrayListOf("A", "B", "C", "D", "E"), null)
147 val response = simpleWorkflow.executeWorkflow(graph, mockBlueprintRuntimeService(), input)
148 assertNotNull(response, "failed to get response")
153 fun testParallelFlow() {
155 val graph = "[START>A/SUCCESS, A>B/SUCCESS, A>C/SUCCESS, B>D/SUCCESS, C>D/SUCCESS, D>END/SUCCESS]"
157 val simpleWorkflow = TestBlueprintWorkFlowService()
158 simpleWorkflow.simulatedState = prepareSimulation(arrayListOf("A", "B", "C", "D"), null)
160 val response = simpleWorkflow.executeWorkflow(graph, mockBlueprintRuntimeService(), input)
161 assertNotNull(response, "failed to get response")
165 private fun mockBlueprintRuntimeService(): BlueprintRuntimeService<*> {
166 return mockBlueprintRuntimeService("123456")
169 private fun mockBlueprintRuntimeService(id: String): BlueprintRuntimeService<*> {
170 val bluePrintRuntimeService = mockk<BlueprintRuntimeService<*>>()
171 every { bluePrintRuntimeService.id() } returns id
172 return bluePrintRuntimeService
175 private fun prepareSimulation(successes: List<String>?, failures: List<String>?): MutableMap<String, EdgeLabel> {
176 val simulatedState: MutableMap<String, EdgeLabel> = hashMapOf()
178 simulatedState[it] = EdgeLabel.SUCCESS
181 simulatedState[it] = EdgeLabel.FAILURE
183 return simulatedState
187 class TestBlueprintWorkFlowService :
188 AbstractBlueprintWorkFlowService<String, String>() {
190 val log = logger(TestBlueprintWorkFlowService::class)
192 lateinit var simulatedState: MutableMap<String, EdgeLabel>
194 override suspend fun initializeWorkflow(input: String): EdgeLabel {
195 return EdgeLabel.SUCCESS
198 override suspend fun executeWorkflow(graph: Graph, bluePrintRuntimeService: BlueprintRuntimeService<*>, input: String): String {
199 log.info("Executing Graph : $graph")
201 this.workflowId = bluePrintRuntimeService.id()
202 val output = CompletableDeferred<String>()
203 val startMessage = WorkflowExecuteMessage(input, output)
204 val workflowActor = workflowActor()
205 if (!workflowActor.isClosedForSend) {
206 workflowActor().send(startMessage)
208 throw BlueprintProcessorException("workflow actor is closed for send $workflowActor")
210 return startMessage.output.await()
213 override suspend fun prepareNodeExecutionMessage(node: Graph.Node):
214 NodeExecuteMessage<String, String> {
215 return NodeExecuteMessage(node, "$node Input", "")
218 override suspend fun executeNode(
223 // val random = (1..10).random() * 100
224 // log.info("workflow($workflowId) node(${node.id}) will reply in $random ms")
225 // kotlinx.coroutines.delay(random.toLong())
226 // //Simulation for timeout
227 if (node.id == "TO") {
229 kotlinx.coroutines.delay(2)
232 return simulatedState[node.id] ?: throw BlueprintException("failed to get status for the node($node)")
235 override suspend fun prepareNodeSkipMessage(node: Graph.Node): NodeSkipMessage<String, String> {
237 return NodeSkipMessage(node, "$node Skip Input", nodeOutput)
240 override suspend fun skipNode(
245 return simulatedState[node.id] ?: throw BlueprintException("failed to get status for the node($node)")
248 override suspend fun cancelNode(
253 TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
256 override suspend fun restartNode(
261 TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
264 override suspend fun prepareWorkflowOutput(): String {
265 if (exceptions.isNotEmpty()) {
267 log.error("workflow($workflowId) exceptions :", it)
270 return "Final Response"