4d97f8bc35277ae9a41c342084f5d8c9758566a2
[ccsdk/cds.git] /
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.controllerblueprints.core.service
18
19 import io.mockk.every
20 import io.mockk.mockk
21 import kotlinx.coroutines.*
22 import org.junit.Test
23 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintException
24 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException
25 import org.onap.ccsdk.cds.controllerblueprints.core.data.EdgeLabel
26 import org.onap.ccsdk.cds.controllerblueprints.core.data.Graph
27 import org.onap.ccsdk.cds.controllerblueprints.core.logger
28 import org.onap.ccsdk.cds.controllerblueprints.core.toGraph
29 import kotlin.test.assertNotNull
30
31 class BluePrintWorkflowServiceTest {
32     @Test
33     fun testSimpleFlow() {
34         runBlocking {
35             val graph = "[START>A/SUCCESS, A>B/SUCCESS, B>C/SUCCESS, C>D/SUCCESS, D>E/SUCCESS, E>END/SUCCESS]"
36                     .toGraph()
37             val simpleWorkflow = TestBluePrintWorkFlowService()
38             simpleWorkflow.simulatedState = prepareSimulation(arrayListOf("A", "B", "C", "D", "E"), null)
39             val input = "123456"
40             val response = simpleWorkflow.executeWorkflow(graph, mockBluePrintRuntimeService(), input)
41             assertNotNull(response, "failed to get response")
42         }
43     }
44
45     @Test
46     fun testMultipleFlows() {
47         runBlocking {
48             coroutineScope {
49                 val wfs = listOf("12345", "12346").map {
50                     async {
51                         val graph = "[START>A/SUCCESS, A>B/SUCCESS, B>C/SUCCESS, C>D/SUCCESS, D>END/SUCCESS]"
52                                 .toGraph()
53                         val simpleWorkflow = TestBluePrintWorkFlowService()
54                         simpleWorkflow.simulatedState = prepareSimulation(arrayListOf("A", "B", "C", "D"), null)
55                         val response = simpleWorkflow.executeWorkflow(graph, mockBluePrintRuntimeService(it), it)
56                         assertNotNull(response, "failed to get response")
57                     }
58                 }
59                 wfs.awaitAll()
60             }
61         }
62     }
63
64     @Test
65     fun testMissingEdgeForBFailureState() {
66         runBlocking {
67             val graph = "[START>A/SUCCESS, A>B/SUCCESS, B>C/SUCCESS, C>D/SUCCESS, D>END/SUCCESS]"
68                     .toGraph()
69             val simpleWorkflow = TestBluePrintWorkFlowService()
70             simpleWorkflow.simulatedState = prepareSimulation(arrayListOf("A", "C", "D", "E"), arrayListOf("B"))
71             val input = "123456"
72             val response = simpleWorkflow.executeWorkflow(graph, mockBluePrintRuntimeService(), input)
73             assertNotNull(response, "failed to get response")
74         }
75     }
76
77     @Test
78     fun testBExceptionFlow() {
79         runBlocking {
80             val graph = "[START>A/SUCCESS, A>B/SUCCESS, B>C/SUCCESS, C>D/SUCCESS, D>END/SUCCESS]"
81                     .toGraph()
82             val simpleWorkflow = TestBluePrintWorkFlowService()
83             simpleWorkflow.simulatedState = prepareSimulation(arrayListOf("A", "C", "D", "E"), null)
84             val input = "123456"
85             val response = simpleWorkflow.executeWorkflow(graph, mockBluePrintRuntimeService(), input)
86             assertNotNull(response, "failed to get response")
87         }
88     }
89
90     @Test
91     fun testTimeoutExceptionFlow() {
92         runBlocking {
93             val graph = "[START>A/SUCCESS, A>TO/SUCCESS, TO>C/SUCCESS, C>D/SUCCESS, D>END/SUCCESS]"
94                     .toGraph()
95             val simpleWorkflow = TestBluePrintWorkFlowService()
96             simpleWorkflow.simulatedState = prepareSimulation(arrayListOf("A", "TO", "C", "D", "E"), null)
97             val input = "123456"
98             val response = simpleWorkflow.executeWorkflow(graph, mockBluePrintRuntimeService(), input)
99             assertNotNull(response, "failed to get response")
100         }
101     }
102
103     @Test
104     fun testConditionalFlow() {
105         runBlocking {
106             val graph = "[START>A/SUCCESS, A>B/SUCCESS, A>C/FAILURE, B>D/SUCCESS, C>D/SUCCESS, D>END/SUCCESS]"
107                     .toGraph()
108             val simpleWorkflow = TestBluePrintWorkFlowService()
109             simpleWorkflow.simulatedState = prepareSimulation(arrayListOf("A", "B", "C", "D", "E"), null)
110             val input = "123456"
111             val response = simpleWorkflow.executeWorkflow(graph, mockBluePrintRuntimeService(), input)
112             assertNotNull(response, "failed to get response")
113         }
114     }
115
116     @Test
117     fun testBothConditionalFlow() {
118         runBlocking {
119             // Failure Flow
120             val failurePatGraph = "[START>A/SUCCESS, A>B/SUCCESS, A>C/FAILURE, B>D/SUCCESS, C>D/SUCCESS, D>END/SUCCESS]"
121                     .toGraph()
122             val failurePathWorkflow = TestBluePrintWorkFlowService()
123             failurePathWorkflow.simulatedState = prepareSimulation(arrayListOf("B", "C", "D", "E"),
124                     arrayListOf("A"))
125             val failurePathWorkflowInput = "123456"
126             val failurePathResponse = failurePathWorkflow.executeWorkflow(failurePatGraph, mockBluePrintRuntimeService(), failurePathWorkflowInput)
127             assertNotNull(failurePathResponse, "failed to get response")
128         }
129     }
130
131     @Test
132     fun testMultipleSkipFlow() {
133         runBlocking {
134             val graph = "[START>A/SUCCESS, A>B/SUCCESS, A>C/FAILURE, C>D/SUCCESS, D>E/SUCCESS, B>E/SUCCESS, E>END/SUCCESS]"
135                     .toGraph()
136             val simpleWorkflow = TestBluePrintWorkFlowService()
137             simpleWorkflow.simulatedState = prepareSimulation(arrayListOf("A", "B", "C", "D", "E"), null)
138             val input = "123456"
139             val response = simpleWorkflow.executeWorkflow(graph, mockBluePrintRuntimeService(), input)
140             assertNotNull(response, "failed to get response")
141         }
142     }
143
144     @Test
145     fun testParallelFlow() {
146         runBlocking {
147             val graph = "[START>A/SUCCESS, A>B/SUCCESS, A>C/SUCCESS, B>D/SUCCESS, C>D/SUCCESS, D>END/SUCCESS]"
148                     .toGraph()
149             val simpleWorkflow = TestBluePrintWorkFlowService()
150             simpleWorkflow.simulatedState = prepareSimulation(arrayListOf("A", "B", "C", "D"), null)
151             val input = "123456"
152             val response = simpleWorkflow.executeWorkflow(graph, mockBluePrintRuntimeService(), input)
153             assertNotNull(response, "failed to get response")
154         }
155     }
156
157     private fun mockBluePrintRuntimeService(): BluePrintRuntimeService<*> {
158         return mockBluePrintRuntimeService("123456")
159     }
160
161     private fun mockBluePrintRuntimeService(id: String): BluePrintRuntimeService<*> {
162         val bluePrintRuntimeService = mockk<BluePrintRuntimeService<*>>()
163         every { bluePrintRuntimeService.id() } returns id
164         return bluePrintRuntimeService
165     }
166
167     private fun prepareSimulation(successes: List<String>?, failures: List<String>?): MutableMap<String, EdgeLabel> {
168         val simulatedState: MutableMap<String, EdgeLabel> = hashMapOf()
169         successes?.forEach {
170             simulatedState[it] = EdgeLabel.SUCCESS
171         }
172         failures?.forEach {
173             simulatedState[it] = EdgeLabel.FAILURE
174         }
175         return simulatedState
176     }
177 }
178
179 class TestBluePrintWorkFlowService
180     : AbstractBluePrintWorkFlowService<String, String>() {
181     val log = logger(TestBluePrintWorkFlowService::class)
182
183     lateinit var simulatedState: MutableMap<String, EdgeLabel>
184
185     override suspend fun initializeWorkflow(input: String): EdgeLabel {
186         return EdgeLabel.SUCCESS
187     }
188
189     override suspend fun executeWorkflow(graph: Graph, bluePrintRuntimeService: BluePrintRuntimeService<*>, input: String): String {
190         log.info("Executing Graph : $graph")
191         this.graph = graph
192         this.workflowId = bluePrintRuntimeService.id()
193         val output = CompletableDeferred<String>()
194         val startMessage = WorkflowExecuteMessage(input, output)
195         val workflowActor = workflowActor()
196         if (!workflowActor.isClosedForSend) {
197             workflowActor().send(startMessage)
198         } else {
199             throw BluePrintProcessorException("workflow actor is closed for send $workflowActor")
200         }
201         return startMessage.output.await()
202     }
203
204     override suspend fun prepareNodeExecutionMessage(node: Graph.Node)
205             : NodeExecuteMessage<String, String> {
206         return NodeExecuteMessage(node, "$node Input", "")
207     }
208
209     override suspend fun executeNode(node: Graph.Node, nodeInput: String,
210                                      nodeOutput: String): EdgeLabel {
211 //        val random = (1..10).random() * 100
212 //        log.info("workflow($workflowId) node(${node.id}) will reply in $random ms")
213 //        kotlinx.coroutines.delay(random.toLong())
214 //        //Simulation for timeout
215         if (node.id == "TO") {
216             withTimeout(1) {
217                 kotlinx.coroutines.delay(2)
218             }
219         }
220         return simulatedState[node.id] ?: throw BluePrintException("failed to get status for the node($node)")
221     }
222
223     override suspend fun prepareNodeSkipMessage(node: Graph.Node): NodeSkipMessage<String, String> {
224         val nodeOutput = ""
225         return NodeSkipMessage(node, "$node Skip Input", nodeOutput)
226     }
227
228     override suspend fun skipNode(node: Graph.Node, nodeInput: String,
229                                   nodeOutput: String): EdgeLabel {
230         return simulatedState[node.id] ?: throw BluePrintException("failed to get status for the node($node)")
231     }
232
233     override suspend fun cancelNode(node: Graph.Node, nodeInput: String,
234                                     nodeOutput: String): EdgeLabel {
235         TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
236     }
237
238     override suspend fun restartNode(node: Graph.Node, nodeInput: String,
239                                      nodeOutput: String): EdgeLabel {
240         TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
241     }
242
243     override suspend fun prepareWorkflowOutput(): String {
244         if (exceptions.isNotEmpty()) {
245             exceptions.forEach {
246                 log.error("workflow($workflowId) exceptions :", it)
247             }
248         }
249         return "Final Response"
250     }
251 }