Merge "Condense Liquibase steps"
[cps.git] / integration-test / src / test / groovy / org / onap / cps / integration / base / CpsIntegrationSpecBase.groovy
1 /*
2  *  ============LICENSE_START=======================================================
3  *  Copyright (C) 2023-2024 Nordix Foundation
4  *  ================================================================================
5  *  Licensed under the Apache License, Version 2.0 (the 'License');
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *        http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an 'AS IS' BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  *  SPDX-License-Identifier: Apache-2.0
18  *  ============LICENSE_END=========================================================
19  */
20
21 package org.onap.cps.integration.base
22
23 import java.time.OffsetDateTime
24 import java.time.format.DateTimeFormatter
25 import org.onap.cps.api.CpsAnchorService
26 import org.onap.cps.api.CpsDataService
27 import org.onap.cps.api.CpsDataspaceService
28 import org.onap.cps.api.CpsModuleService
29 import org.onap.cps.api.CpsQueryService
30 import org.onap.cps.integration.DatabaseTestContainer
31 import org.onap.cps.integration.KafkaTestContainer
32 import org.onap.cps.ncmp.api.NetworkCmProxyCmHandleQueryService
33 import org.onap.cps.ncmp.api.NetworkCmProxyDataService
34 import org.onap.cps.ncmp.api.NetworkCmProxyQueryService
35 import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
36 import org.onap.cps.ncmp.api.impl.inventory.sync.ModuleSyncWatchdog
37 import org.onap.cps.ncmp.api.models.DmiPluginRegistration
38 import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
39 import org.onap.cps.spi.exceptions.DataspaceNotFoundException
40 import org.onap.cps.spi.model.DataNode
41 import org.onap.cps.spi.repository.DataspaceRepository
42 import org.onap.cps.spi.utils.SessionManager
43 import org.onap.cps.utils.JsonObjectMapper
44 import org.springframework.beans.factory.annotation.Autowired
45 import org.springframework.boot.autoconfigure.EnableAutoConfiguration
46 import org.springframework.boot.autoconfigure.domain.EntityScan
47 import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
48 import org.springframework.boot.test.context.SpringBootTest
49 import org.springframework.context.annotation.ComponentScan
50 import org.springframework.data.jpa.repository.config.EnableJpaRepositories
51 import org.springframework.http.HttpStatus
52 import org.springframework.http.MediaType
53 import org.springframework.test.web.client.MockRestServiceServer
54 import org.springframework.test.web.servlet.MockMvc
55 import org.springframework.web.client.RestTemplate
56 import org.testcontainers.spock.Testcontainers
57 import spock.lang.Shared
58 import spock.lang.Specification
59 import spock.util.concurrent.PollingConditions
60
61 import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME
62 import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR
63 import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_PARENT
64 import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo
65 import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus
66
67 @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK, classes = [CpsDataspaceService])
68 @Testcontainers
69 @EnableAutoConfiguration
70 @AutoConfigureMockMvc
71 @EnableJpaRepositories(basePackageClasses = [DataspaceRepository])
72 @ComponentScan(basePackages = ['org.onap.cps'])
73 @EntityScan('org.onap.cps.spi.entities')
74 abstract class CpsIntegrationSpecBase extends Specification {
75
76     @Shared
77     DatabaseTestContainer databaseTestContainer = DatabaseTestContainer.getInstance()
78
79     @Shared
80     KafkaTestContainer kafkaTestContainer = KafkaTestContainer.getInstance()
81
82     @Autowired
83     MockMvc mvc
84
85     @Autowired
86     CpsDataspaceService cpsDataspaceService
87
88     @Autowired
89     CpsAnchorService cpsAnchorService
90
91     @Autowired
92     CpsDataService cpsDataService
93
94     @Autowired
95     CpsModuleService cpsModuleService
96
97     @Autowired
98     CpsQueryService cpsQueryService
99
100     @Autowired
101     SessionManager sessionManager
102
103     @Autowired
104     NetworkCmProxyCmHandleQueryService networkCmProxyCmHandleQueryService
105
106     @Autowired
107     NetworkCmProxyDataService networkCmProxyDataService
108
109     @Autowired
110     NetworkCmProxyQueryService networkCmProxyQueryService
111
112     @Autowired
113     RestTemplate restTemplate
114
115     @Autowired
116     ModuleSyncWatchdog moduleSyncWatchdog
117
118     @Autowired
119     JsonObjectMapper jsonObjectMapper
120
121     MockRestServiceServer mockDmiServer = null
122
123     static final DMI_URL = 'http://mock-dmi-server'
124
125     def static GENERAL_TEST_DATASPACE = 'generalTestDataspace'
126     def static BOOKSTORE_SCHEMA_SET = 'bookstoreSchemaSet'
127
128     def static initialized = false
129     def now = OffsetDateTime.now()
130
131     def setup() {
132         if (!initialized) {
133             cpsDataspaceService.createDataspace(GENERAL_TEST_DATASPACE)
134             createStandardBookStoreSchemaSet(GENERAL_TEST_DATASPACE)
135             initialized = true
136         }
137         mockDmiServer = MockRestServiceServer.bindTo(restTemplate).ignoreExpectOrder(true).build()
138     }
139
140     def cleanup() {
141         mockDmiServer.reset()
142     }
143
144     def static readResourceDataFile(filename) {
145         return new File('src/test/resources/data/' + filename).text
146     }
147
148     // *** CPS Integration Test Utilities ***
149
150     def static countDataNodesInTree(DataNode dataNode) {
151         return 1 + countDataNodesInTree(dataNode.getChildDataNodes())
152     }
153
154     def static countDataNodesInTree(Collection<DataNode> dataNodes) {
155         int nodeCount = 0
156         for (DataNode parent : dataNodes) {
157             nodeCount += countDataNodesInTree(parent)
158         }
159         return nodeCount
160     }
161
162     def getBookstoreYangResourcesNameToContentMap() {
163         def bookstoreModelFileContent = readResourceDataFile('bookstore/bookstore.yang')
164         def bookstoreTypesFileContent = readResourceDataFile('bookstore/bookstore-types.yang')
165         return [bookstore: bookstoreModelFileContent, bookstoreTypes: bookstoreTypesFileContent]
166     }
167
168     def createStandardBookStoreSchemaSet(targetDataspace) {
169         cpsModuleService.createSchemaSet(targetDataspace, BOOKSTORE_SCHEMA_SET, getBookstoreYangResourcesNameToContentMap())
170     }
171
172     def createStandardBookStoreSchemaSet(targetDataspace, targetSchemaSet) {
173         cpsModuleService.createSchemaSet(targetDataspace, targetSchemaSet, getBookstoreYangResourcesNameToContentMap())
174     }
175
176     def dataspaceExists(dataspaceName) {
177         try {
178             cpsDataspaceService.getDataspace(dataspaceName)
179         } catch (DataspaceNotFoundException ignored) {
180             return false
181         }
182         return true
183     }
184
185     def addAnchorsWithData(numberOfAnchors, dataspaceName, schemaSetName, anchorNamePrefix, data) {
186         (1..numberOfAnchors).each {
187             cpsAnchorService.createAnchor(dataspaceName, schemaSetName, anchorNamePrefix + it)
188             cpsDataService.saveData(dataspaceName, anchorNamePrefix + it, data.replace("Easons", "Easons-"+it.toString()), OffsetDateTime.now())
189         }
190     }
191
192     def createJsonArray(name, numberOfElements, keyName, keyValuePrefix, dataPerKey) {
193         def innerJson = (1..numberOfElements).collect {
194             '{"' + keyName + '":"' + keyValuePrefix + '-' + it + '"' + (dataPerKey.empty? '': ',' + dataPerKey) + '}'
195         }.join(',')
196         return '{"' + name + '":[' + innerJson + ']}'
197     }
198
199     def createLeafList(name, numberOfElements, valuePrefix) {
200         def innerJson = (1..numberOfElements).collect {'"' + valuePrefix + '-' + it + '"'}.join(',')
201         return '"' + name + '":[' + innerJson + ']'
202     }
203
204     // *** NCMP Integration Test Utilities ***
205
206     def registerCmHandle(dmiPlugin, cmHandleId, moduleSetTag, dmiModuleReferencesResponse, dmiModuleResourcesResponse) {
207         def cmHandleToCreate = new NcmpServiceCmHandle(cmHandleId: cmHandleId, moduleSetTag: moduleSetTag)
208         networkCmProxyDataService.updateDmiRegistrationAndSyncModule(new DmiPluginRegistration(dmiPlugin: dmiPlugin, createdCmHandles: [cmHandleToCreate]))
209         mockDmiResponsesForModuleSync(dmiPlugin, cmHandleId, dmiModuleReferencesResponse, dmiModuleResourcesResponse)
210         moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
211         new PollingConditions().within(3, () -> {
212             CmHandleState.READY == networkCmProxyDataService.getCmHandleCompositeState(cmHandleId).cmHandleState
213         })
214         mockDmiServer.reset()
215     }
216
217     def deregisterCmHandle(dmiPlugin, cmHandleId) {
218         deregisterCmHandles(dmiPlugin, [cmHandleId])
219     }
220
221     def deregisterCmHandles(dmiPlugin, cmHandleIds) {
222         networkCmProxyDataService.updateDmiRegistrationAndSyncModule(new DmiPluginRegistration(dmiPlugin: dmiPlugin, removedCmHandles: cmHandleIds))
223     }
224
225     def mockDmiResponsesForModuleSync(dmiPlugin, cmHandleId, dmiModuleReferencesResponse, dmiModuleResourcesResponse) {
226         mockDmiServer.expect(requestTo("${dmiPlugin}/dmi/v1/ch/${cmHandleId}/modules"))
227                 .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(dmiModuleReferencesResponse))
228         mockDmiServer.expect(requestTo("${dmiPlugin}/dmi/v1/ch/${cmHandleId}/moduleResources"))
229                 .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(dmiModuleResourcesResponse))
230     }
231
232     def mockDmiIsNotAvailableForModuleSync(dmiPlugin, cmHandleId) {
233         mockDmiServer.expect(requestTo("${dmiPlugin}/dmi/v1/ch/${cmHandleId}/modules"))
234                 .andRespond(withStatus(HttpStatus.SERVICE_UNAVAILABLE))
235     }
236
237     def overrideCmHandleLastUpdateTime(cmHandleId, newUpdateTime) {
238         String ISO_TIMESTAMP_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
239         DateTimeFormatter ISO_TIMESTAMP_FORMATTER = DateTimeFormatter.ofPattern(ISO_TIMESTAMP_PATTERN);
240         def jsonForUpdate = '{ "state": { "last-update-time": "%s" } }'.formatted(ISO_TIMESTAMP_FORMATTER.format(newUpdateTime))
241         cpsDataService.updateNodeLeaves(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
242                 NCMP_DMI_REGISTRY_PARENT + "/cm-handles[@id='${cmHandleId}']", jsonForUpdate, now)
243     }
244 }