633486c6262f4339d65778b6ad5827423c9758cc
[ccsdk/cds.git] / components / model-catalog / blueprint-model / archetype-blueprint / src / main / resources / archetype-resources / Tests / kotlin / org / onap / ccsdk / cds / blueprintsprocessor / uat / base / BaseUatResourceResolutionTest.kt
1 package org.onap.ccsdk.cds.blueprintsprocessor.uat.base
2
3 import com.fasterxml.jackson.databind.ObjectMapper
4 import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
5 import com.nhaarman.mockitokotlin2.any
6 import com.nhaarman.mockitokotlin2.eq
7 import com.nhaarman.mockitokotlin2.mock
8 import com.nhaarman.mockitokotlin2.whenever
9 import io.mockk.every
10 import io.mockk.mockk
11 import io.mockk.spyk
12 import org.mockito.Answers
13 import org.onap.ccsdk.cds.blueprintsprocessor.core.BluePrintPropertiesService
14 import org.onap.ccsdk.cds.blueprintsprocessor.core.BluePrintPropertyConfiguration
15 import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput
16 import org.onap.ccsdk.cds.blueprintsprocessor.core.utils.PayloadUtils
17 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.ResourceResolutionConstants
18 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.ResourceResolutionService
19 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.ResourceResolutionServiceImpl
20 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.db.ResourceResolutionDBService
21 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.db.ResourceResolutionRepository
22 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.db.TemplateResolutionRepository
23 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.db.TemplateResolutionService
24 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.processor.CapabilityResourceResolutionProcessor
25 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.processor.DefaultResourceResolutionProcessor
26 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.processor.InputResourceResolutionProcessor
27 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.processor.RestResourceResolutionProcessor
28 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.utils.ResourceAssignmentUtils
29 import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BluePrintRestLibPropertyService
30 import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BlueprintWebClientService
31 import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.ComponentFunctionScriptingService
32 import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.scripts.DeprecatedBlueprintJythonService
33 import org.onap.ccsdk.cds.blueprintsprocessor.uat.logging.LogColor
34 import org.onap.ccsdk.cds.blueprintsprocessor.uat.logging.MockInvocationLogger
35 import org.onap.ccsdk.cds.blueprintsprocessor.uat.utils.ExpectationDefinition
36 import org.onap.ccsdk.cds.blueprintsprocessor.uat.utils.UatDefinition
37 import org.onap.ccsdk.cds.blueprintsprocessor.uat.utils.UatExecutor.MockPreInterceptor
38 import org.onap.ccsdk.cds.blueprintsprocessor.uat.utils.UatExecutor.SpyPostInterceptor
39 import org.onap.ccsdk.cds.controllerblueprints.core.config.BluePrintLoadConfiguration
40 import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintTemplateService
41 import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintMetadataUtils
42 import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
43 import org.onap.ccsdk.cds.controllerblueprints.resource.dict.ResourceAssignment
44 import org.slf4j.Logger
45 import org.slf4j.LoggerFactory
46 import org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext
47 import org.springframework.context.ApplicationContext
48
49 import java.io.File
50 import java.nio.file.Path
51 import kotlin.test.BeforeTest
52
53 /**
54  * This abstract base class supports tests of single workflow steps in an isolated manner, that are using
55  * {@see org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.ResourceResolutionComponent}.
56  * This means all the used external systems like e.g. sdnc or aai are mocked and must response with the correct
57  * BlueprintWebClientService.WebClientResponse to let the ressource resolution work properly.
58  *
59  * The component inside CDS, which is responsible for resolving resources is ResourceResolutionService.
60  * The ResourceResolutionService is using ResourceAssignmentProcessor's like e.g.
61  * InputResourceResolutionProcessor, DefaultResourceResolutionProcessor, RestResourceResolutionProcessor
62  * and CapabilityResourceResolutionProcessor
63  *
64  * These classes are only partially mocked by mockk spyk() function. This means, that the real classes are used
65  * and only some methods are rewritten via every {}.returns(...) functions
66  *
67  * For example the creation of ResourceAssignmentProcessor's are mocked in multiple
68  *
69  * every {applicationContext.getBean("${ResourceResolutionConstants.PREFIX_RESOURCE_RESOLUTION_PROCESSOR}???")}
70  * .returns( ResourceResolutionProcessorXXX() ) functions.
71  *
72  * The test is also based on UAT concept of the CDS project.
73  * The test makes usage of following classes:
74  *
75  * SpyService: Decorator for overwriting the function for handling the rest based communication with external systems
76  * fun exchangeResource(methodType: String,path: String,request: String,headers: Map<String, String>):
77  *  WebClientResponse<String>
78  * Uses ExpectationDefinition from the uat.yaml
79  *
80  * uat.MockPreInterceptor: Interceptor that hooks in the factory method of creation the different rest clients for
81  * external systems
82  * BluePrintRestLibPropertyService.blueprintWebClientService(selector: String): BlueprintWebClientService
83  * It is used for exchanging the "real service" by a mock (here a mockito based one)
84  *
85  * uat.SpyPostInterceptor: Interceptor that hooks in the factory method of creation the different rest clients for
86  * external systems
87  * BluePrintRestLibPropertyService.blueprintWebClientService(selector: String): BlueprintWebClientService
88  * It is used to inject the uat.SpyService decorator
89  *
90  * In a whole we do have the following decorator chain:  uat.SpyService ( Mockito mock (real service) )
91  *
92  * {@see UatDefinition}: Model of behaviour of external systems. Used at runtime as a representation for
93  * request / response correlation of the external systems. It is loaded from the uat.yaml
94  *
95   *
96  * Prerequisites
97  * - in the cba Definition folder the enriched data_types.json and node_types.json needs to be in the actual version.
98  *   inside the json workflow file (e.g. parameter-consistency.json) the includes to these json must be available.
99  * - uat.yaml for UatDefinition must be inside the cba/Test/ directory of the cba. This uat.yaml file must be adapted,
100  *   if the logic inside the steps changes.
101  *   See https://wiki.onap.org/pages/viewpage.action?pageId=59965554#ModelingConcepts-tests for details
102  */
103 abstract class BaseUatResourceResolutionTest {
104     private val resolutionKey = "resolutionKey"
105     private val resourceId = "1"
106     private val resourceType = "ServiceInstance"
107     private val occurrence = 0
108
109     // protected, bacause they maybe needed to be manipulated in inherited test classes
110     protected val props = hashMapOf<String, Any>()
111     protected var preInterceptor = MockPreInterceptor()
112     protected var postInterceptor = SpyPostInterceptor(ObjectMapper())
113     protected lateinit var resourceResolutionService: ResourceResolutionService
114     protected lateinit var applicationContext : ApplicationContext
115
116     companion object {
117         private val log: Logger = LoggerFactory.getLogger(BaseUatResourceResolutionTest::class.java)
118         private val mockLoggingListener = MockInvocationLogger(LogColor.markerOf(LogColor.COLOR_MOCKITO))
119     }
120
121     @BeforeTest
122     fun setup() {
123         props[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_STORE_RESULT] = false
124         props[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOLUTION_KEY] = resolutionKey
125         props[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOURCE_ID] = resourceId
126         props[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOURCE_TYPE] = resourceType
127         props[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE] = occurrence
128         props[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOLUTION_SUMMARY] = false
129
130         applicationContext = spyk(ReactiveWebServerApplicationContext())
131         val templateResolutionRepository = mockk<TemplateResolutionRepository>()
132         val templateResolutionService = spyk(TemplateResolutionService(templateResolutionRepository))
133         val bluePrintLoadConfiguration = spyk(BluePrintLoadConfiguration())
134         val bluePrintTemplateService = spyk(BluePrintTemplateService(bluePrintLoadConfiguration))
135         val resourceResolutionRepository = mockk<ResourceResolutionRepository>()
136         val resourceResolutionDBService = spyk(ResourceResolutionDBService(resourceResolutionRepository))
137
138         // ResourceResolutionService
139         resourceResolutionService = spyk(
140             ResourceResolutionServiceImpl(
141             applicationContext,
142             templateResolutionService,
143             bluePrintTemplateService,
144             resourceResolutionDBService)
145         )
146
147         // BluePrintRestLibPropertyService: setInterceptors "MockPreInterceptor" and "SpyPostInterceptor"
148         val bluePrintPropertyConfiguration = spyk(BluePrintPropertyConfiguration())
149         val bluePrintPropertiesService = spyk(BluePrintPropertiesService(bluePrintPropertyConfiguration))
150         val bluePrintRestLibPropertyService = BluePrintRestLibPropertyService(bluePrintPropertiesService)
151         bluePrintRestLibPropertyService.setInterceptors(preInterceptor, postInterceptor)
152
153         // ComponentFunctionScriptingService needed for CapabilityResourceResolutionProcessor
154         val blueprintJythonService = spyk(DeprecatedBlueprintJythonService())
155         val componentFunctionScriptingService = ComponentFunctionScriptingService(applicationContext, blueprintJythonService)
156
157         // Add ResourceResolutionProcessor's to the Spring ApplicationContext
158         // if more needed, add them in your own setUp method in derived test class
159         every { applicationContext.getBean("${ResourceResolutionConstants.PREFIX_RESOURCE_RESOLUTION_PROCESSOR}source-input") }.returns(
160             InputResourceResolutionProcessor()
161         )
162         every { applicationContext.getBean("${ResourceResolutionConstants.PREFIX_RESOURCE_RESOLUTION_PROCESSOR}source-default") }.returns(
163             DefaultResourceResolutionProcessor()
164         )
165         every { applicationContext.getBean("${ResourceResolutionConstants.PREFIX_RESOURCE_RESOLUTION_PROCESSOR}source-rest") }.returns(
166             RestResourceResolutionProcessor(bluePrintRestLibPropertyService)
167         )
168         every { applicationContext.getBean("${ResourceResolutionConstants.PREFIX_RESOURCE_RESOLUTION_PROCESSOR}source-capability") }.returns(
169             CapabilityResourceResolutionProcessor(componentFunctionScriptingService)
170         )
171
172         // create the Mockit mocks defined in the uat.yaml
173         createMockitoMocksByUatDefinition()
174     }
175
176     private fun createMockitoMocksByUatDefinition() {
177         // read uat file
178         val cwd: String = Path.of("").toAbsolutePath().toString()
179         log.info("current working directory : $cwd")
180
181         val uatSpec: String = File("$cwd/Tests/uat.yaml").readText(Charsets.UTF_8)
182         val uat = UatDefinition.load(jacksonObjectMapper(), uatSpec)
183         val expectationsPerClient = uat.externalServices.associateBy(
184             { service ->
185                 createRestClientMock(service.expectations).also { restClient ->
186                     // side-effect: register restClient to override real instance
187                     preInterceptor.registerMock(service.selector, restClient)
188                 }
189             },
190             { service -> service.expectations }
191         )
192     }
193
194     private fun createRestClientMock(restExpectations: List<ExpectationDefinition>):
195             BlueprintWebClientService {
196         val restClient = mock<BlueprintWebClientService>(
197             defaultAnswer = Answers.RETURNS_SMART_NULLS,
198             // our custom verboseLogging handler
199             invocationListeners = arrayOf(mockLoggingListener)
200         )
201
202         // Delegates to overloaded exchangeResource(String, String, String, Map<String, String>)
203         whenever(restClient.exchangeResource(any(), any(), any()))
204             .thenAnswer { invocation ->
205                 val method = invocation.arguments[0] as String
206                 val path = invocation.arguments[1] as String
207                 val request = invocation.arguments[2] as String
208                 restClient.exchangeResource(method, path, request, emptyMap())
209             }
210         for (expectation in restExpectations) {
211             var stubbing = whenever(
212                 restClient.exchangeResource(
213                     eq(expectation.request.method),
214                     eq(expectation.request.path),
215                     any(),
216                     any()
217                 )
218             )
219             for (response in expectation.responses) {
220                 stubbing = stubbing.thenReturn(
221                     BlueprintWebClientService.WebClientResponse(
222                         response.status,
223                         response.body.toString()
224                     )
225                 )
226             }
227         }
228         return restClient
229     }
230
231     protected suspend fun callResolveResources(
232         blueprintBasePath: String,
233         fileNameExecutionServiceInput: String,
234         workflowName: String,
235         nodeTemplateName: String,
236         artifactPrefixName: String
237     ): Pair<String, MutableList<ResourceAssignment>> {
238         val bluePrintRuntimeService = BluePrintMetadataUtils.getBluePrintRuntime(
239             "12345",
240             blueprintBasePath
241         )
242
243         val executionServiceInput =
244             JacksonUtils.readValueFromFile(
245                 fileNameExecutionServiceInput,
246                 ExecutionServiceInput::class.java
247             )!!
248
249         val resourceAssignmentRuntimeService =
250             ResourceAssignmentUtils.transformToRARuntimeService(
251                 bluePrintRuntimeService,
252                 "testResolveResource"
253             )
254
255         // Prepare Inputs
256         PayloadUtils.prepareInputsFromWorkflowPayload(
257             bluePrintRuntimeService,
258             executionServiceInput.payload,
259             workflowName
260         )
261
262         return resourceResolutionService.resolveResources(
263             resourceAssignmentRuntimeService,
264             nodeTemplateName,
265             artifactPrefixName,
266             props
267         )
268     }
269 }