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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 * SPDX-License-Identifier: Apache-2.0
18 * ============LICENSE_END=========================================================
21 package org.onap.cps.integration.base
23 import java.time.OffsetDateTime
24 import org.onap.cps.api.CpsAnchorService
25 import org.onap.cps.api.CpsDataService
26 import org.onap.cps.api.CpsDataspaceService
27 import org.onap.cps.api.CpsModuleService
28 import org.onap.cps.api.CpsQueryService
29 import org.onap.cps.integration.DatabaseTestContainer
30 import org.onap.cps.integration.KafkaTestContainer
31 import org.onap.cps.ncmp.api.NetworkCmProxyCmHandleQueryService
32 import org.onap.cps.ncmp.api.NetworkCmProxyDataService
33 import org.onap.cps.ncmp.api.NetworkCmProxyQueryService
34 import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
35 import org.onap.cps.ncmp.api.impl.inventory.sync.ModuleSyncWatchdog
36 import org.onap.cps.ncmp.api.models.DmiPluginRegistration
37 import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
38 import org.onap.cps.spi.exceptions.DataspaceNotFoundException
39 import org.onap.cps.spi.model.DataNode
40 import org.onap.cps.spi.repository.DataspaceRepository
41 import org.onap.cps.spi.utils.SessionManager
42 import org.springframework.beans.factory.annotation.Autowired
43 import org.springframework.boot.autoconfigure.EnableAutoConfiguration
44 import org.springframework.boot.autoconfigure.domain.EntityScan
45 import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
46 import org.springframework.boot.test.context.SpringBootTest
47 import org.springframework.context.annotation.ComponentScan
48 import org.springframework.data.jpa.repository.config.EnableJpaRepositories
49 import org.springframework.http.HttpStatus
50 import org.springframework.http.MediaType
51 import org.springframework.test.web.client.MockRestServiceServer
52 import org.springframework.test.web.servlet.MockMvc
53 import org.springframework.web.client.RestTemplate
54 import org.testcontainers.spock.Testcontainers
55 import spock.lang.Shared
56 import spock.lang.Specification
57 import spock.util.concurrent.PollingConditions
59 import java.time.format.DateTimeFormatter
61 import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo
62 import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus
63 import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME
64 import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR
65 import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_PARENT
67 @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK, classes = [CpsDataspaceService])
69 @EnableAutoConfiguration
71 @EnableJpaRepositories(basePackageClasses = [DataspaceRepository])
72 @ComponentScan(basePackages = ['org.onap.cps'])
73 @EntityScan('org.onap.cps.spi.entities')
74 abstract class CpsIntegrationSpecBase extends Specification {
77 DatabaseTestContainer databaseTestContainer = DatabaseTestContainer.getInstance()
80 KafkaTestContainer kafkaTestContainer = KafkaTestContainer.getInstance();
86 CpsDataspaceService cpsDataspaceService
89 CpsAnchorService cpsAnchorService
92 CpsDataService cpsDataService
95 CpsModuleService cpsModuleService
98 CpsQueryService cpsQueryService
101 SessionManager sessionManager
104 NetworkCmProxyCmHandleQueryService networkCmProxyCmHandleQueryService
107 NetworkCmProxyDataService networkCmProxyDataService
110 NetworkCmProxyQueryService networkCmProxyQueryService
113 RestTemplate restTemplate
116 ModuleSyncWatchdog moduleSyncWatchdog
118 MockRestServiceServer mockDmiServer = null
120 static final DMI_URL = 'http://mock-dmi-server'
122 def static GENERAL_TEST_DATASPACE = 'generalTestDataspace'
123 def static BOOKSTORE_SCHEMA_SET = 'bookstoreSchemaSet'
125 def static initialized = false
126 def now = OffsetDateTime.now()
130 cpsDataspaceService.createDataspace(GENERAL_TEST_DATASPACE)
131 createStandardBookStoreSchemaSet(GENERAL_TEST_DATASPACE)
134 mockDmiServer = MockRestServiceServer.bindTo(restTemplate).ignoreExpectOrder(true).build()
138 mockDmiServer.reset()
141 def static readResourceDataFile(filename) {
142 return new File('src/test/resources/data/' + filename).text
145 // *** CPS Integration Test Utilities ***
147 def static countDataNodesInTree(DataNode dataNode) {
148 return 1 + countDataNodesInTree(dataNode.getChildDataNodes())
151 def static countDataNodesInTree(Collection<DataNode> dataNodes) {
153 for (DataNode parent : dataNodes) {
154 nodeCount += countDataNodesInTree(parent)
159 def getBookstoreYangResourcesNameToContentMap() {
160 def bookstoreModelFileContent = readResourceDataFile('bookstore/bookstore.yang')
161 def bookstoreTypesFileContent = readResourceDataFile('bookstore/bookstore-types.yang')
162 return [bookstore: bookstoreModelFileContent, bookstoreTypes: bookstoreTypesFileContent]
165 def createStandardBookStoreSchemaSet(targetDataspace) {
166 cpsModuleService.createSchemaSet(targetDataspace, BOOKSTORE_SCHEMA_SET, getBookstoreYangResourcesNameToContentMap())
169 def createStandardBookStoreSchemaSet(targetDataspace, targetSchemaSet) {
170 cpsModuleService.createSchemaSet(targetDataspace, targetSchemaSet, getBookstoreYangResourcesNameToContentMap())
173 def dataspaceExists(dataspaceName) {
175 cpsDataspaceService.getDataspace(dataspaceName)
176 } catch (DataspaceNotFoundException ignored) {
182 def addAnchorsWithData(numberOfAnchors, dataspaceName, schemaSetName, anchorNamePrefix, data) {
183 (1..numberOfAnchors).each {
184 cpsAnchorService.createAnchor(dataspaceName, schemaSetName, anchorNamePrefix + it)
185 cpsDataService.saveData(dataspaceName, anchorNamePrefix + it, data.replace("Easons", "Easons-"+it.toString()), OffsetDateTime.now())
189 def createJsonArray(name, numberOfElements, keyName, keyValuePrefix, dataPerKey) {
190 def innerJson = (1..numberOfElements).collect {
191 '{"' + keyName + '":"' + keyValuePrefix + '-' + it + '"' + (dataPerKey.empty? '': ',' + dataPerKey) + '}'
193 return '{"' + name + '":[' + innerJson + ']}'
196 def createLeafList(name, numberOfElements, valuePrefix) {
197 def innerJson = (1..numberOfElements).collect {'"' + valuePrefix + '-' + it + '"'}.join(',')
198 return '"' + name + '":[' + innerJson + ']'
201 // *** NCMP Integration Test Utilities ***
203 def registerCmHandle(dmiPlugin, cmHandleId, moduleSetTag, dmiModuleReferencesResponse, dmiModuleResourcesResponse) {
204 def cmHandleToCreate = new NcmpServiceCmHandle(cmHandleId: cmHandleId, moduleSetTag: moduleSetTag)
205 networkCmProxyDataService.updateDmiRegistrationAndSyncModule(new DmiPluginRegistration(dmiPlugin: dmiPlugin, createdCmHandles: [cmHandleToCreate]))
206 mockDmiResponsesForModuleSync(dmiPlugin, cmHandleId, dmiModuleReferencesResponse, dmiModuleResourcesResponse)
207 moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
208 new PollingConditions().within(3, () -> {
209 CmHandleState.READY == networkCmProxyDataService.getCmHandleCompositeState(cmHandleId).cmHandleState
211 mockDmiServer.reset()
214 def deregisterCmHandle(dmiPlugin, cmHandleId) {
215 deregisterCmHandles(dmiPlugin, [cmHandleId])
218 def deregisterCmHandles(dmiPlugin, cmHandleIds) {
219 networkCmProxyDataService.updateDmiRegistrationAndSyncModule(new DmiPluginRegistration(dmiPlugin: dmiPlugin, removedCmHandles: cmHandleIds))
222 def mockDmiResponsesForModuleSync(dmiPlugin, cmHandleId, dmiModuleReferencesResponse, dmiModuleResourcesResponse) {
223 mockDmiServer.expect(requestTo("${dmiPlugin}/dmi/v1/ch/${cmHandleId}/modules"))
224 .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(dmiModuleReferencesResponse))
225 mockDmiServer.expect(requestTo("${dmiPlugin}/dmi/v1/ch/${cmHandleId}/moduleResources"))
226 .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(dmiModuleResourcesResponse))
229 def mockDmiIsNotAvailableForModuleSync(dmiPlugin, cmHandleId) {
230 mockDmiServer.expect(requestTo("${dmiPlugin}/dmi/v1/ch/${cmHandleId}/modules"))
231 .andRespond(withStatus(HttpStatus.SERVICE_UNAVAILABLE))
234 def overrideCmHandleLastUpdateTime(cmHandleId, newUpdateTime) {
235 String ISO_TIMESTAMP_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
236 DateTimeFormatter ISO_TIMESTAMP_FORMATTER = DateTimeFormatter.ofPattern(ISO_TIMESTAMP_PATTERN);
237 def jsonForUpdate = '{ "state": { "last-update-time": "%s" } }'.formatted(ISO_TIMESTAMP_FORMATTER.format(newUpdateTime))
238 cpsDataService.updateNodeLeaves(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
239 NCMP_DMI_REGISTRY_PARENT + "/cm-handles[@id='${cmHandleId}']", jsonForUpdate, now)