2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2023-2025 OpenInfra Foundation Europe. All rights reserved.
4 * Modifications Copyright (C) 2024-2025 TechMahindra Ltd.
5 * ================================================================================
6 * Licensed under the Apache License, Version 2.0 (the 'License');
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an 'AS IS' BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 * SPDX-License-Identifier: Apache-2.0
19 * ============LICENSE_END=========================================================
22 package org.onap.cps.integration.base
24 import com.hazelcast.map.IMap
25 import okhttp3.mockwebserver.MockWebServer
26 import org.onap.cps.api.CpsAnchorService
27 import org.onap.cps.api.CpsDataService
28 import org.onap.cps.api.CpsDataspaceService
29 import org.onap.cps.api.CpsDeltaService
30 import org.onap.cps.api.CpsModuleService
31 import org.onap.cps.api.CpsQueryService
32 import org.onap.cps.api.exceptions.DataspaceNotFoundException
33 import org.onap.cps.api.model.DataNode
34 import org.onap.cps.integration.DatabaseTestContainer
35 import org.onap.cps.integration.KafkaTestContainer
36 import org.onap.cps.ncmp.api.inventory.models.CmHandleState
37 import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistration
38 import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle
39 import org.onap.cps.ncmp.impl.NetworkCmProxyInventoryFacadeImpl
40 import org.onap.cps.ncmp.impl.data.NetworkCmProxyFacade
41 import org.onap.cps.ncmp.impl.data.NetworkCmProxyQueryService
42 import org.onap.cps.ncmp.impl.inventory.InventoryPersistence
43 import org.onap.cps.ncmp.impl.inventory.ParameterizedCmHandleQueryService
44 import org.onap.cps.ncmp.impl.inventory.sync.ModuleSyncService
45 import org.onap.cps.ncmp.impl.inventory.sync.ModuleSyncWatchdog
46 import org.onap.cps.ncmp.impl.utils.AlternateIdMatcher
47 import org.onap.cps.ncmp.rest.controller.NetworkCmProxyInventoryController
48 import org.onap.cps.ri.repository.DataspaceRepository
49 import org.onap.cps.ri.repository.SchemaSetRepository
50 import org.onap.cps.ri.utils.SessionManager
51 import org.onap.cps.spi.CpsModulePersistenceService
52 import org.onap.cps.utils.JsonObjectMapper
53 import org.springframework.beans.factory.annotation.Autowired
54 import org.springframework.beans.factory.annotation.Value
55 import org.springframework.boot.autoconfigure.EnableAutoConfiguration
56 import org.springframework.boot.autoconfigure.domain.EntityScan
57 import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
58 import org.springframework.boot.test.context.SpringBootTest
59 import org.springframework.context.annotation.ComponentScan
60 import org.springframework.data.jpa.repository.config.EnableJpaRepositories
61 import org.springframework.test.context.ActiveProfiles
62 import org.springframework.test.web.servlet.MockMvc
63 import org.testcontainers.spock.Testcontainers
64 import spock.lang.Shared
65 import spock.lang.Specification
67 import java.time.OffsetDateTime
68 import java.util.concurrent.BlockingQueue
70 @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK, classes = [CpsDataspaceService])
72 @EnableAutoConfiguration
74 @EnableJpaRepositories(basePackageClasses = [DataspaceRepository])
75 @ComponentScan(basePackages = ['org.onap.cps'])
76 @EntityScan('org.onap.cps.ri.models')
77 @ActiveProfiles('module-sync-delayed')
78 abstract class CpsIntegrationSpecBase extends Specification {
81 DatabaseTestContainer databaseTestContainer = DatabaseTestContainer.getInstance()
84 KafkaTestContainer kafkaTestContainer = KafkaTestContainer.getInstance()
90 NetworkCmProxyInventoryController networkCmProxyInventoryController
93 CpsDataspaceService cpsDataspaceService
96 CpsAnchorService cpsAnchorService
99 CpsDataService cpsDataService
102 CpsDeltaService cpsDeltaService
105 CpsModuleService cpsModuleService
108 CpsQueryService cpsQueryService
111 SessionManager sessionManager
114 CpsModulePersistenceService cpsModulePersistenceService
117 DataspaceRepository dataspaceRepository
120 SchemaSetRepository schemaSetRepository
123 ParameterizedCmHandleQueryService networkCmProxyCmHandleQueryService
126 NetworkCmProxyFacade networkCmProxyFacade
129 NetworkCmProxyInventoryFacadeImpl NetworkCmProxyInventoryFacade
132 NetworkCmProxyQueryService networkCmProxyQueryService
135 ModuleSyncWatchdog moduleSyncWatchdog
138 ModuleSyncService moduleSyncService
141 BlockingQueue<String> moduleSyncWorkQueue
144 IMap<String, String> cpsAndNcmpLock
147 JsonObjectMapper jsonObjectMapper
150 InventoryPersistence inventoryPersistence
153 AlternateIdMatcher alternateIdMatcher
155 @Value('${ncmp.policy-executor.server.port:8080}')
156 private String policyServerPort;
158 MockWebServer mockDmiServer1 = new MockWebServer()
159 MockWebServer mockDmiServer2 = new MockWebServer()
160 MockWebServer mockPolicyServer = new MockWebServer()
162 DmiDispatcher dmiDispatcher1 = new DmiDispatcher()
163 DmiDispatcher dmiDispatcher2 = new DmiDispatcher()
165 PolicyDispatcher policyDispatcher = new PolicyDispatcher();
170 static NO_MODULE_SET_TAG = ''
171 static NO_ALTERNATE_ID = ''
172 static GENERAL_TEST_DATASPACE = 'generalTestDataspace'
173 static BOOKSTORE_SCHEMA_SET = 'bookstoreSchemaSet'
175 static initialized = false
176 def now = OffsetDateTime.now()
178 enum ModuleNameStrategy { UNIQUE, OVERLAPPING }
182 cpsDataspaceService.createDataspace(GENERAL_TEST_DATASPACE)
183 createStandardBookStoreSchemaSet(GENERAL_TEST_DATASPACE)
186 mockDmiServer1.setDispatcher(dmiDispatcher1)
187 mockDmiServer1.start()
189 mockDmiServer2.setDispatcher(dmiDispatcher2)
190 mockDmiServer2.start()
192 mockPolicyServer.setDispatcher(policyDispatcher)
193 mockPolicyServer.start(Integer.valueOf(policyServerPort))
195 DMI1_URL = String.format("http://%s:%s", mockDmiServer1.getHostName(), mockDmiServer1.getPort())
196 DMI2_URL = String.format("http://%s:%s", mockDmiServer2.getHostName(), mockDmiServer2.getPort())
200 mockDmiServer1.shutdown()
201 mockDmiServer2.shutdown()
202 mockPolicyServer.shutdown()
203 cpsModuleService.deleteAllUnusedYangModuleData('NFP-Operational')
206 def static readResourceDataFile(filename) {
207 return new File('src/test/resources/data/' + filename).text
210 // *** CPS Integration Test Utilities ***
212 def static countDataNodesInTree(DataNode dataNode) {
213 return 1 + countDataNodesInTree(dataNode.getChildDataNodes())
216 def static countDataNodesInTree(Collection<DataNode> dataNodes) {
218 for (DataNode parent : dataNodes) {
219 nodeCount += countDataNodesInTree(parent)
224 def getBookstoreyangResourceContentPerName() {
225 def bookstoreModelFileContent = readResourceDataFile('bookstore/bookstore.yang')
226 def bookstoreTypesFileContent = readResourceDataFile('bookstore/bookstore-types.yang')
227 return [bookstore: bookstoreModelFileContent, bookstoreTypes: bookstoreTypesFileContent]
230 def createStandardBookStoreSchemaSet(targetDataspace) {
231 cpsModuleService.createSchemaSet(targetDataspace, BOOKSTORE_SCHEMA_SET, getBookstoreyangResourceContentPerName())
234 def createStandardBookStoreSchemaSet(targetDataspace, targetSchemaSet) {
235 cpsModuleService.createSchemaSet(targetDataspace, targetSchemaSet, getBookstoreyangResourceContentPerName())
238 def dataspaceExists(dataspaceName) {
240 cpsDataspaceService.getDataspace(dataspaceName)
241 } catch (DataspaceNotFoundException ignored) {
247 def addAnchorsWithData(numberOfAnchors, dataspaceName, schemaSetName, anchorNamePrefix, data, contentType) {
248 (1..numberOfAnchors).each {
249 cpsAnchorService.createAnchor(dataspaceName, schemaSetName, anchorNamePrefix + it)
250 cpsDataService.saveData(dataspaceName, anchorNamePrefix + it, data.replace("Easons", "Easons-"+it.toString()), OffsetDateTime.now(), contentType)
254 def createJsonArray(name, numberOfElements, keyName, keyValuePrefix, dataPerKey) {
255 def innerJson = (1..numberOfElements).collect {
256 '{"' + keyName + '":"' + keyValuePrefix + '-' + it + '"' + (dataPerKey.empty? '': ',' + dataPerKey) + '}'
258 return '{"' + name + '":[' + innerJson + ']}'
261 def createLeafList(name, numberOfElements, valuePrefix) {
262 def innerJson = (1..numberOfElements).collect {'"' + valuePrefix + '-' + it + '"'}.join(',')
263 return '"' + name + '":[' + innerJson + ']'
266 // *** NCMP Integration Test Utilities ***
268 def registerCmHandle(dmiPlugin, cmHandleId, moduleSetTag) {
269 registerCmHandle(dmiPlugin, cmHandleId, moduleSetTag, NO_ALTERNATE_ID)
272 def registerCmHandle(dmiPlugin, cmHandleId, moduleSetTag, alternateId) {
273 registerCmHandleWithoutWaitForReady(dmiPlugin, cmHandleId, moduleSetTag, alternateId)
274 moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
275 CmHandleState.READY == networkCmProxyInventoryFacade.getCmHandleCompositeState(cmHandleId).cmHandleState
278 def registerCmHandleWithoutWaitForReady(dmiPlugin, cmHandleId, moduleSetTag, alternateId) {
279 def cmHandleToCreate = new NcmpServiceCmHandle(cmHandleId: cmHandleId, moduleSetTag: moduleSetTag, alternateId: alternateId, dataProducerIdentifier: 'some data producer id')
280 networkCmProxyInventoryFacade.updateDmiRegistration(new DmiPluginRegistration(dmiPlugin: dmiPlugin, createdCmHandles: [cmHandleToCreate]))
283 def registerSequenceOfCmHandlesWithManyModuleReferencesButDoNotWaitForReady(dmiPlugin, moduleSetTag, numberOfCmHandles, offset) {
284 registerSequenceOfCmHandles(dmiPlugin, moduleSetTag, numberOfCmHandles, offset, ModuleNameStrategy.UNIQUE, { id -> "alt=${id}" })
287 def registerSequenceOfCmHandlesWithManyModuleReferencesButDoNotWaitForReady(dmiPlugin, moduleSetTag, numberOfCmHandles, offset, altIdPrefix) {
288 registerSequenceOfCmHandles(dmiPlugin, moduleSetTag, numberOfCmHandles, offset, ModuleNameStrategy.UNIQUE, { id -> "${altIdPrefix}alt=${id}" })
292 def registerSequenceOfCmHandlesWithManyModuleReferencesButDoNotWaitForReady(dmiPlugin, moduleSetTag, numberOfCmHandles, offset, ModuleNameStrategy moduleNameStrategy) {
293 registerSequenceOfCmHandles(dmiPlugin, moduleSetTag, numberOfCmHandles, offset, moduleNameStrategy, { id -> "alt=${id}" })
296 def registerSequenceOfCmHandlesWithManyModuleReferencesButDoNotWaitForReady(dmiPlugin, moduleSetTag, numberOfCmHandles, offset, ModuleNameStrategy moduleNameStrategy, Closure<String> alternateIdGenerator) {
297 registerSequenceOfCmHandles(dmiPlugin, moduleSetTag, numberOfCmHandles, offset, moduleNameStrategy, alternateIdGenerator)
300 def registerSequenceOfCmHandles(dmiPlugin, moduleSetTag, numberOfCmHandles, offset, ModuleNameStrategy moduleNameStrategy, Closure<String> alternateIdGenerator) {
303 def modulePrefix = moduleNameStrategy.OVERLAPPING.equals(moduleNameStrategy) ? 'same' : moduleSetTag
304 def moduleReferences = (1..200).collect { "${modulePrefix}Module${it}" }
306 (1..numberOfCmHandles).each {
307 def alternateId = alternateIdGenerator(id)
308 def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: "ch-${id}", moduleSetTag: moduleSetTag, alternateId: alternateId)
309 cmHandles.add(ncmpServiceCmHandle)
310 dmiDispatcher1.moduleNamesPerCmHandleId[ncmpServiceCmHandle.cmHandleId] = moduleReferences
311 dmiDispatcher2.moduleNamesPerCmHandleId[ncmpServiceCmHandle.cmHandleId] = moduleReferences
314 networkCmProxyInventoryFacade.updateDmiRegistration(new DmiPluginRegistration(dmiPlugin: dmiPlugin, createdCmHandles: cmHandles))
317 def deregisterCmHandle(dmiPlugin, cmHandleId) {
318 deregisterCmHandles(dmiPlugin, [cmHandleId])
321 def deregisterCmHandles(dmiPlugin, cmHandleIds) {
322 networkCmProxyInventoryFacade.updateDmiRegistration(new DmiPluginRegistration(dmiPlugin: dmiPlugin, removedCmHandles: cmHandleIds))
325 def deregisterSequenceOfCmHandles(dmiPlugin, numberOfCmHandles, offset) {
328 (1..numberOfCmHandles).each { cmHandleIds.add('ch-' + id++) }
329 networkCmProxyInventoryFacade.updateDmiRegistration(new DmiPluginRegistration(dmiPlugin: dmiPlugin, removedCmHandles: cmHandleIds))