diff options
Diffstat (limited to 'cps-ncmp-service/src/test/groovy/org')
11 files changed, 382 insertions, 133 deletions
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceSpec.groovy new file mode 100644 index 0000000000..a1ad9af191 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandlerQueryServiceSpec.groovy @@ -0,0 +1,149 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2022 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.ncmp.api.impl + +import com.fasterxml.jackson.databind.ObjectMapper +import org.onap.cps.ncmp.api.NetworkCmProxyCmHandlerQueryService +import org.onap.cps.spi.CpsAdminPersistenceService +import org.onap.cps.spi.CpsDataPersistenceService +import org.onap.cps.spi.model.Anchor +import org.onap.cps.spi.model.CmHandleQueryParameters +import org.onap.cps.spi.model.ConditionProperties +import org.onap.cps.spi.model.DataNode +import org.onap.cps.utils.JsonObjectMapper +import spock.lang.Specification + +import java.util.stream.Collectors + +class NetworkCmProxyCmHandlerQueryServiceSpec extends Specification { + + def cpsDataPersistenceService = Mock(CpsDataPersistenceService) + def cpsAdminPersistenceService = Mock(CpsAdminPersistenceService) + + NetworkCmProxyCmHandlerQueryService objectUnderTest = new NetworkCmProxyCmHandlerQueryServiceImpl( + cpsDataPersistenceService, cpsAdminPersistenceService, new JsonObjectMapper(new ObjectMapper()) + ) + + def 'Retrieve cm handles with public properties when #scenario.'() { + given: 'a condition property' + def cmHandleQueryParameters = new CmHandleQueryParameters() + def conditionProperties = new ConditionProperties() + conditionProperties.conditionName = 'hasAllProperties' + conditionProperties.conditionParameters = publicProperties + cmHandleQueryParameters.setCmHandleQueryParameters([conditionProperties]) + and: 'mock services' + mockResponses() + when: 'the service is invoked' + def returnedCmHandles = objectUnderTest.queryCmHandles(cmHandleQueryParameters) + then: 'the correct expected cm handles are returned' + returnedCmHandles.stream().map(d -> d.leaves.get('id').toString()).collect(Collectors.toList()) == expectedCmHandleIds + where: 'the following data is used' + scenario | publicProperties || expectedCmHandleIds + 'single matching property' | [['Contact' : 'newemailforstore@bookstore.com']] || ['PNFDemo', 'PNFDemo2', 'PNFDemo4'] + 'public property dont match' | [['wont_match' : 'wont_match']] || [] + '2 properties, only one match (and)' | [['Contact' : 'newemailforstore@bookstore.com'], ['Contact2': 'newemailforstore2@bookstore.com']] || ['PNFDemo4'] + '2 properties, no match (and)' | [['Contact' : 'newemailforstore@bookstore.com'], ['Contact2': '']] || [] + } + + def 'Retrieve cm handles with module names when #scenario.'() { + given: 'a condition property' + def cmHandleQueryParameters = new CmHandleQueryParameters() + def conditionProperties = new ConditionProperties() + conditionProperties.conditionName = 'hasAllModules' + conditionProperties.conditionParameters = moduleNames + cmHandleQueryParameters.setCmHandleQueryParameters([conditionProperties]) + and: 'mock services' + mockResponses() + when: 'the service is invoked' + def returnedCmHandles = objectUnderTest.queryCmHandles(cmHandleQueryParameters) + then: 'the correct expected cm handles are returned' + returnedCmHandles.stream().map(d -> d.leaves.get('id').toString()).collect(Collectors.toList()) == expectedCmHandleIds + where: 'the following data is used' + scenario | moduleNames || expectedCmHandleIds + 'single matching module name' | [['moduleName' : 'MODULE-NAME-001']] || ['PNFDemo2', 'PNFDemo3', 'PNFDemo'] + 'module name dont match' | [['moduleName' : 'MODULE-NAME-004']] || [] + '2 module names, only one match (and)' | [['moduleName' : 'MODULE-NAME-002'], ['moduleName': 'MODULE-NAME-003']] || ['PNFDemo4'] + '2 module names, no match (and)' | [['moduleName' : 'MODULE-NAME-002'], ['moduleName': 'MODULE-NAME-004']] || [] + } + + def 'Retrieve cm handles with combined queries when #scenario.'() { + given: 'condition properties' + def cmHandleQueryParameters = new CmHandleQueryParameters() + def conditionProperties1 = new ConditionProperties() + conditionProperties1.conditionName = 'hasAllProperties' + conditionProperties1.conditionParameters = publicProperties + def conditionProperties2 = new ConditionProperties() + conditionProperties2.conditionName = 'hasAllModules' + conditionProperties2.conditionParameters = moduleNames + cmHandleQueryParameters.setCmHandleQueryParameters([conditionProperties1,conditionProperties2]) + and: 'mock services' + mockResponses() + when: 'the service is invoked' + def returnedCmHandles = objectUnderTest.queryCmHandles(cmHandleQueryParameters) + then: 'the correct expected cm handles are returned' + returnedCmHandles.stream().map(d -> d.leaves.get('id').toString()).collect(Collectors.toList()) == expectedCmHandleIds + where: 'the following data is used' + scenario | moduleNames | publicProperties || expectedCmHandleIds + 'particularly intersect' | [['moduleName' : 'MODULE-NAME-001']] | [['Contact' : 'newemailforstore@bookstore.com']] || ['PNFDemo2', 'PNFDemo'] + 'empty intersect' | [['moduleName' : 'MODULE-NAME-004']] | [['Contact' : 'newemailforstore@bookstore.com']] || [] + 'total intersect' | [['moduleName' : 'MODULE-NAME-002']] | [['Contact2' : 'newemailforstore2@bookstore.com']] || ['PNFDemo4'] + } + + def 'Retrieve cm handles when the query is empty.'() { + given: 'mock services' + mockResponses() + when: 'the service is invoked' + def cmHandleQueryParameters = new CmHandleQueryParameters() + def returnedCmHandles = objectUnderTest.queryCmHandles(cmHandleQueryParameters) + then: 'the correct expected cm handles are returned' + returnedCmHandles.stream().map(d -> d.leaves.get('id').toString()).collect(Collectors.toList()) == ['PNFDemo', 'PNFDemo2', 'PNFDemo3', 'PNFDemo4'] + } + + void mockResponses() { + def pNFDemo = new DataNode(xpath: 'cmHandle/id[\'PNFDemo\']', leaves: ['id':'PNFDemo']) + def pNFDemo2 = new DataNode(xpath: 'cmHandle/id[\'PNFDemo2\']', leaves: ['id':'PNFDemo2']) + def pNFDemo3 = new DataNode(xpath: 'cmHandle/id[\'PNFDemo3\']', leaves: ['id':'PNFDemo3']) + def pNFDemo4 = new DataNode(xpath: 'cmHandle/id[\'PNFDemo4\']', leaves: ['id':'PNFDemo4']) + + cpsDataPersistenceService.queryDataNodes(_, _, '//public-properties[@name=\'Contact\' and @value=\'newemailforstore@bookstore.com\']/ancestor::cm-handles', _) + >> [pNFDemo, pNFDemo2, pNFDemo4] + cpsDataPersistenceService.queryDataNodes(_, _, '//public-properties[@name=\'wont_match\' and @value=\'wont_match\']/ancestor::cm-handles', _) + >> [] + cpsDataPersistenceService.queryDataNodes(_, _, '//public-properties[@name=\'Contact2\' and @value=\'newemailforstore2@bookstore.com\']/ancestor::cm-handles', _) + >> [pNFDemo4] + cpsDataPersistenceService.queryDataNodes(_, _, '//public-properties[@name=\'Contact2\' and @value=\'\']/ancestor::cm-handles', _) + >> [] + cpsDataPersistenceService.queryDataNodes(_, _, '//public-properties/ancestor::cm-handles', _) + >> [pNFDemo, pNFDemo2, pNFDemo3, pNFDemo4] + cpsDataPersistenceService.queryDataNodes(_, _, '//cm-handles[@id=\'PNFDemo\']', _) >> [pNFDemo] + cpsDataPersistenceService.queryDataNodes(_, _, '//cm-handles[@id=\'PNFDemo2\']', _) >> [pNFDemo2] + cpsDataPersistenceService.queryDataNodes(_, _, '//cm-handles[@id=\'PNFDemo3\']', _) >> [pNFDemo3] + cpsDataPersistenceService.queryDataNodes(_, _, '//cm-handles[@id=\'PNFDemo4\']', _) >> [pNFDemo4] + + cpsAdminPersistenceService.queryAnchors(_, ['MODULE-NAME-001']) >> [new Anchor(name: 'PNFDemo2'), new Anchor(name: 'PNFDemo3'), new Anchor(name: 'PNFDemo')] + cpsAdminPersistenceService.queryAnchors(_, ['MODULE-NAME-004']) >> [] + cpsAdminPersistenceService.queryAnchors(_, ['MODULE-NAME-003', 'MODULE-NAME-002']) >> [new Anchor(name: 'PNFDemo4')] + cpsAdminPersistenceService.queryAnchors(_, ['MODULE-NAME-002', 'MODULE-NAME-003']) >> [new Anchor(name: 'PNFDemo4')] + cpsAdminPersistenceService.queryAnchors(_, ['MODULE-NAME-004', 'MODULE-NAME-002']) >> [] + cpsAdminPersistenceService.queryAnchors(_, ['MODULE-NAME-002', 'MODULE-NAME-004']) >> [] + cpsAdminPersistenceService.queryAnchors(_, ['MODULE-NAME-002']) >> [new Anchor(name: 'PNFDemo2'), new Anchor(name: 'PNFDemo4')] + } +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy index f56aea7f33..e9d02dfc72 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy @@ -22,6 +22,7 @@ package org.onap.cps.ncmp.api.impl import com.fasterxml.jackson.databind.ObjectMapper +import org.onap.cps.ncmp.api.NetworkCmProxyCmHandlerQueryService import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle import org.onap.cps.api.CpsAdminService import org.onap.cps.api.CpsDataService @@ -64,9 +65,10 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { def mockNetworkCmProxyDataServicePropertyHandler = Mock(NetworkCmProxyDataServicePropertyHandler) def mockInventoryPersistence = Mock(InventoryPersistence) def mockModuleSyncService = Mock(ModuleSyncService) + def stubbedNetworkCmProxyCmHandlerQueryService = Stub(NetworkCmProxyCmHandlerQueryService) def noTimestamp = null - def objectUnderTest = getObjectUnderTestWithModelSyncDisabled() + def objectUnderTest = getObjectUnderTest() def 'DMI Registration: Create, Update & Delete operations are processed in the right order'() { given: 'a registration with operations of all three types' @@ -164,20 +166,10 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { } and: 'save list elements is invoked with the expected parameters' interaction { - def expectedJsonData = """{"cm-handles":[{"id":"cmhandle","dmi-service-name":"my-server","additional-properties":$expectedDmiProperties,"public-properties":$expectedPublicProperties}]}""" + def expectedJsonData = """{"cm-handles":[{"id":"cmhandle","dmi-service-name":"my-server","state":{"cm-handle-state":"ADVISED"},"additional-properties":$expectedDmiProperties,"public-properties":$expectedPublicProperties}]}""" 1 * mockCpsDataService.saveListElements('NCMP-Admin', 'ncmp-dmi-registry', '/dmi-registry', expectedJsonData, noTimestamp) } - then: 'model sync is invoked with expected parameters' - 1 * objectUnderTest.syncModulesAndCreateAnchor(_) >> { YangModelCmHandle yangModelCmHandle -> - { - assert yangModelCmHandle.id == 'cmhandle' - assert yangModelCmHandle.dmiServiceName == 'my-server' - assert spiedJsonObjectMapper.asJsonString(yangModelCmHandle.getPublicProperties()) == expectedPublicProperties - assert spiedJsonObjectMapper.asJsonString(yangModelCmHandle.getDmiProperties()) == expectedDmiProperties - - } - } where: scenario | dmiProperties | publicProperties || expectedDmiProperties | expectedPublicProperties 'with dmi & public properties' | ['dmi-key': 'dmi-value'] | ['public-key': 'public-value'] || '[{"name":"dmi-key","value":"dmi-value"}]' | '[{"name":"public-key","value":"public-value"}]' @@ -233,8 +225,6 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { assert it.registrationError == expectedError assert it.errorText == expectedErrorText } - and: 'model-sync is not invoked' - 0 * objectUnderTest.syncModulesAndCreateAnchor(_) where: scenario | cmHandleId | exception || expectedError | expectedErrorText 'cm-handle already exist' | 'cmhandle' | new AlreadyDefinedException('', new RuntimeException()) || CM_HANDLE_ALREADY_EXIST | 'cm-handle already exists' @@ -242,28 +232,6 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { 'unknown exception while registering cm-handle' | 'cmhandle' | new RuntimeException('Failed') || UNKNOWN_ERROR | 'Failed' } - def 'Create CM-Handle Error Handling: Model Sync fails'() { - given: 'objects under test without disabled model sync' - def objectUnderTest = getObjectUnderTest() - and: 'a registration without cm-handle properties' - def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: 'my-server') - dmiPluginRegistration.createdCmHandles = [new NcmpServiceCmHandle(cmHandleId: 'cmhandle')] - and: 'cm-handler models sync fails' - objectUnderTest.syncModulesAndCreateAnchor(*_) >> { throw new RuntimeException('Model-Sync failed') } - when: 'registration is updated' - def response = objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration) - then: 'a failure response is received' - response.getCreatedCmHandles().size() == 1 - with(response.getCreatedCmHandles().get(0)) { - assert it.status == Status.FAILURE - assert it.cmHandle == 'cmhandle' - assert it.registrationError == UNKNOWN_ERROR - assert it.errorText == 'Model-Sync failed' - } - and: 'cm-handle is registered' - 1 * mockCpsDataService.saveListElements(*_) - } - def 'Update CM-Handle: Update Operation Response is added to the response'() { given: 'a registration to update CmHandles' def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: 'my-server', @@ -379,14 +347,9 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { 'an unexpected exception' | 'cmhandle' | new RuntimeException("Failed") || UNKNOWN_ERROR | 'Failed' } - def getObjectUnderTestWithModelSyncDisabled() { - def objectUnderTest = getObjectUnderTest() - objectUnderTest.syncModulesAndCreateAnchor(*_) >> null - return objectUnderTest - } - def getObjectUnderTest() { return Spy(new NetworkCmProxyDataServiceImpl(mockCpsDataService, spiedJsonObjectMapper, mockDmiDataOperations, - mockCpsModuleService, mockCpsAdminService, mockNetworkCmProxyDataServicePropertyHandler, mockInventoryPersistence, mockModuleSyncService)) + mockCpsModuleService, mockCpsAdminService, mockNetworkCmProxyDataServicePropertyHandler, mockInventoryPersistence, + mockModuleSyncService, stubbedNetworkCmProxyCmHandlerQueryService)) } } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy index 55a1a8d1fa..6ba2a2c276 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy @@ -22,15 +22,19 @@ package org.onap.cps.ncmp.api.impl -import org.onap.cps.ncmp.api.impl.exception.HttpClientRequestException +import org.onap.cps.ncmp.api.NetworkCmProxyCmHandlerQueryService import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle import org.onap.cps.ncmp.api.inventory.CmHandleState import org.onap.cps.ncmp.api.inventory.CompositeState import org.onap.cps.ncmp.api.inventory.InventoryPersistence +import org.onap.cps.ncmp.api.models.CmHandleQueryApiParameters +import org.onap.cps.ncmp.api.models.ConditionApiProperties import org.onap.cps.ncmp.api.models.DmiPluginRegistration import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle import org.onap.cps.spi.exceptions.DataValidationException import org.onap.cps.ncmp.api.inventory.sync.ModuleSyncService +import org.onap.cps.spi.model.CmHandleQueryParameters +import org.onap.cps.spi.model.ConditionProperties import spock.lang.Shared import static org.onap.cps.ncmp.api.impl.operations.DmiOperations.DataStoreEnum.PASSTHROUGH_OPERATIONAL @@ -61,6 +65,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { def mockInventoryPersistence = Mock(InventoryPersistence) def mockModuleSyncService = Mock(ModuleSyncService) def mockDmiPluginRegistration = Mock(DmiPluginRegistration) + def mockCpsCmHandlerQueryService = Mock(NetworkCmProxyCmHandlerQueryService) def NO_TOPIC = null def NO_REQUEST_ID = null @@ -70,7 +75,8 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: 'some-cm-handle-id') def objectUnderTest = new NetworkCmProxyDataServiceImpl(mockCpsDataService, spiedJsonObjectMapper, mockDmiDataOperations, - mockCpsModuleService, mockCpsAdminService, nullNetworkCmProxyDataServicePropertyHandler, mockInventoryPersistence, mockModuleSyncService) + mockCpsModuleService, mockCpsAdminService, nullNetworkCmProxyDataServicePropertyHandler, mockInventoryPersistence, + mockModuleSyncService, mockCpsCmHandlerQueryService) def cmHandleXPath = "/dmi-registry/cm-handles[@id='testCmHandle']" @@ -160,13 +166,6 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { 0 * mockCpsModuleService.getYangResourcesModuleReferences(*_) } - def 'Get cm handle identifiers for the given module names.'() { - when: 'execute a cm handle search for the given module names' - objectUnderTest.executeCmHandleHasAllModulesSearch(['some-module-name']) - then: 'get anchor identifiers is invoked with the expected parameters' - 1 * mockCpsAdminService.queryAnchorNames('NFP-Operational', ['some-module-name']) - } - def 'Get a cm handle.'() { given: 'the system returns a yang modelled cm handle' def dmiServiceName = 'some service name' @@ -241,8 +240,28 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { then: 'validate params for creating anchor and list elements' 1 * mockCpsDataService.saveListElements('NCMP-Admin', 'ncmp-dmi-registry', '/dmi-registry', '{"cm-handles":[{"id":"some-cm-handle-id",' + - '"additional-properties":[],"public-properties":[]}]}', null) - 1 * mockCpsAdminService.createAnchor('NFP-Operational', null, - 'some-cm-handle-id') + '"state":{"cm-handle-state":"ADVISED"},' + + '"additional-properties":[],"public-properties":[]}]}', null) + } + + def 'Execute cm handle id search'() { + given: 'valid CmHandleQueryApiParameters input' + def cmHandleQueryApiParameters = new CmHandleQueryApiParameters() + def conditionApiProperties = new ConditionApiProperties() + conditionApiProperties.conditionName = 'hasAllModules' + conditionApiProperties.conditionParameters = [[moduleName: 'module-name-1']] + cmHandleQueryApiParameters.cmHandleQueryParameters = [conditionApiProperties] + and: 'valid CmHandleQueryParameters input' + def cmHandleQueryParameters = new CmHandleQueryParameters() + def conditionProperties = new ConditionProperties() + conditionProperties.conditionName = 'hasAllModules' + conditionProperties.conditionParameters = [[moduleName: 'module-name-1']] + cmHandleQueryParameters.cmHandleQueryParameters = [conditionProperties] + and: 'query cm handle method return with a data node list' + mockCpsCmHandlerQueryService.queryCmHandles(cmHandleQueryParameters) >> [new DataNode(leaves: [id: 'cm-handle-id-1'])] + when: 'execute cm handle search is called' + def result = objectUnderTest.executeCmHandleIdSearch(cmHandleQueryApiParameters) + then: 'result is the same collection as returned by the CPS Data Service' + assert result == ['cm-handle-id-1'] as Set } } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/CpsAsyncRequestResponseEventIntegrationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/CpsAsyncRequestResponseEventIntegrationSpec.groovy index aa6bf1a783..31f179ab27 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/CpsAsyncRequestResponseEventIntegrationSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/CpsAsyncRequestResponseEventIntegrationSpec.groovy @@ -20,68 +20,26 @@ package org.onap.cps.ncmp.api.impl.async -import org.apache.kafka.clients.consumer.ConsumerConfig -import org.apache.kafka.clients.producer.ProducerConfig -import org.apache.kafka.common.serialization.StringSerializer +import com.fasterxml.jackson.databind.ObjectMapper +import org.apache.kafka.clients.consumer.KafkaConsumer import org.mapstruct.factory.Mappers +import org.onap.cps.ncmp.api.utils.MessagingSpec import org.onap.cps.ncmp.event.model.DmiAsyncRequestResponseEvent import org.onap.cps.ncmp.event.model.NcmpAsyncRequestResponseEvent -import org.springframework.kafka.core.DefaultKafkaProducerFactory -import org.springframework.kafka.core.KafkaTemplate -import org.springframework.kafka.support.serializer.JsonSerializer -import org.testcontainers.containers.KafkaContainer -import org.testcontainers.spock.Testcontainers -import org.testcontainers.utility.DockerImageName - -import java.time.Duration -import com.fasterxml.jackson.databind.ObjectMapper +import org.onap.cps.ncmp.utils.TestUtils import org.onap.cps.utils.JsonObjectMapper -import org.apache.kafka.clients.consumer.KafkaConsumer -import org.apache.kafka.common.serialization.StringDeserializer -import org.onap.cps.ncmp.utils.TestUtils; -import org.springframework.boot.test.context.SpringBootTest import org.spockframework.spring.SpringBean +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest import org.springframework.test.annotation.DirtiesContext -import org.springframework.test.context.DynamicPropertyRegistry -import org.springframework.test.context.DynamicPropertySource -import spock.lang.Specification +import org.testcontainers.spock.Testcontainers + +import java.time.Duration -@SpringBootTest(classes = [NcmpAsyncRequestResponseEventProducer, NcmpAsyncRequestResponseEventConsumer]) +@SpringBootTest(classes = [NcmpAsyncRequestResponseEventProducer, NcmpAsyncRequestResponseEventConsumer, ObjectMapper, JsonObjectMapper]) @Testcontainers @DirtiesContext -class NcmpAsyncRequestResponseEventProducerIntegrationSpec extends Specification { - - static kafkaTestContainer = new KafkaContainer( - DockerImageName.parse('confluentinc/cp-kafka:6.2.1') - ) - - static { - Runtime.getRuntime().addShutdownHook(new Thread(kafkaTestContainer::stop)) - } - - def setupSpec() { - kafkaTestContainer.start() - } - - def producerConfigProperties = [ - (ProducerConfig.BOOTSTRAP_SERVERS_CONFIG) : kafkaTestContainer.getBootstrapServers().split(',')[0], - (ProducerConfig.RETRIES_CONFIG) : 0, - (ProducerConfig.BATCH_SIZE_CONFIG) : 16384, - (ProducerConfig.LINGER_MS_CONFIG) : 1, - (ProducerConfig.BUFFER_MEMORY_CONFIG) : 33554432, - (ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG) : StringSerializer, - (ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG) : JsonSerializer - ] - - def consumerConfigProperties = [ - (ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG) : kafkaTestContainer.getBootstrapServers().split(',')[0], - (ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG) : StringDeserializer, - (ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG): StringDeserializer, - (ConsumerConfig.AUTO_OFFSET_RESET_CONFIG) : 'earliest', - (ConsumerConfig.GROUP_ID_CONFIG) : 'test' - ] - - def kafkaTemplate = new KafkaTemplate<>(new DefaultKafkaProducerFactory<Integer, String>(producerConfigProperties)) +class NcmpAsyncRequestResponseEventProducerIntegrationSpec extends MessagingSpec { @SpringBean NcmpAsyncRequestResponseEventProducer cpsAsyncRequestResponseEventProducerService = @@ -96,9 +54,10 @@ class NcmpAsyncRequestResponseEventProducerIntegrationSpec extends Specification new NcmpAsyncRequestResponseEventConsumer(cpsAsyncRequestResponseEventProducerService, ncmpAsyncRequestResponseEventMapper) - def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper()) + @Autowired + JsonObjectMapper jsonObjectMapper - def kafkaConsumer = new KafkaConsumer<>(getConsumerConfigProperties()) + def kafkaConsumer = new KafkaConsumer<>(consumerConfigProperties('test')) def 'Consume and forward valid message'() { given: 'consumer has a subscription' @@ -118,9 +77,4 @@ class NcmpAsyncRequestResponseEventProducerIntegrationSpec extends Specification NcmpAsyncRequestResponseEvent).getForwardedEvent().getEventId()) } - @DynamicPropertySource - static void registerKafkaProperties(DynamicPropertyRegistry dynamicPropertyRegistry) { - dynamicPropertyRegistry.add('spring.kafka.bootstrap-servers', kafkaTestContainer::getBootstrapServers) - } - } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/NcmpEventsPublisherSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/NcmpEventsPublisherSpec.groovy new file mode 100644 index 0000000000..774a46558b --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/NcmpEventsPublisherSpec.groovy @@ -0,0 +1,84 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2022 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.ncmp.api.impl.event + +import com.fasterxml.jackson.databind.ObjectMapper +import org.apache.kafka.clients.consumer.KafkaConsumer +import org.onap.cps.ncmp.api.utils.MessagingSpec +import org.onap.cps.ncmp.utils.TestUtils +import org.onap.cps.utils.JsonObjectMapper +import org.onap.ncmp.cmhandle.lcm.event.Event +import org.onap.ncmp.cmhandle.lcm.event.NcmpEvent +import org.spockframework.spring.SpringBean +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.test.annotation.DirtiesContext +import org.testcontainers.spock.Testcontainers + +import java.time.Duration + +@SpringBootTest(classes = [NcmpEventsPublisher, ObjectMapper, JsonObjectMapper]) +@Testcontainers +@DirtiesContext +class NcmpEventsPublisherSpec extends MessagingSpec { + + def kafkaConsumer = new KafkaConsumer<>(consumerConfigProperties('ncmp-group')) + + def testTopic = 'ncmp-events-test' + + @SpringBean + NcmpEventsPublisher ncmpEventsPublisher = new NcmpEventsPublisher(kafkaTemplate) + + @Autowired + JsonObjectMapper jsonObjectMapper + + + def 'Produce and Consume Ncmp Event'() { + given: 'event key and event data' + def eventKey = 'ncmp' + def eventData = new NcmpEvent(eventId: 'test-uuid', + eventCorrelationId: 'cmhandle-as-correlationid', + eventSchema: URI.create('org.onap.ncmp.cmhandle.lcm.event:v1'), + eventSource: URI.create('org.onap.ncmp'), + eventTime: '2022-12-31T20:30:40.000+0000', + eventType: 'org.onap.ncmp.cmhandle.lcm.event', + event: new Event(cmHandleId: 'cmhandle-test', cmhandleState: 'READY', operation: 'CREATE', cmhandleProperties: [['publicProperty1': 'value1'], ['publicProperty2': 'value2']])) + and: 'we have an expected NcmpEvent' + def expectedJsonString = TestUtils.getResourceFileContent('expectedNcmpEvent.json') + def expectedNcmpEvent = jsonObjectMapper.convertJsonString(expectedJsonString, NcmpEvent.class) + and: 'consumer has a subscription' + kafkaConsumer.subscribe([testTopic] as List<String>) + when: 'an event is published' + ncmpEventsPublisher.publishEvent(testTopic, eventKey, eventData) + and: 'topic is polled' + def records = kafkaConsumer.poll(Duration.ofMillis(1500)) + then: 'no exception is thrown' + noExceptionThrown() + and: 'poll returns one record' + assert records.size() == 1 + and: 'record key matches the expected event key' + def record = records.iterator().next() + assert eventKey == record.key + and: 'record matches the expected event' + assert expectedNcmpEvent == jsonObjectMapper.convertJsonString(record.value, NcmpEvent.class) + + } +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/InventoryPersistenceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/InventoryPersistenceSpec.groovy index b638eecd41..a2ebcb5d81 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/InventoryPersistenceSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/InventoryPersistenceSpec.groovy @@ -88,7 +88,7 @@ class InventoryPersistenceSpec extends Specification { where: 'the following parameters are used' scenario | childDataNodes || expectedDmiProperties || expectedPublicProperties || expectedCompositeState 'no properties' | [] || [] || [] || null - 'DMI and public properties' | childDataNodesForCmHandleWithAllProperties || [new YangModelCmHandle.Property("name1", "value1")] || [new YangModelCmHandle.Property("name2", "value2")] || null + 'DMI and public properties' | childDataNodesForCmHandleWithAllProperties || [new YangModelCmHandle.Property("name1", "value1")] || [new YangModelCmHandle.Property("name2", "value2")] || null 'just DMI properties' | childDataNodesForCmHandleWithDMIProperties || [new YangModelCmHandle.Property("name1", "value1")] || [] || null 'just public properties' | childDataNodesForCmHandleWithPublicProperties || [] || [new YangModelCmHandle.Property("name2", "value2")] || null 'with state details' | childDataNodesForCmHandleWithState || [] || [] || CmHandleState.ADVISED @@ -105,7 +105,7 @@ class InventoryPersistenceSpec extends Specification { def "Handling missing service names as null CPS-1043."() { given: 'the cps data service returns a data node from the DMI registry with empty child and leaf attributes' - def dataNode = new DataNode(childDataNodes:[], leaves: [:]) + def dataNode = new DataNode(childDataNodes:[], leaves: ["cm-handle-state":"ADVISED"]) mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry', xpath, INCLUDE_ALL_DESCENDANTS) >> dataNode when: 'retrieving the yang modelled cm handle' def result = objectUnderTest.getYangModelCmHandle(cmHandleId) diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncServiceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncServiceSpec.groovy index 37fdbeeb2a..8050a571af 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncServiceSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncServiceSpec.groovy @@ -20,9 +20,11 @@ package org.onap.cps.ncmp.api.inventory.sync +import org.onap.cps.api.CpsAdminService import org.onap.cps.api.CpsModuleService import org.onap.cps.ncmp.api.impl.operations.DmiModelOperations import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle +import org.onap.cps.ncmp.api.inventory.CmHandleState import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle import org.onap.cps.spi.model.ModuleReference import spock.lang.Specification @@ -32,8 +34,9 @@ class ModuleSyncServiceSpec extends Specification { def mockCpsModuleService = Mock(CpsModuleService) def mockDmiModelOperations = Mock(DmiModelOperations) + def mockCpsAdminService = Mock(CpsAdminService) - def objectUnderTest = new ModuleSyncService(mockDmiModelOperations, mockCpsModuleService) + def objectUnderTest = new ModuleSyncService(mockDmiModelOperations, mockCpsModuleService, mockCpsAdminService) def expectedDataspaceName = 'NFP-Operational' @@ -42,7 +45,7 @@ class ModuleSyncServiceSpec extends Specification { def ncmpServiceCmHandle = new NcmpServiceCmHandle() def dmiServiceName = 'some service name' ncmpServiceCmHandle.cmHandleId = 'cmHandleId-1' - def yangModelCmHandle = YangModelCmHandle.toYangModelCmHandle(dmiServiceName, '' , '', ncmpServiceCmHandle) + def yangModelCmHandle = YangModelCmHandle.toYangModelCmHandle(dmiServiceName, '' , '', CmHandleState.ADVISED, ncmpServiceCmHandle) and: 'DMI operations returns some module references' def moduleReferences = [ new ModuleReference(moduleName:'module1',revision:'1'), new ModuleReference(moduleName:'module2',revision:'2') ] @@ -50,17 +53,19 @@ class ModuleSyncServiceSpec extends Specification { and: 'CPS-Core returns list of existing module resources' mockCpsModuleService.getYangResourceModuleReferences(expectedDataspaceName) >> toModuleReference(existingModuleResourcesInCps) and: 'DMI-Plugin returns resource(s) for "new" module(s)' - mockDmiModelOperations.getNewYangResourcesFromDmi(yangModelCmHandle, [new ModuleReference('module1', '1')]) >> yangResourceToContentMap + mockDmiModelOperations.getNewYangResourcesFromDmi(yangModelCmHandle, [new ModuleReference('module1', '1')]) >> newModuleNameContentToMap when: 'module sync is triggered' mockCpsModuleService.identifyNewModuleReferences(moduleReferences) >> toModuleReference(identifiedNewModuleReferences) - def result = objectUnderTest.syncAndCreateSchemaSet(yangModelCmHandle) - then: 'the resulting schema set name is the same as the cm handle id' - assert result == 'cmHandleId-1' + objectUnderTest.syncAndCreateSchemaSetAndAnchor(yangModelCmHandle) + then: 'create schema set from module is invoked with correct parameters' + 1 * mockCpsModuleService.createSchemaSetFromModules('NFP-Operational', 'cmHandleId-1', newModuleNameContentToMap, existingModuleReferencesInCps) + and: 'anchor is created with the correct parameters' + 1 * mockCpsAdminService.createAnchor('NFP-Operational', 'cmHandleId-1', 'cmHandleId-1') where: 'the following parameters are used' - scenario | existingModuleResourcesInCps | identifiedNewModuleReferences | yangResourceToContentMap - 'one new module' | [['module2' : '2'], ['module3' : '3']] | [['module1' : '1']] | [module1: 'some yang source'] - 'no add. properties' | [['module2' : '2'], ['module3' : '3']] | [['module1' : '1']] | [module1: 'some yang source'] - 'no new module' | [['module1' : '1'], ['module2' : '2']] | [] | [:] + scenario | existingModuleResourcesInCps | identifiedNewModuleReferences | newModuleNameContentToMap | existingModuleReferencesInCps + 'one new module' | [['module2' : '2'], ['module3' : '3']] | [['module1' : '1']] | [module1: 'some yang source'] | [new ModuleReference(moduleName:'module2',revision:'2')] + 'no add. properties' | [['module2' : '2'], ['module3' : '3']] | [['module1' : '1']] | [module1: 'some yang source'] | [new ModuleReference(moduleName:'module2',revision:'2')] + 'no new module' | [['module1' : '1'], ['module2' : '2']] | [] | [:] | [new ModuleReference(moduleName:'module1',revision:'1'), new ModuleReference(moduleName:'module2',revision:'2')] } def toModuleReference(moduleReferenceAsMap) { diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncSpec.groovy index bcfe47fd5d..97bea096a3 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncSpec.groovy @@ -52,7 +52,7 @@ class ModuleSyncSpec extends Specification { then: 'the inventory persistence cm handle returns a composite state for the first cm handle' 1 * mockInventoryPersistence.getCmHandleState('some-cm-handle') >> compositeState1 and: 'module sync service syncs the first cm handle and creates a schema set' - 1 * mockModuleSyncService.syncAndCreateSchemaSet(yangModelCmHandle1) + 1 * mockModuleSyncService.syncAndCreateSchemaSetAndAnchor(yangModelCmHandle1) and: 'the composite state cm handle state is now READY' assert compositeState1.getCmHandleState() == CmHandleState.READY and: 'the first cm handle state is updated' @@ -60,7 +60,7 @@ class ModuleSyncSpec extends Specification { then: 'the inventory persistence cm handle returns a composite state for the second cm handle' mockInventoryPersistence.getCmHandleState('some-cm-handle-2') >> compositeState2 and: 'module sync service syncs the second cm handle and creates a schema set' - 1 * mockModuleSyncService.syncAndCreateSchemaSet(yangModelCmHandle2) + 1 * mockModuleSyncService.syncAndCreateSchemaSetAndAnchor(yangModelCmHandle2) and: 'the composite state cm handle state is now READY' assert compositeState2.getCmHandleState() == CmHandleState.READY and: 'the second cm handle state is updated' @@ -78,7 +78,7 @@ class ModuleSyncSpec extends Specification { then: 'the inventory persistence cm handle returns a composite state for the cm handle' 1 * mockInventoryPersistence.getCmHandleState('some-cm-handle') >> compositeState and: 'module sync service attempts to sync the cm handle and throws an exception' - 1 * mockModuleSyncService.syncAndCreateSchemaSet(*_) >> { throw new Exception('some exception') } + 1 * mockModuleSyncService.syncAndCreateSchemaSetAndAnchor(*_) >> { throw new Exception('some exception') } and: 'the composite state cm handle state is now LOCKED' assert compositeState.getCmHandleState() == CmHandleState.LOCKED and: 'update lock reason, details and attempts is invoked' diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/YangModelCmHandleSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/YangModelCmHandleSpec.groovy index 7bbc3d7533..cdfcf59ef4 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/YangModelCmHandleSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/YangModelCmHandleSpec.groovy @@ -21,6 +21,8 @@ package org.onap.cps.ncmp.api.models import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle +import org.onap.cps.ncmp.api.inventory.CmHandleState +import org.onap.ncmp.cmhandle.lcm.event.Event import spock.lang.Specification import static org.onap.cps.ncmp.api.impl.operations.RequiredDmiService.DATA @@ -35,7 +37,7 @@ class YangModelCmHandleSpec extends Specification { ncmpServiceCmHandle.dmiProperties = [myDmiProperty:'value1'] ncmpServiceCmHandle.publicProperties = [myPublicProperty:'value2'] when: 'it is converted to a yang model cm handle' - def objectUnderTest = YangModelCmHandle.toYangModelCmHandle('','','', ncmpServiceCmHandle) + def objectUnderTest = YangModelCmHandle.toYangModelCmHandle('','','', CmHandleState.ADVISED, ncmpServiceCmHandle) then: 'the result has the right size' assert objectUnderTest.dmiProperties.size() == 1 and: 'the DMI property in the result has the correct name and value' @@ -48,7 +50,7 @@ class YangModelCmHandleSpec extends Specification { def 'Resolve DMI service name: #scenario and #requiredService service require.'() { given: 'a yang model cm handle' - def objectUnderTest = YangModelCmHandle.toYangModelCmHandle(dmiServiceName, dmiDataServiceName, dmiModelServiceName, new NcmpServiceCmHandle(cmHandleId: 'cm-handle-id-1')) + def objectUnderTest = YangModelCmHandle.toYangModelCmHandle(dmiServiceName, dmiDataServiceName, dmiModelServiceName, CmHandleState.ADVISED, new NcmpServiceCmHandle(cmHandleId: 'cm-handle-id-1')) expect: assert objectUnderTest.resolveDmiServiceName(requiredService) == expectedService where: diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/utils/DmiServiceUrlBuilderSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/utils/DmiServiceUrlBuilderSpec.groovy index 964826be13..b3ea3b870d 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/utils/DmiServiceUrlBuilderSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/utils/DmiServiceUrlBuilderSpec.groovy @@ -20,6 +20,8 @@ package org.onap.cps.ncmp.api.utils +import org.onap.cps.ncmp.api.inventory.CmHandleState + import static org.onap.cps.ncmp.api.impl.operations.DmiOperations.DataStoreEnum.PASSTHROUGH_RUNNING import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle @@ -33,7 +35,7 @@ class DmiServiceUrlBuilderSpec extends Specification { @Shared YangModelCmHandle yangModelCmHandle = YangModelCmHandle.toYangModelCmHandle('dmiServiceName', - 'dmiDataServiceName', 'dmiModuleServiceName', new NcmpServiceCmHandle(cmHandleId: 'some-cm-handle-id')) + 'dmiDataServiceName', 'dmiModuleServiceName', CmHandleState.ADVISED , new NcmpServiceCmHandle(cmHandleId: 'some-cm-handle-id')) NcmpConfiguration.DmiProperties dmiProperties = new NcmpConfiguration.DmiProperties() diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/utils/MessagingSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/utils/MessagingSpec.groovy new file mode 100644 index 0000000000..097834afc5 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/utils/MessagingSpec.groovy @@ -0,0 +1,71 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (c) 2022 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.ncmp.api.utils + +import org.apache.kafka.common.serialization.StringDeserializer +import org.apache.kafka.common.serialization.StringSerializer +import org.springframework.kafka.core.DefaultKafkaProducerFactory +import org.springframework.kafka.core.KafkaTemplate +import org.springframework.kafka.support.serializer.JsonSerializer +import org.springframework.test.context.DynamicPropertyRegistry +import org.springframework.test.context.DynamicPropertySource +import org.testcontainers.containers.KafkaContainer +import org.testcontainers.utility.DockerImageName +import spock.lang.Specification + +class MessagingSpec extends Specification { + + static { + Runtime.getRuntime().addShutdownHook(new Thread(kafkaTestContainer::stop)) + } + + def setupSpec() { + kafkaTestContainer.start() + } + + static kafkaTestContainer = new KafkaContainer(DockerImageName.parse('confluentinc/cp-kafka:6.2.1')) + + def producerConfigProperties() { + return [('bootstrap.servers'): kafkaTestContainer.getBootstrapServers().split(',')[0], + ('retries') : 0, + ('batch-size') : 16384, + ('linger.ms') : 1, + ('buffer.memory') : 33554432, + ('key.serializer') : StringSerializer, + ('value.serializer') : JsonSerializer] + } + + def consumerConfigProperties(consumerGroupId) { + return [('bootstrap.servers') : kafkaTestContainer.getBootstrapServers().split(',')[0], + ('key.deserializer') : StringDeserializer, + ('value.deserializer'): StringDeserializer, + ('auto.offset.reset') : 'earliest', + ('group.id') : consumerGroupId + ] + } + + def kafkaTemplate = new KafkaTemplate<>(new DefaultKafkaProducerFactory<Integer, String>(producerConfigProperties())) + + @DynamicPropertySource + static void registerKafkaProperties(DynamicPropertyRegistry dynamicPropertyRegistry) { + dynamicPropertyRegistry.add('spring.kafka.bootstrap-servers', kafkaTestContainer::getBootstrapServers) + } +} |