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.ncmp.api.NetworkCmProxyCmHandleQueryService
31 import org.onap.cps.ncmp.api.NetworkCmProxyDataService
32 import org.onap.cps.ncmp.api.NetworkCmProxyQueryService
33 import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
34 import org.onap.cps.ncmp.api.impl.inventory.sync.ModuleSyncWatchdog
35 import org.onap.cps.ncmp.api.models.DmiPluginRegistration
36 import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
37 import org.onap.cps.spi.exceptions.DataspaceNotFoundException
38 import org.onap.cps.spi.model.DataNode
39 import org.onap.cps.spi.repository.DataspaceRepository
40 import org.onap.cps.spi.utils.SessionManager
41 import org.springframework.beans.factory.annotation.Autowired
42 import org.springframework.boot.autoconfigure.EnableAutoConfiguration
43 import org.springframework.boot.autoconfigure.domain.EntityScan
44 import org.springframework.boot.test.context.SpringBootTest
45 import org.springframework.context.annotation.ComponentScan
46 import org.springframework.data.jpa.repository.config.EnableJpaRepositories
47 import org.springframework.http.HttpStatus
48 import org.springframework.http.MediaType
49 import org.springframework.test.web.client.MockRestServiceServer
50 import org.springframework.web.client.RestTemplate
51 import org.testcontainers.spock.Testcontainers
52 import spock.lang.Shared
53 import spock.lang.Specification
54 import spock.util.concurrent.PollingConditions
56 import java.time.format.DateTimeFormatter
58 import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo
59 import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus
60 import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME;
61 import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR;
62 import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_PARENT;
64 @SpringBootTest(classes = [CpsDataspaceService])
66 @EnableAutoConfiguration
67 @EnableJpaRepositories(basePackageClasses = [DataspaceRepository])
68 @ComponentScan(basePackages = ['org.onap.cps'])
69 @EntityScan('org.onap.cps.spi.entities')
70 abstract class CpsIntegrationSpecBase extends Specification {
73 DatabaseTestContainer databaseTestContainer = DatabaseTestContainer.getInstance()
76 CpsDataspaceService cpsDataspaceService
79 CpsAnchorService cpsAnchorService
82 CpsDataService cpsDataService
85 CpsModuleService cpsModuleService
88 CpsQueryService cpsQueryService
91 SessionManager sessionManager
94 NetworkCmProxyCmHandleQueryService networkCmProxyCmHandleQueryService
97 NetworkCmProxyDataService networkCmProxyDataService
100 NetworkCmProxyQueryService networkCmProxyQueryService
103 RestTemplate restTemplate
106 ModuleSyncWatchdog moduleSyncWatchdog
108 MockRestServiceServer mockDmiServer = null
110 static final DMI_URL = 'http://mock-dmi-server'
112 def static GENERAL_TEST_DATASPACE = 'generalTestDataspace'
113 def static BOOKSTORE_SCHEMA_SET = 'bookstoreSchemaSet'
115 def static initialized = false
116 def now = OffsetDateTime.now()
120 cpsDataspaceService.createDataspace(GENERAL_TEST_DATASPACE)
121 createStandardBookStoreSchemaSet(GENERAL_TEST_DATASPACE)
124 mockDmiServer = MockRestServiceServer.bindTo(restTemplate).ignoreExpectOrder(true).build()
128 mockDmiServer.reset()
131 def static readResourceDataFile(filename) {
132 return new File('src/test/resources/data/' + filename).text
135 // *** CPS Integration Test Utilities ***
137 def static countDataNodesInTree(DataNode dataNode) {
138 return 1 + countDataNodesInTree(dataNode.getChildDataNodes())
141 def static countDataNodesInTree(Collection<DataNode> dataNodes) {
143 for (DataNode parent : dataNodes) {
144 nodeCount += countDataNodesInTree(parent)
149 def getBookstoreYangResourcesNameToContentMap() {
150 def bookstoreModelFileContent = readResourceDataFile('bookstore/bookstore.yang')
151 def bookstoreTypesFileContent = readResourceDataFile('bookstore/bookstore-types.yang')
152 return [bookstore: bookstoreModelFileContent, bookstoreTypes: bookstoreTypesFileContent]
155 def createStandardBookStoreSchemaSet(targetDataspace) {
156 cpsModuleService.createSchemaSet(targetDataspace, BOOKSTORE_SCHEMA_SET, getBookstoreYangResourcesNameToContentMap())
159 def createStandardBookStoreSchemaSet(targetDataspace, targetSchemaSet) {
160 cpsModuleService.createSchemaSet(targetDataspace, targetSchemaSet, getBookstoreYangResourcesNameToContentMap())
163 def dataspaceExists(dataspaceName) {
165 cpsDataspaceService.getDataspace(dataspaceName)
166 } catch (DataspaceNotFoundException ignored) {
172 def addAnchorsWithData(numberOfAnchors, dataspaceName, schemaSetName, anchorNamePrefix, data) {
173 (1..numberOfAnchors).each {
174 cpsAnchorService.createAnchor(dataspaceName, schemaSetName, anchorNamePrefix + it)
175 cpsDataService.saveData(dataspaceName, anchorNamePrefix + it, data.replace("Easons", "Easons-"+it.toString()), OffsetDateTime.now())
179 def createJsonArray(name, numberOfElements, keyName, keyValuePrefix, dataPerKey) {
180 def innerJson = (1..numberOfElements).collect {
181 '{"' + keyName + '":"' + keyValuePrefix + '-' + it + '"' + (dataPerKey.empty? '': ',' + dataPerKey) + '}'
183 return '{"' + name + '":[' + innerJson + ']}'
186 def createLeafList(name, numberOfElements, valuePrefix) {
187 def innerJson = (1..numberOfElements).collect {'"' + valuePrefix + '-' + it + '"'}.join(',')
188 return '"' + name + '":[' + innerJson + ']'
191 // *** NCMP Integration Test Utilities ***
193 def registerCmHandle(dmiPlugin, cmHandleId, moduleSetTag, dmiModuleReferencesResponse, dmiModuleResourcesResponse) {
194 def cmHandleToCreate = new NcmpServiceCmHandle(cmHandleId: cmHandleId, moduleSetTag: moduleSetTag)
195 networkCmProxyDataService.updateDmiRegistrationAndSyncModule(new DmiPluginRegistration(dmiPlugin: dmiPlugin, createdCmHandles: [cmHandleToCreate]))
196 mockDmiResponsesForModuleSync(dmiPlugin, cmHandleId, dmiModuleReferencesResponse, dmiModuleResourcesResponse)
197 moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
198 new PollingConditions().within(3, () -> {
199 CmHandleState.READY == networkCmProxyDataService.getCmHandleCompositeState(cmHandleId).cmHandleState
201 mockDmiServer.reset()
204 def deregisterCmHandle(dmiPlugin, cmHandleId) {
205 deregisterCmHandles(dmiPlugin, [cmHandleId])
208 def deregisterCmHandles(dmiPlugin, cmHandleIds) {
209 networkCmProxyDataService.updateDmiRegistrationAndSyncModule(new DmiPluginRegistration(dmiPlugin: dmiPlugin, removedCmHandles: cmHandleIds))
212 def mockDmiResponsesForModuleSync(dmiPlugin, cmHandleId, dmiModuleReferencesResponse, dmiModuleResourcesResponse) {
213 mockDmiServer.expect(requestTo("${dmiPlugin}/dmi/v1/ch/${cmHandleId}/modules"))
214 .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(dmiModuleReferencesResponse))
215 mockDmiServer.expect(requestTo("${dmiPlugin}/dmi/v1/ch/${cmHandleId}/moduleResources"))
216 .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(dmiModuleResourcesResponse))
219 def mockDmiIsNotAvailableForModuleSync(dmiPlugin, cmHandleId) {
220 mockDmiServer.expect(requestTo("${dmiPlugin}/dmi/v1/ch/${cmHandleId}/modules"))
221 .andRespond(withStatus(HttpStatus.SERVICE_UNAVAILABLE))
224 def overrideCmHandleLastUpdateTime(cmHandleId, newUpdateTime) {
225 String ISO_TIMESTAMP_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
226 DateTimeFormatter ISO_TIMESTAMP_FORMATTER = DateTimeFormatter.ofPattern(ISO_TIMESTAMP_PATTERN);
227 def jsonForUpdate = '{ "state": { "last-update-time": "%s" } }'.formatted(ISO_TIMESTAMP_FORMATTER.format(newUpdateTime))
228 cpsDataService.updateNodeLeaves(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
229 NCMP_DMI_REGISTRY_PARENT + "/cm-handles[@id='${cmHandleId}']", jsonForUpdate, now)