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.autoconfigure.web.servlet.AutoConfigureMockMvc
45 import org.springframework.boot.test.context.SpringBootTest
46 import org.springframework.context.annotation.ComponentScan
47 import org.springframework.data.jpa.repository.config.EnableJpaRepositories
48 import org.springframework.http.HttpStatus
49 import org.springframework.http.MediaType
50 import org.springframework.test.web.client.MockRestServiceServer
51 import org.springframework.test.web.servlet.MockMvc
52 import org.springframework.web.client.RestTemplate
53 import org.testcontainers.spock.Testcontainers
54 import spock.lang.Shared
55 import spock.lang.Specification
56 import spock.util.concurrent.PollingConditions
58 import java.time.format.DateTimeFormatter
60 import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo
61 import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus
62 import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME;
63 import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR;
64 import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_PARENT;
66 @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK, classes = [CpsDataspaceService])
68 @EnableAutoConfiguration
70 @EnableJpaRepositories(basePackageClasses = [DataspaceRepository])
71 @ComponentScan(basePackages = ['org.onap.cps'])
72 @EntityScan('org.onap.cps.spi.entities')
73 abstract class CpsIntegrationSpecBase extends Specification {
76 DatabaseTestContainer databaseTestContainer = DatabaseTestContainer.getInstance()
82 CpsDataspaceService cpsDataspaceService
85 CpsAnchorService cpsAnchorService
88 CpsDataService cpsDataService
91 CpsModuleService cpsModuleService
94 CpsQueryService cpsQueryService
97 SessionManager sessionManager
100 NetworkCmProxyCmHandleQueryService networkCmProxyCmHandleQueryService
103 NetworkCmProxyDataService networkCmProxyDataService
106 NetworkCmProxyQueryService networkCmProxyQueryService
109 RestTemplate restTemplate
112 ModuleSyncWatchdog moduleSyncWatchdog
114 MockRestServiceServer mockDmiServer = null
116 static final DMI_URL = 'http://mock-dmi-server'
118 def static GENERAL_TEST_DATASPACE = 'generalTestDataspace'
119 def static BOOKSTORE_SCHEMA_SET = 'bookstoreSchemaSet'
121 def static initialized = false
122 def now = OffsetDateTime.now()
126 cpsDataspaceService.createDataspace(GENERAL_TEST_DATASPACE)
127 createStandardBookStoreSchemaSet(GENERAL_TEST_DATASPACE)
130 mockDmiServer = MockRestServiceServer.bindTo(restTemplate).ignoreExpectOrder(true).build()
134 mockDmiServer.reset()
137 def static readResourceDataFile(filename) {
138 return new File('src/test/resources/data/' + filename).text
141 // *** CPS Integration Test Utilities ***
143 def static countDataNodesInTree(DataNode dataNode) {
144 return 1 + countDataNodesInTree(dataNode.getChildDataNodes())
147 def static countDataNodesInTree(Collection<DataNode> dataNodes) {
149 for (DataNode parent : dataNodes) {
150 nodeCount += countDataNodesInTree(parent)
155 def getBookstoreYangResourcesNameToContentMap() {
156 def bookstoreModelFileContent = readResourceDataFile('bookstore/bookstore.yang')
157 def bookstoreTypesFileContent = readResourceDataFile('bookstore/bookstore-types.yang')
158 return [bookstore: bookstoreModelFileContent, bookstoreTypes: bookstoreTypesFileContent]
161 def createStandardBookStoreSchemaSet(targetDataspace) {
162 cpsModuleService.createSchemaSet(targetDataspace, BOOKSTORE_SCHEMA_SET, getBookstoreYangResourcesNameToContentMap())
165 def createStandardBookStoreSchemaSet(targetDataspace, targetSchemaSet) {
166 cpsModuleService.createSchemaSet(targetDataspace, targetSchemaSet, getBookstoreYangResourcesNameToContentMap())
169 def dataspaceExists(dataspaceName) {
171 cpsDataspaceService.getDataspace(dataspaceName)
172 } catch (DataspaceNotFoundException ignored) {
178 def addAnchorsWithData(numberOfAnchors, dataspaceName, schemaSetName, anchorNamePrefix, data) {
179 (1..numberOfAnchors).each {
180 cpsAnchorService.createAnchor(dataspaceName, schemaSetName, anchorNamePrefix + it)
181 cpsDataService.saveData(dataspaceName, anchorNamePrefix + it, data.replace("Easons", "Easons-"+it.toString()), OffsetDateTime.now())
185 def createJsonArray(name, numberOfElements, keyName, keyValuePrefix, dataPerKey) {
186 def innerJson = (1..numberOfElements).collect {
187 '{"' + keyName + '":"' + keyValuePrefix + '-' + it + '"' + (dataPerKey.empty? '': ',' + dataPerKey) + '}'
189 return '{"' + name + '":[' + innerJson + ']}'
192 def createLeafList(name, numberOfElements, valuePrefix) {
193 def innerJson = (1..numberOfElements).collect {'"' + valuePrefix + '-' + it + '"'}.join(',')
194 return '"' + name + '":[' + innerJson + ']'
197 // *** NCMP Integration Test Utilities ***
199 def registerCmHandle(dmiPlugin, cmHandleId, moduleSetTag, dmiModuleReferencesResponse, dmiModuleResourcesResponse) {
200 def cmHandleToCreate = new NcmpServiceCmHandle(cmHandleId: cmHandleId, moduleSetTag: moduleSetTag)
201 networkCmProxyDataService.updateDmiRegistrationAndSyncModule(new DmiPluginRegistration(dmiPlugin: dmiPlugin, createdCmHandles: [cmHandleToCreate]))
202 mockDmiResponsesForModuleSync(dmiPlugin, cmHandleId, dmiModuleReferencesResponse, dmiModuleResourcesResponse)
203 moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
204 new PollingConditions().within(3, () -> {
205 CmHandleState.READY == networkCmProxyDataService.getCmHandleCompositeState(cmHandleId).cmHandleState
207 mockDmiServer.reset()
210 def deregisterCmHandle(dmiPlugin, cmHandleId) {
211 deregisterCmHandles(dmiPlugin, [cmHandleId])
214 def deregisterCmHandles(dmiPlugin, cmHandleIds) {
215 networkCmProxyDataService.updateDmiRegistrationAndSyncModule(new DmiPluginRegistration(dmiPlugin: dmiPlugin, removedCmHandles: cmHandleIds))
218 def mockDmiResponsesForModuleSync(dmiPlugin, cmHandleId, dmiModuleReferencesResponse, dmiModuleResourcesResponse) {
219 mockDmiServer.expect(requestTo("${dmiPlugin}/dmi/v1/ch/${cmHandleId}/modules"))
220 .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(dmiModuleReferencesResponse))
221 mockDmiServer.expect(requestTo("${dmiPlugin}/dmi/v1/ch/${cmHandleId}/moduleResources"))
222 .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(dmiModuleResourcesResponse))
225 def mockDmiIsNotAvailableForModuleSync(dmiPlugin, cmHandleId) {
226 mockDmiServer.expect(requestTo("${dmiPlugin}/dmi/v1/ch/${cmHandleId}/modules"))
227 .andRespond(withStatus(HttpStatus.SERVICE_UNAVAILABLE))
230 def overrideCmHandleLastUpdateTime(cmHandleId, newUpdateTime) {
231 String ISO_TIMESTAMP_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
232 DateTimeFormatter ISO_TIMESTAMP_FORMATTER = DateTimeFormatter.ofPattern(ISO_TIMESTAMP_PATTERN);
233 def jsonForUpdate = '{ "state": { "last-update-time": "%s" } }'.formatted(ISO_TIMESTAMP_FORMATTER.format(newUpdateTime))
234 cpsDataService.updateNodeLeaves(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
235 NCMP_DMI_REGISTRY_PARENT + "/cm-handles[@id='${cmHandleId}']", jsonForUpdate, now)