diff options
Diffstat (limited to 'integration-test/src')
18 files changed, 247 insertions, 173 deletions
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy index 75cb3cd7a2..9b79af95ff 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy @@ -22,6 +22,8 @@ package org.onap.cps.integration.base import com.hazelcast.map.IMap +import java.time.OffsetDateTime +import java.util.concurrent.BlockingQueue import okhttp3.mockwebserver.MockWebServer import org.onap.cps.api.CpsAnchorService import org.onap.cps.api.CpsDataService @@ -44,7 +46,9 @@ import org.onap.cps.ncmp.impl.inventory.sync.ModuleSyncService import org.onap.cps.ncmp.impl.inventory.sync.ModuleSyncWatchdog import org.onap.cps.ncmp.impl.utils.AlternateIdMatcher import org.onap.cps.ri.repository.DataspaceRepository +import org.onap.cps.ri.repository.SchemaSetRepository import org.onap.cps.ri.utils.SessionManager +import org.onap.cps.spi.CpsModulePersistenceService import org.onap.cps.utils.JsonObjectMapper import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Value @@ -59,10 +63,6 @@ import org.springframework.test.web.servlet.MockMvc import org.testcontainers.spock.Testcontainers import spock.lang.Shared import spock.lang.Specification -import spock.util.concurrent.PollingConditions - -import java.time.OffsetDateTime -import java.util.concurrent.BlockingQueue @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK, classes = [CpsDataspaceService]) @Testcontainers @@ -102,6 +102,15 @@ abstract class CpsIntegrationSpecBase extends Specification { SessionManager sessionManager @Autowired + CpsModulePersistenceService cpsModulePersistenceService + + @Autowired + DataspaceRepository dataspaceRepository + + @Autowired + SchemaSetRepository schemaSetRepository + + @Autowired ParameterizedCmHandleQueryService networkCmProxyCmHandleQueryService @Autowired @@ -153,7 +162,6 @@ abstract class CpsIntegrationSpecBase extends Specification { static NO_ALTERNATE_ID = '' static GENERAL_TEST_DATASPACE = 'generalTestDataspace' static BOOKSTORE_SCHEMA_SET = 'bookstoreSchemaSet' - static MODULE_SYNC_WAIT_TIME_IN_SECONDS = 2 static initialized = false def now = OffsetDateTime.now() @@ -204,18 +212,18 @@ abstract class CpsIntegrationSpecBase extends Specification { return nodeCount } - def getBookstoreYangResourcesNameToContentMap() { + def getBookstoreyangResourceContentPerName() { def bookstoreModelFileContent = readResourceDataFile('bookstore/bookstore.yang') def bookstoreTypesFileContent = readResourceDataFile('bookstore/bookstore-types.yang') return [bookstore: bookstoreModelFileContent, bookstoreTypes: bookstoreTypesFileContent] } def createStandardBookStoreSchemaSet(targetDataspace) { - cpsModuleService.createSchemaSet(targetDataspace, BOOKSTORE_SCHEMA_SET, getBookstoreYangResourcesNameToContentMap()) + cpsModuleService.createSchemaSet(targetDataspace, BOOKSTORE_SCHEMA_SET, getBookstoreyangResourceContentPerName()) } def createStandardBookStoreSchemaSet(targetDataspace, targetSchemaSet) { - cpsModuleService.createSchemaSet(targetDataspace, targetSchemaSet, getBookstoreYangResourcesNameToContentMap()) + cpsModuleService.createSchemaSet(targetDataspace, targetSchemaSet, getBookstoreyangResourceContentPerName()) } def dataspaceExists(dataspaceName) { @@ -255,13 +263,11 @@ abstract class CpsIntegrationSpecBase extends Specification { def registerCmHandle(dmiPlugin, cmHandleId, moduleSetTag, alternateId) { registerCmHandleWithoutWaitForReady(dmiPlugin, cmHandleId, moduleSetTag, alternateId) moduleSyncWatchdog.moduleSyncAdvisedCmHandles() - new PollingConditions().within(MODULE_SYNC_WAIT_TIME_IN_SECONDS, () -> { - CmHandleState.READY == networkCmProxyInventoryFacade.getCmHandleCompositeState(cmHandleId).cmHandleState - }) + CmHandleState.READY == networkCmProxyInventoryFacade.getCmHandleCompositeState(cmHandleId).cmHandleState } def registerCmHandleWithoutWaitForReady(dmiPlugin, cmHandleId, moduleSetTag, alternateId) { - def cmHandleToCreate = new NcmpServiceCmHandle(cmHandleId: cmHandleId, moduleSetTag: moduleSetTag, alternateId: alternateId) + def cmHandleToCreate = new NcmpServiceCmHandle(cmHandleId: cmHandleId, moduleSetTag: moduleSetTag, alternateId: alternateId, dataProducerIdentifier: 'some data producer id') networkCmProxyInventoryFacade.updateDmiRegistration(new DmiPluginRegistration(dmiPlugin: dmiPlugin, createdCmHandles: [cmHandleToCreate])) } @@ -275,7 +281,7 @@ abstract class CpsIntegrationSpecBase extends Specification { def modulePrefix = moduleNameStrategy.OVERLAPPING.equals(moduleNameStrategy) ? 'same' : moduleSetTag def moduleReferences = (1..200).collect { "${modulePrefix}Module${it}" } (1..numberOfCmHandles).each { - def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: "ch-${id}", moduleSetTag: moduleSetTag, alternateId: NO_ALTERNATE_ID) + def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: "ch-${id}", moduleSetTag: moduleSetTag, alternateId: "alt=${id}") cmHandles.add(ncmpServiceCmHandle) dmiDispatcher1.moduleNamesPerCmHandleId[ncmpServiceCmHandle.cmHandleId] = moduleReferences dmiDispatcher2.moduleNamesPerCmHandleId[ncmpServiceCmHandle.cmHandleId] = moduleReferences diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/base/DmiDispatcher.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/base/DmiDispatcher.groovy index 35a7b6a7c2..11c0ff2743 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/base/DmiDispatcher.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/base/DmiDispatcher.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2024 Nordix Foundation + * Copyright (C) 2024-2025 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the 'License'); * you may not use this file except in compliance with the License. @@ -29,6 +29,7 @@ import org.springframework.http.HttpStatus import org.springframework.http.MediaType import java.util.regex.Matcher +import java.util.stream.Collectors import static org.onap.cps.integration.base.CpsIntegrationSpecBase.readResourceDataFile @@ -81,7 +82,7 @@ class DmiDispatcher extends Dispatcher { // get module resources for a CM-handle case ~'^/dmi/v1/ch/(.*)/moduleResources$': def cmHandleId = Matcher.lastMatcher[0][1] - return getModuleResourcesResponse(cmHandleId) + return getModuleResourcesResponse(request, cmHandleId) // pass-through data operation for a CM-handle case ~'^/dmi/v1/ch/(.*)/data/ds/(.*)$': @@ -113,7 +114,7 @@ class DmiDispatcher extends Dispatcher { def destination = Matcher.lastMatcher[0][1] def subJobWriteRequest = jsonSlurper.parseText(request.getBody().readUtf8()) this.receivedSubJobs.put(destination, subJobWriteRequest) - def response = '{"subJobId":"some sub job id", "dmiServiceName":"some dmi service name", "dataProducerId":"some data producer id"}' + def response = '{"subJobId":"some sub job id"}' return mockResponseWithBody(HttpStatus.OK, response) } @@ -124,8 +125,13 @@ class DmiDispatcher extends Dispatcher { return mockResponseWithBody(HttpStatus.OK, moduleReferences) } - def getModuleResourcesResponse(cmHandleId) { - def moduleResources = '[' + getModuleNamesForCmHandle(cmHandleId).collect { + def getModuleResourcesResponse(request, cmHandleId) { + def moduleResourcesRequest = jsonSlurper.parseText(request.getBody().readUtf8()) + def requestedModuleNames = moduleResourcesRequest.get('data').get('modules').collect{it.get('name')} + def candidateModuleNames = getModuleNamesForCmHandle(cmHandleId) + def moduleNames = candidateModuleNames.stream().filter(candidate -> requestedModuleNames.contains(candidate)).toList() + + def moduleResources = '[' + moduleNames.collect { MODULE_RESOURCES_RESPONSE_TEMPLATE.replaceAll("<MODULE_NAME>", it) }.join(',') + ']' return mockResponseWithBody(HttpStatus.OK, moduleResources) diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/ModuleServiceIntegrationSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/ModuleServiceIntegrationSpec.groovy index c787b4209e..9a48dd72f3 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/ModuleServiceIntegrationSpec.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/ModuleServiceIntegrationSpec.groovy @@ -21,8 +21,6 @@ package org.onap.cps.integration.functional.cps import org.onap.cps.api.CpsModuleService -import org.onap.cps.integration.base.FunctionalSpecBase -import org.onap.cps.api.parameters.CascadeDeleteAllowed import org.onap.cps.api.exceptions.AlreadyDefinedException import org.onap.cps.api.exceptions.DataspaceNotFoundException import org.onap.cps.api.exceptions.ModelValidationException @@ -30,6 +28,8 @@ import org.onap.cps.api.exceptions.SchemaSetInUseException import org.onap.cps.api.exceptions.SchemaSetNotFoundException import org.onap.cps.api.model.ModuleDefinition import org.onap.cps.api.model.ModuleReference +import org.onap.cps.api.parameters.CascadeDeleteAllowed +import org.onap.cps.integration.base.FunctionalSpecBase class ModuleServiceIntegrationSpec extends FunctionalSpecBase { @@ -53,8 +53,8 @@ class ModuleServiceIntegrationSpec extends FunctionalSpecBase { } """ - def newYangResourcesNameToContentMap = [:] - def moduleReferences = [] + def yangResourceContentPerName = [:] + def allModuleReferences = [] def noNewModules = [:] def bookstoreModelFileContent = readResourceDataFile('bookstore/bookstore.yang') def bookstoreTypesFileContent = readResourceDataFile('bookstore/bookstore-types.yang') @@ -67,9 +67,9 @@ class ModuleServiceIntegrationSpec extends FunctionalSpecBase { def 'Create new schema set from yang resources with #scenario'() { given: 'a new schema set with #numberOfModules modules' - populateNewYangResourcesNameToContentMapAndAllModuleReferences(numberOfNewModules) + populateYangResourceContentPerNameAndAllModuleReferences(numberOfNewModules) when: 'the new schema set is created' - objectUnderTest.createSchemaSet(FUNCTIONAL_TEST_DATASPACE_1, 'newSchemaSet', newYangResourcesNameToContentMap) + objectUnderTest.createSchemaSet(FUNCTIONAL_TEST_DATASPACE_1, 'newSchemaSet', yangResourceContentPerName) then: 'the number of module references has increased by #numberOfNewModules' def yangResourceModuleReferences = objectUnderTest.getYangResourceModuleReferences(FUNCTIONAL_TEST_DATASPACE_1) originalNumberOfModuleReferences + numberOfNewModules == yangResourceModuleReferences.size() @@ -93,49 +93,53 @@ class ModuleServiceIntegrationSpec extends FunctionalSpecBase { def 'Create new schema set from modules with #scenario'() { given: 'a new schema set with #numberOfNewModules modules' - populateNewYangResourcesNameToContentMapAndAllModuleReferences(numberOfNewModules) + populateYangResourceContentPerNameAndAllModuleReferences(numberOfNewModules) and: 'add existing module references (optional)' - moduleReferences.addAll(existingModuleReferences) + allModuleReferences.addAll(existingModuleReferences) when: 'the new schema set is created' def schemaSetName = "NewSchemaWith${numberOfNewModules}Modules" - objectUnderTest.createSchemaSetFromModules(FUNCTIONAL_TEST_DATASPACE_1, schemaSetName, newYangResourcesNameToContentMap, moduleReferences) + objectUnderTest.createSchemaSetFromModules(FUNCTIONAL_TEST_DATASPACE_1, schemaSetName, yangResourceContentPerName, allModuleReferences) and: 'associated with a new anchor' cpsAnchorService.createAnchor(FUNCTIONAL_TEST_DATASPACE_1, schemaSetName, 'newAnchor') then: 'the new anchor has the correct number of modules' def yangResourceModuleReferences = objectUnderTest.getYangResourcesModuleReferences(FUNCTIONAL_TEST_DATASPACE_1, 'newAnchor') assert expectedNumberOfModulesForAnchor == yangResourceModuleReferences.size() + and: 'the schema set has the correct number of modules too' + def dataspaceEntity = dataspaceRepository.getByName(FUNCTIONAL_TEST_DATASPACE_1) + def schemaSetEntity = schemaSetRepository.getByDataspaceAndName(dataspaceEntity, schemaSetName) + assert expectedNumberOfModulesForAnchor == schemaSetEntity.yangResources.size() cleanup: objectUnderTest.deleteSchemaSetsWithCascade(FUNCTIONAL_TEST_DATASPACE_1, [ schemaSetName.toString() ]) where: 'the following module references are provided' scenario | numberOfNewModules | existingModuleReferences || expectedNumberOfModulesForAnchor 'empty schema set' | 0 | [ ] || 0 - 'one existing module' | 0 | [bookStoreModuleReference ] || 1 + 'one existing module' | 0 | [ bookStoreModuleReference ] || 1 'two new modules' | 2 | [ ] || 2 - 'two new modules, one existing' | 2 | [bookStoreModuleReference ] || 3 + 'two new modules, one existing' | 2 | [ bookStoreModuleReference ] || 3 'over max batch size #modules' | 101 | [ ] || 101 'two valid, one invalid module' | 2 | [ new ModuleReference('NOT EXIST','IRRELEVANT') ] || 2 } def 'Duplicate schema content.'() { given: 'a map of yang resources' - populateNewYangResourcesNameToContentMapAndAllModuleReferences(1) + populateYangResourceContentPerNameAndAllModuleReferences(1) when: 'a new schema set is created' - objectUnderTest.createSchemaSet(FUNCTIONAL_TEST_DATASPACE_1, 'newSchema1', newYangResourcesNameToContentMap) + objectUnderTest.createSchemaSet(FUNCTIONAL_TEST_DATASPACE_1, 'newSchema1', yangResourceContentPerName) then: 'the dataspace has one new module (reference)' def numberOfModuleReferencesAfterFirstSchemaSetHasBeenAdded = objectUnderTest.getYangResourceModuleReferences(FUNCTIONAL_TEST_DATASPACE_1).size() assert numberOfModuleReferencesAfterFirstSchemaSetHasBeenAdded == originalNumberOfModuleReferences + 1 when: 'a second new schema set is created' - objectUnderTest.createSchemaSet(FUNCTIONAL_TEST_DATASPACE_1, 'newSchema2', newYangResourcesNameToContentMap) + objectUnderTest.createSchemaSet(FUNCTIONAL_TEST_DATASPACE_1, 'newSchema2', yangResourceContentPerName) then: 'the dataspace has no additional module (reference)' assert numberOfModuleReferencesAfterFirstSchemaSetHasBeenAdded == objectUnderTest.getYangResourceModuleReferences(FUNCTIONAL_TEST_DATASPACE_1).size() - cleanup: + cleanup: 'the data created in this test' objectUnderTest.deleteSchemaSetsWithCascade(FUNCTIONAL_TEST_DATASPACE_1, [ 'newSchema1', 'newSchema2']) } def 'Attempt to create schema set, error scenario: #scenario.'() { when: 'attempt to store schema set #schemaSetName in dataspace #dataspaceName' - populateNewYangResourcesNameToContentMapAndAllModuleReferences(0) - objectUnderTest.createSchemaSet(dataspaceName, schemaSetName, newYangResourcesNameToContentMap) + populateYangResourceContentPerNameAndAllModuleReferences(0) + objectUnderTest.createSchemaSet(dataspaceName, schemaSetName, yangResourceContentPerName) then: 'an #expectedException is thrown' thrown(expectedException) where: 'the following data is used' @@ -146,7 +150,7 @@ class ModuleServiceIntegrationSpec extends FunctionalSpecBase { def 'Attempt to create duplicate schema set from modules.'() { when: 'attempt to store duplicate schema set from modules' - objectUnderTest.createSchemaSetFromModules(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_SCHEMA_SET, newYangResourcesNameToContentMap, []) + objectUnderTest.createSchemaSetFromModules(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_SCHEMA_SET, yangResourceContentPerName, []) then: 'an Already Defined Exception is thrown' thrown(AlreadyDefinedException) } @@ -192,12 +196,12 @@ class ModuleServiceIntegrationSpec extends FunctionalSpecBase { def 'Identifying new module references with #scenario'() { when: 'identifyNewModuleReferences is called' - def result = objectUnderTest.identifyNewModuleReferences(moduleReferences) + def result = objectUnderTest.identifyNewModuleReferences(allModuleReferences) then: 'the correct module references are returned' assert result.size() == expectedResult.size() assert result.containsAll(expectedResult) where: 'the following data is used' - scenario | moduleReferences || expectedResult + scenario | allModuleReferences || expectedResult 'just new module references' | [new ModuleReference('new1', 'r1'), new ModuleReference('new2', 'r1')] || [new ModuleReference('new1', 'r1'), new ModuleReference('new2', 'r1')] 'one new module,one existing reference' | [new ModuleReference('new1', 'r1'), bookStoreModuleReference] || [new ModuleReference('new1', 'r1')] 'no new module references' | [bookStoreModuleReference] || [] @@ -212,29 +216,71 @@ class ModuleServiceIntegrationSpec extends FunctionalSpecBase { assert result.name == 'bookstoreSchemaSet' assert result.moduleReferences.size() == 2 assert result.moduleReferences.containsAll(bookStoreModuleReferenceWithNamespace, bookStoreTypesModuleReferenceWithNamespace) + and: 'the yang resource is stored with the normalized filename' + def fileName = cpsModulePersistenceService.getYangSchemaResources(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_SCHEMA_SET).keySet()[0] + assert fileName == 'bookstore-types@2024-01-30.yang' } def 'Retrieve all schema sets.'() { given: 'an extra schema set is stored' - populateNewYangResourcesNameToContentMapAndAllModuleReferences(1) - objectUnderTest.createSchemaSet(FUNCTIONAL_TEST_DATASPACE_1, 'newSchema1', newYangResourcesNameToContentMap) + populateYangResourceContentPerNameAndAllModuleReferences(1) + objectUnderTest.createSchemaSet(FUNCTIONAL_TEST_DATASPACE_1, 'newSchema1', yangResourceContentPerName) when: 'all schema sets are retrieved' def result = objectUnderTest.getSchemaSets(FUNCTIONAL_TEST_DATASPACE_1) then: 'the result contains all expected schema sets' assert result.name.size() == 2 assert result.name.containsAll('bookstoreSchemaSet', 'newSchema1') - cleanup: + cleanup: 'the data created in this test' objectUnderTest.deleteSchemaSetsWithCascade(FUNCTIONAL_TEST_DATASPACE_1, ['newSchema1']) } + def 'Create schema set with duplicate module filename [CPS-138].'() { + given: 'store the original number of sets and modules' + def numberOfSchemaSets = objectUnderTest.getSchemaSets(FUNCTIONAL_TEST_DATASPACE_1).size() + def numberOfModuleReferences = objectUnderTest.getYangResourceModuleReferences(FUNCTIONAL_TEST_DATASPACE_1).size() + and: 'create a new schema set using a module with filename identical to a previously stored module (e.g. bookstore)' + populateYangResourceContentPerNameAndAllModuleReferences('otherModule', 1) + def otherModuleContent = yangResourceContentPerName.values()[0] + def mapWithDuplicateName = ['bookstore' : otherModuleContent] + objectUnderTest.createSchemaSet(FUNCTIONAL_TEST_DATASPACE_1, 'newSchema', mapWithDuplicateName) + when: 'the yang resource details are retrieved' + def yangSchemaResources = cpsModulePersistenceService.getYangSchemaResources(FUNCTIONAL_TEST_DATASPACE_1, 'newSchema') + then: 'the file name of the resource has been normalized' + def fileName = yangSchemaResources.keySet()[0] + assert fileName == 'otherModule_0@2000-01-01.yang' + and: 'the yang resource has the correct content' + assert yangSchemaResources.get(fileName) == otherModuleContent + and: 'the number of schema sets and modules has increased as expected' + assert objectUnderTest.getSchemaSets(FUNCTIONAL_TEST_DATASPACE_1).size() == numberOfSchemaSets + 1 + assert objectUnderTest.getYangResourceModuleReferences(FUNCTIONAL_TEST_DATASPACE_1).size() == numberOfModuleReferences + 1 + cleanup: 'the data created in this test' + objectUnderTest.deleteSchemaSetsWithCascade(FUNCTIONAL_TEST_DATASPACE_1, ['newSchema']) + } + + def 'Create schema set with RFC-6020 filename pattern but incorrect details [CPS-138].'() { + given: 'create a new schema set using a module with filename identical to a previously stored module (e.g. bookstore)' + populateYangResourceContentPerNameAndAllModuleReferences('otherModule', 1) + def otherModuleContent = yangResourceContentPerName.values()[0] + def mapIncorrectName = ['wrongModuleAndRevision@1999-08-08.yang': otherModuleContent] + objectUnderTest.createSchemaSet(FUNCTIONAL_TEST_DATASPACE_1, 'newSchema', mapIncorrectName) + when: 'the yang resource details are retrieved' + def yangSchemaResources = cpsModulePersistenceService.getYangSchemaResources(FUNCTIONAL_TEST_DATASPACE_1, 'newSchema') + then: 'the file name of the resource has been normalized' + def fileName = yangSchemaResources.keySet()[0] + assert fileName == 'otherModule_0@2000-01-01.yang' + cleanup: 'the data created in this test' + objectUnderTest.deleteSchemaSetsWithCascade(FUNCTIONAL_TEST_DATASPACE_1, ['newSchema']) + } + + /* D E L E T E S C H E M A S E T U S E - C A S E S */ def 'Delete schema sets with(out) cascade.'() { given: 'a schema set' - populateNewYangResourcesNameToContentMapAndAllModuleReferences(1) - objectUnderTest.createSchemaSet(FUNCTIONAL_TEST_DATASPACE_1, 'newSchemaSet', newYangResourcesNameToContentMap) + populateYangResourceContentPerNameAndAllModuleReferences(1) + objectUnderTest.createSchemaSet(FUNCTIONAL_TEST_DATASPACE_1, 'newSchemaSet', yangResourceContentPerName) and: 'optionally create anchor for the schema set' if (associateWithAnchor) { cpsAnchorService.createAnchor(FUNCTIONAL_TEST_DATASPACE_1, 'newSchemaSet', 'newAnchor') @@ -249,7 +295,7 @@ class ModuleServiceIntegrationSpec extends FunctionalSpecBase { then: 'check if the dataspace still contains the new schema set or not' def remainingSchemaSetNames = objectUnderTest.getSchemaSets(FUNCTIONAL_TEST_DATASPACE_1).name assert remainingSchemaSetNames.contains('newSchemaSet') == expectSchemaSetStillPresent - cleanup: + cleanup: 'the data created in this test' objectUnderTest.deleteSchemaSetsWithCascade(FUNCTIONAL_TEST_DATASPACE_1, ['newSchemaSet']) where: 'the following options are used' associateWithAnchor | cascadeDeleteAllowedOption || expectSchemaSetStillPresent @@ -261,11 +307,11 @@ class ModuleServiceIntegrationSpec extends FunctionalSpecBase { def 'Delete schema sets with shared resources.'() { given: 'a new schema set' - populateNewYangResourcesNameToContentMapAndAllModuleReferences(1) - objectUnderTest.createSchemaSet(FUNCTIONAL_TEST_DATASPACE_1, 'newSchemaSet1', newYangResourcesNameToContentMap) + populateYangResourceContentPerNameAndAllModuleReferences(1) + objectUnderTest.createSchemaSet(FUNCTIONAL_TEST_DATASPACE_1, 'newSchemaSet1', yangResourceContentPerName) and: 'another schema set which shares one yang resource (module)' - populateNewYangResourcesNameToContentMapAndAllModuleReferences(2) - objectUnderTest.createSchemaSet(FUNCTIONAL_TEST_DATASPACE_1, 'newSchemaSet2', newYangResourcesNameToContentMap) + populateYangResourceContentPerNameAndAllModuleReferences(2) + objectUnderTest.createSchemaSet(FUNCTIONAL_TEST_DATASPACE_1, 'newSchemaSet2', yangResourceContentPerName) when: 'all schema sets are retrieved' def moduleRevisions = objectUnderTest.getYangResourceModuleReferences(FUNCTIONAL_TEST_DATASPACE_1).revision then: 'both modules (revisions) are present' @@ -280,7 +326,7 @@ class ModuleServiceIntegrationSpec extends FunctionalSpecBase { def remainingModuleRevisions = objectUnderTest.getYangResourceModuleReferences(FUNCTIONAL_TEST_DATASPACE_1).revision assert remainingModuleRevisions.contains('2000-01-01') assert !remainingModuleRevisions.contains('2001-01-01') - cleanup: + cleanup: 'the data created in this test' objectUnderTest.deleteSchemaSetsWithCascade(FUNCTIONAL_TEST_DATASPACE_1, ['newSchemaSet1']) } @@ -299,44 +345,45 @@ class ModuleServiceIntegrationSpec extends FunctionalSpecBase { U P G R A D E */ - def 'Upgrade schema set (with existing and new modules, no matching module set tag in NCMP)'() { + def 'Upgrade schema set [with existing and new modules, no matching module set tag in NCMP]'() { given: 'an anchor and schema set with 2 modules (to be upgraded)' - populateNewYangResourcesNameToContentMapAndAllModuleReferences('original', 2) - objectUnderTest.createSchemaSetFromModules(FUNCTIONAL_TEST_DATASPACE_1, 'targetSchema', newYangResourcesNameToContentMap, []) + populateYangResourceContentPerNameAndAllModuleReferences('original', 2) + objectUnderTest.createSchemaSetFromModules(FUNCTIONAL_TEST_DATASPACE_1, 'targetSchema', yangResourceContentPerName, allModuleReferences) cpsAnchorService.createAnchor(FUNCTIONAL_TEST_DATASPACE_1, 'targetSchema', 'targetAnchor') def yangResourceModuleReferencesBeforeUpgrade = objectUnderTest.getYangResourcesModuleReferences(FUNCTIONAL_TEST_DATASPACE_1, 'targetAnchor') assert yangResourceModuleReferencesBeforeUpgrade.size() == 2 assert yangResourceModuleReferencesBeforeUpgrade.containsAll([new ModuleReference('original_0','2000-01-01'),new ModuleReference('original_1','2001-01-01')]) and: 'two new 2 modules (from node)' - populateNewYangResourcesNameToContentMapAndAllModuleReferences('new', 2) + populateYangResourceContentPerNameAndAllModuleReferences('new', 2) def newModuleReferences = [new ModuleReference('new_0','2000-01-01'),new ModuleReference('new_1','2001-01-01')] and: 'a list of all module references (normally retrieved from node)' - def allModuleReferences = [] - allModuleReferences.add(bookStoreModuleReference) - allModuleReferences.addAll(newModuleReferences) + def allOtherModuleReferences = [] + allOtherModuleReferences.add(bookStoreModuleReference) + allOtherModuleReferences.addAll(newModuleReferences) when: 'the schema set is upgraded' - objectUnderTest.upgradeSchemaSetFromModules(FUNCTIONAL_TEST_DATASPACE_1, 'targetSchema', newYangResourcesNameToContentMap, allModuleReferences) + objectUnderTest.upgradeSchemaSetFromModules(FUNCTIONAL_TEST_DATASPACE_1, 'targetSchema', yangResourceContentPerName, allOtherModuleReferences) then: 'the new anchor has the correct new and existing modules' def yangResourceModuleReferencesAfterUpgrade = objectUnderTest.getYangResourcesModuleReferences(FUNCTIONAL_TEST_DATASPACE_1, 'targetAnchor') assert yangResourceModuleReferencesAfterUpgrade.size() == 3 assert yangResourceModuleReferencesAfterUpgrade.contains(bookStoreModuleReference) assert yangResourceModuleReferencesAfterUpgrade.containsAll(newModuleReferences); - cleanup: + cleanup: 'the data created in this test' objectUnderTest.deleteSchemaSetsWithCascade(FUNCTIONAL_TEST_DATASPACE_1, ['targetSchema']) } - def 'Upgrade existing schema set from another anchor (used in NCMP for matching module set tag)'() { + def 'Upgrade existing schema set from another anchor [used in NCMP for matching module set tag]'() { given: 'an anchor and schema set with 1 module (target)' - populateNewYangResourcesNameToContentMapAndAllModuleReferences('target', 1) - objectUnderTest.createSchemaSetFromModules(FUNCTIONAL_TEST_DATASPACE_1, 'targetSchema', newYangResourcesNameToContentMap, []) + populateYangResourceContentPerNameAndAllModuleReferences('target', 1) + objectUnderTest.createSchemaSetFromModules(FUNCTIONAL_TEST_DATASPACE_1, 'targetSchema', yangResourceContentPerName, allModuleReferences) cpsAnchorService.createAnchor(FUNCTIONAL_TEST_DATASPACE_1, 'targetSchema', 'targetAnchor') def moduleReferencesBeforeUpgrade = objectUnderTest.getYangResourcesModuleReferences(FUNCTIONAL_TEST_DATASPACE_1, 'targetAnchor') assert moduleReferencesBeforeUpgrade.size() == 1 and: 'another anchor and schema set with 2 other modules (source for upgrade)' - populateNewYangResourcesNameToContentMapAndAllModuleReferences('source', 2) - objectUnderTest.createSchemaSetFromModules(FUNCTIONAL_TEST_DATASPACE_1, 'sourceSchema', newYangResourcesNameToContentMap, []) + populateYangResourceContentPerNameAndAllModuleReferences('source', 2) + objectUnderTest.createSchemaSetFromModules(FUNCTIONAL_TEST_DATASPACE_1, 'sourceSchema', yangResourceContentPerName, allModuleReferences) cpsAnchorService.createAnchor(FUNCTIONAL_TEST_DATASPACE_1, 'sourceSchema', 'sourceAnchor') - assert objectUnderTest.getYangResourcesModuleReferences(FUNCTIONAL_TEST_DATASPACE_1, 'sourceAnchor').size() == 2 + def yangResourcesModuleReferences = objectUnderTest.getYangResourcesModuleReferences(FUNCTIONAL_TEST_DATASPACE_1, 'sourceAnchor') + assert yangResourcesModuleReferences.size() == 2 when: 'the target schema is upgraded using the module references from the source anchor' def moduleReferencesFromSourceAnchor = objectUnderTest.getYangResourcesModuleReferences(FUNCTIONAL_TEST_DATASPACE_1, 'sourceAnchor') objectUnderTest.upgradeSchemaSetFromModules(FUNCTIONAL_TEST_DATASPACE_1, 'targetSchema', noNewModules, moduleReferencesFromSourceAnchor) @@ -346,7 +393,7 @@ class ModuleServiceIntegrationSpec extends FunctionalSpecBase { and: 'the associated target anchor has the same module references (without namespace but that is a legacy issue)' def anchorModuleReferencesAfterUpgrade = objectUnderTest.getYangResourcesModuleReferences(FUNCTIONAL_TEST_DATASPACE_1, 'targetAnchor') assert anchorModuleReferencesAfterUpgrade.containsAll([new ModuleReference('source_0','2000-01-01'),new ModuleReference('source_1','2001-01-01')]); - cleanup: + cleanup: 'the data created in this test' objectUnderTest.deleteSchemaSetsWithCascade(FUNCTIONAL_TEST_DATASPACE_1, ['sourceSchema', 'targetSchema']) } @@ -354,17 +401,19 @@ class ModuleServiceIntegrationSpec extends FunctionalSpecBase { H E L P E R M E T H O D S */ - def populateNewYangResourcesNameToContentMapAndAllModuleReferences(numberOfModules) { - populateNewYangResourcesNameToContentMapAndAllModuleReferences('name', numberOfModules) + def populateYangResourceContentPerNameAndAllModuleReferences(numberOfModules) { + populateYangResourceContentPerNameAndAllModuleReferences('name', numberOfModules) } - def populateNewYangResourcesNameToContentMapAndAllModuleReferences(namePrefix, numberOfModules) { + def populateYangResourceContentPerNameAndAllModuleReferences(namePrefix, numberOfModules) { + yangResourceContentPerName.clear() + allModuleReferences.clear() numberOfModules.times { def uniqueName = namePrefix + '_' + it def uniqueRevision = String.valueOf(2000 + it) + '-01-01' - moduleReferences.add(new ModuleReference(uniqueName, uniqueRevision)) + allModuleReferences.add(new ModuleReference(uniqueName, uniqueRevision)) def uniqueContent = NEW_RESOURCE_CONTENT.replace(NEW_RESOURCE_REVISION, uniqueRevision).replace('module test_module', 'module '+uniqueName) - newYangResourcesNameToContentMap.put(uniqueRevision, uniqueContent) + yangResourceContentPerName.put(uniqueName, uniqueContent) } } diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/QueryServiceIntegrationSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/QueryServiceIntegrationSpec.groovy index e4d75aa378..42fb964d52 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/QueryServiceIntegrationSpec.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/QueryServiceIntegrationSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2023-2024 Nordix Foundation + * Copyright (C) 2023-2025 Nordix Foundation * Modifications Copyright (C) 2023-2025 TechMahindra Ltd * ================================================================================ * Licensed under the Apache License, Version 2.0 (the 'License'); @@ -27,7 +27,6 @@ import org.onap.cps.integration.base.FunctionalSpecBase import org.onap.cps.api.parameters.FetchDescendantsOption import org.onap.cps.api.parameters.PaginationOption import org.onap.cps.api.exceptions.CpsPathException -import spock.lang.Ignore import static org.onap.cps.api.parameters.FetchDescendantsOption.DIRECT_CHILDREN_ONLY import static org.onap.cps.api.parameters.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS @@ -57,7 +56,6 @@ class QueryServiceIntegrationSpec extends FunctionalSpecBase { 'the AND is used where result does not exist' | '//books[@lang="English" and @price=1000]' || 0 | [] } - @Ignore // TODO will be implemented in CPS-2416 def 'Query data leaf using CPS path for #scenario.'() { when: 'query data leaf for bookstore container' def result = objectUnderTest.queryDataLeaf(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, cpsPath, Object.class) @@ -70,7 +68,6 @@ class QueryServiceIntegrationSpec extends FunctionalSpecBase { 'non-existing path' | '/non-existing/@title' || 0 } - @Ignore def 'Query data leaf with type #leafType using CPS path.'() { given: 'a cps path query for two books, returning only #leafName' def cpsPath = '//books[@title="Matilda" or @title="Good Omens"]/@' + leafName @@ -85,7 +82,6 @@ class QueryServiceIntegrationSpec extends FunctionalSpecBase { 'editions' | List.class || [[1988, 2000], [2006]] } - @Ignore def 'Query data leaf using CPS path with ancestor axis.'() { given: 'a cps path query that will return the names of the categories of two books' def cpsPath = '//books[@title="Matilda" or @title="Good Omens"]/ancestor::categories/@name' @@ -461,4 +457,17 @@ class QueryServiceIntegrationSpec extends FunctionalSpecBase { and: 'the queried nodes have expected bookstore names' assert result.anchorName.toSet() == [BOOKSTORE_ANCHOR_1, BOOKSTORE_ANCHOR_2].toSet() } + + def 'Query with a limit of #limit.' () { + when: + def result = objectUnderTest.queryDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '/bookstore/categories', OMIT_DESCENDANTS, limit) + then: 'the expected number of nodes is returned' + assert countDataNodesInTree(result) == expectedNumberOfResults + where: 'the following parameters are used' + limit || expectedNumberOfResults + 1 || 1 + 2 || 2 + 0 || 5 + -1 || 5 + } } diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/AlternateIdSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/AlternateIdSpec.groovy index 222b3c0f6f..b1b777c79f 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/AlternateIdSpec.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/AlternateIdSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2024 Nordix Foundation + * Copyright (C) 2024-2025 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the 'License'); * you may not use this file except in compliance with the License. @@ -30,16 +30,13 @@ class AlternateIdSpec extends CpsIntegrationSpecBase { def setup() { dmiDispatcher1.moduleNamesPerCmHandleId['ch-1'] = ['M1', 'M2'] - registerCmHandle(DMI1_URL, 'ch-1', NO_MODULE_SET_TAG, 'alternateId') } - def cleanup() { - deregisterCmHandle(DMI1_URL, 'ch-1') - } - - def 'AlternateId in pass-through data operations should return OK status.'() { - given: 'the URL for the pass-through data request' - def url = '/ncmp/v1/ch/alternateId/data/ds/ncmp-datastore:passthrough-running' + def 'Pass-through data operations using #scenario as reference.'() { + given: 'a cm handle with an alternate id' + registerCmHandle(DMI1_URL, 'ch-1', NO_MODULE_SET_TAG, alternateId) + and: 'the URL for the pass-through data request' + def url = "/ncmp/v1/ch/${cmHandleReference}/data/ds/ncmp-datastore:passthrough-running" when: 'a pass-through data request is sent to NCMP' def response = mvc.perform(get(url) .queryParam('resourceIdentifier', 'my-resource-id') @@ -47,8 +44,13 @@ class AlternateIdSpec extends CpsIntegrationSpecBase { .andReturn().response then: 'response status is Ok' assert response.status == HttpStatus.OK.value() + cleanup: 'remove the test cm handle' + deregisterCmHandle(DMI1_URL, 'ch-1') + where: 'the following ids are used' + scenario | alternateId | cmHandleReference + 'standard id' | 'dont care' | 'ch-1' + 'alt-id with =' | 'alt=1' | 'alt=1' + 'alt-id without =' | 'alt-1' | 'alt-1' } - - } diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/CmHandleCreateSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/CmHandleCreateSpec.groovy index c4946b48b9..41798cb1f1 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/CmHandleCreateSpec.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/CmHandleCreateSpec.groovy @@ -20,6 +20,7 @@ package org.onap.cps.integration.functional.ncmp +import java.time.Duration import org.apache.kafka.clients.consumer.KafkaConsumer import org.apache.kafka.common.serialization.StringDeserializer import org.onap.cps.integration.KafkaTestContainer @@ -32,9 +33,6 @@ import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle import org.onap.cps.ncmp.events.lcm.v1.LcmEvent import org.onap.cps.ncmp.api.inventory.models.CmHandleState import org.onap.cps.ncmp.api.inventory.models.LockReasonCategory -import spock.util.concurrent.PollingConditions - -import java.time.Duration class CmHandleCreateSpec extends CpsIntegrationSpecBase { @@ -73,9 +71,7 @@ class CmHandleCreateSpec extends CpsIntegrationSpecBase { moduleSyncWatchdog.moduleSyncAdvisedCmHandles() then: 'CM-handle goes to READY state after module sync' - new PollingConditions().within(MODULE_SYNC_WAIT_TIME_IN_SECONDS, () -> { - assert CmHandleState.READY == objectUnderTest.getCmHandleCompositeState(uniqueId).cmHandleState - }) + assert CmHandleState.READY == objectUnderTest.getCmHandleCompositeState(uniqueId).cmHandleState and: 'the CM-handle has expected modules' assert ['M1', 'M2'] == objectUnderTest.getYangResourcesModuleReferences(uniqueId).moduleName.sort() @@ -113,11 +109,9 @@ class CmHandleCreateSpec extends CpsIntegrationSpecBase { moduleSyncWatchdog.moduleSyncAdvisedCmHandles() then: 'CM-handle goes to LOCKED state with reason MODULE_SYNC_FAILED' - new PollingConditions().within(MODULE_SYNC_WAIT_TIME_IN_SECONDS, () -> { - def cmHandleCompositeState = objectUnderTest.getCmHandleCompositeState('ch-1') - assert cmHandleCompositeState.cmHandleState == CmHandleState.LOCKED - assert cmHandleCompositeState.lockReason.lockReasonCategory == LockReasonCategory.MODULE_SYNC_FAILED - }) + def cmHandleCompositeState = objectUnderTest.getCmHandleCompositeState('ch-1') + assert cmHandleCompositeState.cmHandleState == CmHandleState.LOCKED + assert cmHandleCompositeState.lockReason.lockReasonCategory == LockReasonCategory.MODULE_SYNC_FAILED and: 'CM-handle has no modules' assert objectUnderTest.getYangResourcesModuleReferences('ch-1').empty @@ -141,9 +135,7 @@ class CmHandleCreateSpec extends CpsIntegrationSpecBase { moduleSyncWatchdog.moduleSyncAdvisedCmHandles() then: 'the CM-handle goes to READY state' - new PollingConditions().within(MODULE_SYNC_WAIT_TIME_IN_SECONDS, () -> { - assert CmHandleState.READY == objectUnderTest.getCmHandleCompositeState('ch-3').cmHandleState - }) + assert CmHandleState.READY == objectUnderTest.getCmHandleCompositeState('ch-3').cmHandleState and: 'the CM-handle has expected moduleSetTag' assert objectUnderTest.getNcmpServiceCmHandle('ch-3').moduleSetTag == 'B' @@ -200,9 +192,7 @@ class CmHandleCreateSpec extends CpsIntegrationSpecBase { moduleSyncWatchdog.moduleSyncAdvisedCmHandles() then: 'CM-handles go to LOCKED state' - new PollingConditions().within(MODULE_SYNC_WAIT_TIME_IN_SECONDS, () -> { - assert objectUnderTest.getCmHandleCompositeState('ch-1').cmHandleState == CmHandleState.LOCKED - }) + assert objectUnderTest.getCmHandleCompositeState('ch-1').cmHandleState == CmHandleState.LOCKED when: 'DMI is available for retry' dmiDispatcher1.moduleNamesPerCmHandleId = ['ch-1': ['M1', 'M2'], 'ch-2': ['M1', 'M2']] @@ -212,11 +202,9 @@ class CmHandleCreateSpec extends CpsIntegrationSpecBase { 2.times { moduleSyncWatchdog.moduleSyncAdvisedCmHandles() } then: 'Both CM-handles go to READY state' - new PollingConditions().within(MODULE_SYNC_WAIT_TIME_IN_SECONDS, () -> { - ['ch-1', 'ch-2'].each { cmHandleId -> - assert objectUnderTest.getCmHandleCompositeState(cmHandleId).cmHandleState == CmHandleState.READY - } - }) + ['ch-1', 'ch-2'].each { cmHandleId -> + assert objectUnderTest.getCmHandleCompositeState(cmHandleId).cmHandleState == CmHandleState.READY + } and: 'Both CM-handles have expected modules' ['ch-1', 'ch-2'].each { cmHandleId -> diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/CmHandleUpgradeSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/CmHandleUpgradeSpec.groovy index 097a043556..43540a9675 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/CmHandleUpgradeSpec.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/CmHandleUpgradeSpec.groovy @@ -27,7 +27,6 @@ import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistration import org.onap.cps.ncmp.api.inventory.models.LockReasonCategory import org.onap.cps.ncmp.api.inventory.models.UpgradedCmHandles import org.onap.cps.ncmp.impl.NetworkCmProxyInventoryFacadeImpl -import spock.util.concurrent.PollingConditions class CmHandleUpgradeSpec extends CpsIntegrationSpecBase { @@ -67,9 +66,7 @@ class CmHandleUpgradeSpec extends CpsIntegrationSpecBase { 2.times { moduleSyncWatchdog.moduleSyncAdvisedCmHandles() } then: 'CM-handle goes to READY state' - new PollingConditions().within(MODULE_SYNC_WAIT_TIME_IN_SECONDS, () -> { - assert CmHandleState.READY == objectUnderTest.getCmHandleCompositeState(cmHandleId).cmHandleState - }) + assert CmHandleState.READY == objectUnderTest.getCmHandleCompositeState(cmHandleId).cmHandleState and: 'the CM-handle has expected moduleSetTag' assert objectUnderTest.getNcmpServiceCmHandle(cmHandleId).moduleSetTag == updatedModuleSetTag @@ -111,9 +108,7 @@ class CmHandleUpgradeSpec extends CpsIntegrationSpecBase { 2.times { moduleSyncWatchdog.moduleSyncAdvisedCmHandles() } and: 'CM-handle goes to READY state' - new PollingConditions().within(MODULE_SYNC_WAIT_TIME_IN_SECONDS, () -> { - assert CmHandleState.READY == objectUnderTest.getCmHandleCompositeState(cmHandleId).cmHandleState - }) + assert CmHandleState.READY == objectUnderTest.getCmHandleCompositeState(cmHandleId).cmHandleState and: 'the CM-handle has expected moduleSetTag' assert objectUnderTest.getNcmpServiceCmHandle(cmHandleId).moduleSetTag == updatedModuleSetTag @@ -170,11 +165,9 @@ class CmHandleUpgradeSpec extends CpsIntegrationSpecBase { 2.times { moduleSyncWatchdog.moduleSyncAdvisedCmHandles() } then: 'CM-handle goes to LOCKED state with reason MODULE_UPGRADE_FAILED' - new PollingConditions().within(MODULE_SYNC_WAIT_TIME_IN_SECONDS, () -> { - def cmHandleCompositeState = objectUnderTest.getCmHandleCompositeState(cmHandleId) - assert cmHandleCompositeState.cmHandleState == CmHandleState.LOCKED - assert cmHandleCompositeState.lockReason.lockReasonCategory == LockReasonCategory.MODULE_UPGRADE_FAILED - }) + def cmHandleCompositeState = objectUnderTest.getCmHandleCompositeState(cmHandleId) + assert cmHandleCompositeState.cmHandleState == CmHandleState.LOCKED + assert cmHandleCompositeState.lockReason.lockReasonCategory == LockReasonCategory.MODULE_UPGRADE_FAILED and: 'the CM-handle has same moduleSetTag as before' assert objectUnderTest.getNcmpServiceCmHandle(cmHandleId).moduleSetTag == 'oldTag' diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/DataJobStatusServiceSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/DataJobStatusServiceSpec.groovy index 6e5c0e40c2..162b51844c 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/DataJobStatusServiceSpec.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/DataJobStatusServiceSpec.groovy @@ -18,6 +18,6 @@ class DataJobStatusServiceSpec extends CpsIntegrationSpecBase { when: 'the data job status checked' def result = dataJobStatusService.getDataJobStatus(authorization, dmiServiceName, dataProducerId, dataProducerJobId) then: 'the status is that defined in the mock service.' - assert result == 'status details from mock service' + assert result == '{"status":"status details from mock service"}' } } diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/ModuleSyncWatchdogIntegrationSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/ModuleSyncWatchdogIntegrationSpec.groovy index 81fbc3c4f7..8bbe0ca194 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/ModuleSyncWatchdogIntegrationSpec.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/ModuleSyncWatchdogIntegrationSpec.groovy @@ -101,7 +101,7 @@ class ModuleSyncWatchdogIntegrationSpec extends CpsIntegrationSpecBase { }) and: 'log the relevant instrumentation' def dmiModuleRetrievalTimer = meterRegistry.get('cps.ncmp.inventory.module.references.from.dmi').timer() - def dbSchemaSetStorageTimer = meterRegistry.get('cps.module.persistence.schemaset.store').timer() + def dbSchemaSetStorageTimer = meterRegistry.get('cps.module.persistence.schemaset.createFromNewAndExistingModules').timer() def dbStateUpdateTimer = meterRegistry.get('cps.ncmp.cmhandle.state.update.batch').timer() logInstrumentation(dmiModuleRetrievalTimer, 'get modules from DMI ') logInstrumentation(dbSchemaSetStorageTimer, 'store schema sets ') @@ -145,10 +145,8 @@ class ModuleSyncWatchdogIntegrationSpec extends CpsIntegrationSpecBase { when: 'advised cm handles are processed on 2 threads (exactly one batch for each)' objectUnderTest.moduleSyncAdvisedCmHandles() executorService.execute(moduleSyncAdvisedCmHandles) - then: 'wait till all cm handles have been processed' - new PollingConditions().within(10, () -> { - assert getNumberOfProcessedCmHandles() == 200 - }) + then: 'all cm handles have been processed' + assert getNumberOfProcessedCmHandles() == 200 then: 'at least 1 cm handle is in state LOCKED' assert cmHandlesByState.get('lockedCmHandlesCount') >= 1 cleanup: 'remove all test cm handles' diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/RestApiSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/RestApiSpec.groovy index 7ce3cf5e17..77349fe0a5 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/RestApiSpec.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/RestApiSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2024 Nordix Foundation + * Copyright (C) 2024-2025 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the 'License'); * you may not use this file except in compliance with the License. @@ -29,7 +29,6 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import org.onap.cps.integration.base.CpsIntegrationSpecBase import org.springframework.http.MediaType -import spock.util.concurrent.PollingConditions class RestApiSpec extends CpsIntegrationSpecBase { @@ -47,13 +46,11 @@ class RestApiSpec extends CpsIntegrationSpecBase { and: 'the module sync watchdog is triggered' moduleSyncWatchdog.moduleSyncAdvisedCmHandles() then: 'CM-handles go to READY state' - new PollingConditions().within(MODULE_SYNC_WAIT_TIME_IN_SECONDS, () -> { - (1..3).each { - mvc.perform(get('/ncmp/v1/ch/ch-'+it)) - .andExpect(status().isOk()) - .andExpect(jsonPath('$.state.cmHandleState').value('READY')) - } - }) + (1..3).each { + mvc.perform(get('/ncmp/v1/ch/ch-'+it)) + .andExpect(status().isOk()) + .andExpect(jsonPath('$.state.cmHandleState').value('READY')) + } } def 'Search for CM Handles by module using REST API.'() { diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/WriteSubJobSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/WriteSubJobSpec.groovy index 834e1399e3..46c641cd23 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/WriteSubJobSpec.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/WriteSubJobSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2024 Nordix Foundation + * Copyright (C) 2024-2025 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the 'License'); * you may not use this file except in compliance with the License. @@ -59,9 +59,9 @@ class WriteSubJobSpec extends CpsIntegrationSpecBase { then: 'each DMI received the expected sub-jobs and the response has the expected values' assert response.size() == 2 assert response[0].class == SubJobWriteResponse.class - assert response[0].subJobId == "some sub job id" - assert response[0].dmiServiceName == "some dmi service name" - assert response[0].dataProducerId == "some data producer id" + assert response[0].subJobId == 'some sub job id' + assert response[0].dmiServiceName.startsWith('http://localhost:') || response[0].dmiServiceName().startsWith('http://kubernetes') + assert response[0].dataProducerId == 'some data producer id' and: 'dmi 1 received the correct job details' def receivedSubJobsForDispatcher1 = dmiDispatcher1.receivedSubJobs['?destination=d1']['data'].collect() assert receivedSubJobsForDispatcher1.size() == 2 diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/CpsModuleServicePerfTest.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/CpsModuleServicePerfTest.groovy index a37bb6ad4d..d8553419ce 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/CpsModuleServicePerfTest.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/CpsModuleServicePerfTest.groovy @@ -47,15 +47,15 @@ class CpsModuleServicePerfTest extends CpsPerfTestBase { def 'Store new schema set with many modules'() { when: 'a new schema set with 200 modules is stored' - def newYangResourcesNameToContentMap = [:] + def newYangResourceContentPerName = [:] (1..200).each { def year = 2000 + it def resourceName = "module${it}".toString() def moduleName = "stores${it}" def content = NEW_RESOURCE_CONTENT.replace('2020',String.valueOf(year)).replace('stores',moduleName) - newYangResourcesNameToContentMap.put(resourceName, content) + newYangResourceContentPerName.put(resourceName, content) } - objectUnderTest.createSchemaSet(CPS_PERFORMANCE_TEST_DATASPACE, 'perfSchemaSet', newYangResourcesNameToContentMap) + objectUnderTest.createSchemaSet(CPS_PERFORMANCE_TEST_DATASPACE, 'perfSchemaSet', newYangResourceContentPerName) then: 'the schema set is persisted correctly' def result = cpsModuleService.getSchemaSet(CPS_PERFORMANCE_TEST_DATASPACE, 'perfSchemaSet') result.moduleReferences.size() == 200 diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/QueryPerfTest.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/QueryPerfTest.groovy index 364127f388..acc95cab8d 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/QueryPerfTest.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/QueryPerfTest.groovy @@ -103,5 +103,4 @@ class QueryPerfTest extends CpsPerfTestBase { 'direct descendants' | DIRECT_CHILDREN_ONLY || 0.11 | 8 | 1 + OPENROADM_DEVICES_PER_ANCHOR 'all descendants' | INCLUDE_ALL_DESCENDANTS || 1.34 | 400 | 1 + OPENROADM_DEVICES_PER_ANCHOR * OPENROADM_DATANODES_PER_DEVICE } - } diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/AlternateIdPerfTest.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/AlternateIdPerfTest.groovy new file mode 100644 index 0000000000..b9d57cf14d --- /dev/null +++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/AlternateIdPerfTest.groovy @@ -0,0 +1,47 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2025 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.integration.performance.ncmp + +import org.onap.cps.integration.ResourceMeter +import org.onap.cps.integration.base.CpsIntegrationSpecBase + +/** + * This test does not depend on common performance test data. Hence it just extends the integration spec base. + */ +class AlternateIdPerfTest extends CpsIntegrationSpecBase { + + def resourceMeter = new ResourceMeter() + + def 'Alternate Id Lookup Performance.'() { + given: 'register 1,000 cm handles (with alternative ids)' + registerSequenceOfCmHandlesWithManyModuleReferencesButDoNotWaitForReady(DMI1_URL, 'tagA', 1000, 1) + when: 'perform a 1,000 lookups by alternate id' + resourceMeter.start() + (1..1000).each { + networkCmProxyInventoryFacade.getNcmpServiceCmHandle("alt=${it}") + } + resourceMeter.stop() + then: 'record the result. Not asserted, just recorded in See https://lf-onap.atlassian.net/browse/CPS-2605' + println "*** CPS-2605 Execution time: ${resourceMeter.totalTimeInSeconds} ms" + cleanup: 'deregister test cm handles' + deregisterSequenceOfCmHandles(DMI1_URL, 1000, 1) + } +} diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmHandleQueryPerfTest.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmHandleQueryPerfTest.groovy index 5389732181..dbf7e71710 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmHandleQueryPerfTest.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmHandleQueryPerfTest.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2023-2024 Nordix Foundation + * Copyright (C) 2023-2025 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the 'License'); * you may not use this file except in compliance with the License. @@ -46,7 +46,7 @@ class CmHandleQueryPerfTest extends NcmpPerfTestBase { cpsDataService.getDataNodes(NCMP_PERFORMANCE_TEST_DATASPACE, REGISTRY_ANCHOR, '/dmi-registry/cm-handles[@id="cm-' + it + '"]', OMIT_DESCENDANTS) objectUnderTest.queryDataNodes(NCMP_PERFORMANCE_TEST_DATASPACE, REGISTRY_ANCHOR, - '/dmi-registry/cm-handles[@alternate-id="alt-' + it + '"]', OMIT_DESCENDANTS) + '/dmi-registry/cm-handles[@alternate-id="alt=' + it + '"]', OMIT_DESCENDANTS) } resourceMeter.stop() then: 'resource usage is as expected' @@ -100,7 +100,7 @@ class CmHandleQueryPerfTest extends NcmpPerfTestBase { resourceMeter.start() (1..100).each { count += cpsQueryService.queryDataNodes(NCMP_PERFORMANCE_TEST_DATASPACE, REGISTRY_ANCHOR, - '/dmi-registry/cm-handles[@alternate-id="alt-' + it + '"]', OMIT_DESCENDANTS).size() + '/dmi-registry/cm-handles[@alternate-id="alt=' + it + '"]', OMIT_DESCENDANTS).size() } resourceMeter.stop() then: @@ -116,7 +116,7 @@ class CmHandleQueryPerfTest extends NcmpPerfTestBase { def 'A batch of CM-handles is looked up by alternate-id.'() { given: 'a CPS Path Query to look up 100 alternate-ids in a single operation' - def cpsPathQuery = '/dmi-registry/cm-handles[' + (1..100).collect { "@alternate-id='alt-${it}'" }.join(' or ') + ']' + def cpsPathQuery = '/dmi-registry/cm-handles[' + (1..100).collect { "@alternate-id='alt=${it}'" }.join(' or ') + ']' when: 'CM-handles are looked up by alternate-ids in a single query' resourceMeter.start() def count = cpsQueryService.queryDataNodes(NCMP_PERFORMANCE_TEST_DATASPACE, REGISTRY_ANCHOR, cpsPathQuery, OMIT_DESCENDANTS).size() diff --git a/integration-test/src/test/java/org/onap/cps/integration/KafkaTestContainer.java b/integration-test/src/test/java/org/onap/cps/integration/KafkaTestContainer.java index ff4aec4175..60c1637c5a 100644 --- a/integration-test/src/test/java/org/onap/cps/integration/KafkaTestContainer.java +++ b/integration-test/src/test/java/org/onap/cps/integration/KafkaTestContainer.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2024 Nordix Foundation. + * Copyright (C) 2024-2025 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,8 +25,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.kafka.clients.consumer.ConsumerConfig; import org.apache.kafka.clients.consumer.KafkaConsumer; import org.apache.kafka.common.serialization.StringDeserializer; -import org.testcontainers.containers.KafkaContainer; -import org.testcontainers.utility.DockerImageName; +import org.testcontainers.kafka.ConfluentKafkaContainer; /** * The Apache Kafka test container wrapper. @@ -35,14 +34,14 @@ import org.testcontainers.utility.DockerImageName; * Avoid unnecessary resource and time consumption. */ @Slf4j -public class KafkaTestContainer extends KafkaContainer { +public class KafkaTestContainer extends ConfluentKafkaContainer { - private static final String IMAGE_NAME_AND_VERSION = "registry.nordix.org/onaptest/confluentinc/cp-kafka:6.2.1"; + private static final String IMAGE_NAME_AND_VERSION = "confluentinc/cp-kafka:7.8.0"; private static volatile KafkaTestContainer kafkaTestContainer; private KafkaTestContainer() { - super(DockerImageName.parse(IMAGE_NAME_AND_VERSION).asCompatibleSubstituteFor("confluentinc/cp-kafka")); + super(IMAGE_NAME_AND_VERSION); } /** diff --git a/integration-test/src/test/resources/application.yml b/integration-test/src/test/resources/application.yml index 30598dfb90..e213a70a59 100644 --- a/integration-test/src/test/resources/application.yml +++ b/integration-test/src/test/resources/application.yml @@ -102,6 +102,7 @@ app: cm-subscription-dmi-out: ${CM_SUBSCRIPTION_DMI_OUT_TOPIC:dmi-ncmp-cm-avc-subscription} cm-subscription-ncmp-out: ${CM_SUBSCRIPTION_NCMP_OUT_TOPIC:subscription-response} cm-events-topic: ${NCMP_CM_EVENTS_TOPIC:cm-events} + inventory-events-topic: ncmp-inventory-events lcm: events: topic: ${LCM_EVENTS_TOPIC:ncmp-events} @@ -189,10 +190,6 @@ ncmp: trust-level: dmi-availability-watchdog-ms: 30000 - modules-sync-watchdog: - async-executor: - parallelism-level: 2 - model-loader: maximum-attempt-count: 20 diff --git a/integration-test/src/test/resources/hibernate.cfg.xml b/integration-test/src/test/resources/hibernate.cfg.xml deleted file mode 100644 index 8d5139b605..0000000000 --- a/integration-test/src/test/resources/hibernate.cfg.xml +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE hibernate-configuration PUBLIC - "-//Hibernate/Hibernate Configuration DTD 3.0//EN" - "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> - -<hibernate-configuration> - <session-factory> - <property name="hibernate.connection.driver_class">org.postgresql.Driver</property> - <property name="hibernate.connection.url">${DB_URL}</property> - <property name="hibernate.connection.username">${DB_USERNAME}</property> - <property name="hibernate.connection.password">${DB_PASSWORD}</property> - <property name="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</property> - <property name="show_sql">true</property> - <property name="hibernate.hbm2ddl.auto">none</property> - </session-factory> -</hibernate-configuration>
\ No newline at end of file |