diff options
Diffstat (limited to 'cps-ncmp-service/src/test')
14 files changed, 396 insertions, 79 deletions
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 871af842ea..5b49e04635 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 @@ -52,10 +52,10 @@ import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity import spock.lang.Specification -import static org.onap.cps.ncmp.api.impl.operations.DmiOperations.DataStoreEnum.PASSTHROUGH_OPERATIONAL -import static org.onap.cps.ncmp.api.impl.operations.DmiOperations.DataStoreEnum.PASSTHROUGH_RUNNING -import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.CREATE -import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.UPDATE +import static org.onap.cps.ncmp.api.impl.operations.DataStoreEnum.PASSTHROUGH_OPERATIONAL +import static org.onap.cps.ncmp.api.impl.operations.DataStoreEnum.PASSTHROUGH_RUNNING +import static org.onap.cps.ncmp.api.impl.operations.OperationEnum.CREATE +import static org.onap.cps.ncmp.api.impl.operations.OperationEnum.UPDATE class NetworkCmProxyDataServiceImplSpec extends Specification { @@ -94,61 +94,64 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { def 'Write resource data for pass-through running from DMI using POST.'() { given: 'cpsDataService returns valid datanode' - mockCpsDataService.getDataNodes('NCMP-Admin', 'ncmp-dmi-registry', - cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode + mockDataNode() when: 'write resource data is called' objectUnderTest.writeResourceDataPassThroughRunningForCmHandle('testCmHandle', 'testResourceId', CREATE, '{some-json}', 'application/json') then: 'DMI called with correct data' 1 * mockDmiDataOperations.writeResourceDataPassThroughRunningFromDmi('testCmHandle', 'testResourceId', - CREATE, '{some-json}', 'application/json') + CREATE, '{some-json}', 'application/json') >> { new ResponseEntity<>(HttpStatus.CREATED) } } def 'Get resource data for pass-through operational from DMI.'() { given: 'get data node is called' - mockCpsDataService.getDataNodes('NCMP-Admin', 'ncmp-dmi-registry', - cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode + mockDataNode() and: 'get resource data from DMI is called' - mockDmiDataOperations.getResourceDataFromDmi( - 'testCmHandle', - 'testResourceId', - OPTIONS_PARAM, - PASSTHROUGH_OPERATIONAL, - NO_REQUEST_ID, - NO_TOPIC) >> new ResponseEntity<>('dmi-response', HttpStatus.OK) + mockDmiDataOperations.getResourceDataFromDmi(PASSTHROUGH_OPERATIONAL.value,'testCmHandle', + 'testResourceId', OPTIONS_PARAM, NO_TOPIC, NO_REQUEST_ID) >> + new ResponseEntity<>('dmi-response', HttpStatus.OK) when: 'get resource data operational for cm-handle is called' - def response = objectUnderTest.getResourceDataOperationalForCmHandle('testCmHandle', - 'testResourceId', - OPTIONS_PARAM, - NO_TOPIC, - NO_REQUEST_ID) + def response = objectUnderTest.getResourceDataForCmHandle(PASSTHROUGH_OPERATIONAL.value, 'testCmHandle', + 'testResourceId', OPTIONS_PARAM, NO_TOPIC, NO_REQUEST_ID) then: 'DMI returns a json response' response == 'dmi-response' } def 'Get resource data for pass-through running from DMI.'() { given: 'cpsDataService returns valid data node' - mockCpsDataService.getDataNodes('NCMP-Admin', 'ncmp-dmi-registry', - cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode + mockDataNode() and: 'DMI returns valid response and data' - mockDmiDataOperations.getResourceDataFromDmi('testCmHandle', - 'testResourceId', - OPTIONS_PARAM, - PASSTHROUGH_RUNNING, - NO_REQUEST_ID, - NO_TOPIC) >> new ResponseEntity<>('{dmi-response}', HttpStatus.OK) + mockDmiDataOperations.getResourceDataFromDmi(PASSTHROUGH_RUNNING.value, 'testCmHandle', + 'testResourceId', OPTIONS_PARAM, NO_TOPIC, NO_REQUEST_ID) >> + new ResponseEntity<>('{dmi-response}', HttpStatus.OK) when: 'get resource data is called' - def response = objectUnderTest.getResourceDataPassThroughRunningForCmHandle('testCmHandle', - 'testResourceId', - OPTIONS_PARAM, - NO_TOPIC, - NO_REQUEST_ID) + def response = objectUnderTest.getResourceDataForCmHandle(PASSTHROUGH_RUNNING.value, 'testCmHandle', + 'testResourceId', OPTIONS_PARAM, NO_TOPIC, NO_REQUEST_ID) then: 'get resource data returns expected response' response == '{dmi-response}' } + def 'Get bulk resource data for #datastoreName from DMI.'() { + given: 'cpsDataService returns valid data node' + mockDataNode() + and: 'DMI returns valid response and data' + mockDmiDataOperations.getResourceDataFromDmi(datastoreName, ['testCmHandle'], + 'testResourceId', OPTIONS_PARAM,'some topic','requestId') >> + new ResponseEntity<>('{dmi-bulk-response}', HttpStatus.OK) + when: 'get batch resource data is called' + def response = objectUnderTest.getResourceDataForCmHandleBatch(datastoreName, ['testCmHandle'], + 'testResourceId', + OPTIONS_PARAM, + 'some topic', + 'requestId') + then: 'get bulk resource data returns expected response' + response == '{dmi-bulk-response}' + where: 'the following data stores are used' + datastoreName << [PASSTHROUGH_RUNNING.value, PASSTHROUGH_OPERATIONAL.value] + } + def 'Getting Yang Resources.'() { when: 'yang resources is called' objectUnderTest.getYangResourcesModuleReferences('some-cm-handle') @@ -242,7 +245,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { '{some-json}', 'application/json') then: 'DMI called with correct data' 1 * mockDmiDataOperations.writeResourceDataPassThroughRunningFromDmi('testCmHandle', 'testResourceId', - UPDATE, '{some-json}', 'application/json') + UPDATE, '{some-json}', 'application/json') >> { new ResponseEntity<>(HttpStatus.OK) } } @@ -365,4 +368,9 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { .dataStoreSyncState(DataStoreSyncState.NONE_REQUESTED) .lastSyncTime('some-timestamp').build()).build() } + + def mockDataNode() { + mockCpsDataService.getDataNodes('NCMP-Admin', 'ncmp-dmi-registry', + cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode + } } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/client/DmiRestClientSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/client/DmiRestClientSpec.groovy index 90839f8ac0..b38ca10f7b 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/client/DmiRestClientSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/client/DmiRestClientSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2021-2022 Nordix Foundation + * Copyright (C) 2021-2023 Nordix Foundation * Modifications Copyright (C) 2022 Bell Canada * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -34,10 +34,9 @@ import org.springframework.web.client.HttpServerErrorException import org.springframework.web.client.RestTemplate import spock.lang.Specification -import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.READ -import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.PATCH -import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.CREATE - +import static org.onap.cps.ncmp.api.impl.operations.OperationEnum.READ +import static org.onap.cps.ncmp.api.impl.operations.OperationEnum.PATCH +import static org.onap.cps.ncmp.api.impl.operations.OperationEnum.CREATE @SpringBootTest @ContextConfiguration(classes = [NcmpConfiguration.DmiProperties, DmiRestClient]) diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/embeddedcache/SynchronizationCacheConfigSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/embeddedcache/SynchronizationCacheConfigSpec.groovy index 868ee7a705..567debdded 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/embeddedcache/SynchronizationCacheConfigSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/embeddedcache/SynchronizationCacheConfigSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================== - * Copyright (C) 2022 Nordix Foundation + * Copyright (C) 2022-2023 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ package org.onap.cps.ncmp.api.impl.config.embeddedcache +import com.hazelcast.config.Config import com.hazelcast.core.Hazelcast import com.hazelcast.map.IMap import org.onap.cps.spi.model.DataNode @@ -50,8 +51,8 @@ class SynchronizationCacheConfigSpec extends Specification { assert null != moduleSyncStartedOnCmHandles and: 'system is able to create an instance of a map to hold data sync semaphores' assert null != dataSyncSemaphores - and: 'there 3 instances' - assert Hazelcast.allHazelcastInstances.size() == 3 + and: 'there are at least 3 instances' + assert Hazelcast.allHazelcastInstances.size() > 2 and: 'they have the correct names (in any order)' assert Hazelcast.allHazelcastInstances.name.containsAll('moduleSyncWorkQueue', 'moduleSyncStartedOnCmHandles', 'dataSyncSemaphores' ) } @@ -74,6 +75,40 @@ class SynchronizationCacheConfigSpec extends Specification { assert dataSyncSemaphoresConfig.asyncBackupCount == 3 } + def 'Verify deployment network configs for Distributed objects'() { + given: 'the Module Sync Work Queue config' + def queueNetworkConfig = Hazelcast.getHazelcastInstanceByName('moduleSyncWorkQueue').config.networkConfig + and: 'the Module Sync Started Cm Handle Map config' + def moduleSyncStartedOnCmHandlesNetworkConfig = Hazelcast.getHazelcastInstanceByName('moduleSyncStartedOnCmHandles').config.networkConfig + and: 'the Data Sync Semaphores Map config' + def dataSyncSemaphoresNetworkConfig = Hazelcast.getHazelcastInstanceByName('dataSyncSemaphores').config.networkConfig + expect: 'system created instance with correct config of Module Sync Work Queue' + assert queueNetworkConfig.join.autoDetectionConfig.enabled + assert !queueNetworkConfig.join.kubernetesConfig.enabled + and: 'Module Sync Started Cm Handle Map has the correct settings' + assert moduleSyncStartedOnCmHandlesNetworkConfig.join.autoDetectionConfig.enabled + assert !moduleSyncStartedOnCmHandlesNetworkConfig.join.kubernetesConfig.enabled + and: 'Data Sync Semaphore Map has the correct settings' + assert dataSyncSemaphoresNetworkConfig.join.autoDetectionConfig.enabled + assert !dataSyncSemaphoresNetworkConfig.join.kubernetesConfig.enabled + + } + + def 'Verify network config'() { + given: 'Synchronization config object and test configuration' + def objectUnderTest = new SynchronizationCacheConfig() + def testConfig = new Config() + when: 'kubernetes properties are enabled' + objectUnderTest.cacheKubernetesEnabled = true + objectUnderTest.cacheKubernetesServiceName = 'test-service-name' + and: 'method called to update the discovery mode' + objectUnderTest.updateDiscoveryMode(testConfig) + then: 'applied properties are reflected' + assert testConfig.networkConfig.join.kubernetesConfig.enabled + assert testConfig.networkConfig.join.kubernetesConfig.properties.get('service-name') == 'test-service-name' + + } + def 'Time to Live Verify for Module Sync Semaphore'() { when: 'the key is inserted with a TTL of 1 second (Hazelcast TTL resolution is seconds!)' moduleSyncStartedOnCmHandles.put('testKeyModuleSync', 'toBeExpired' as Object, 1, TimeUnit.SECONDS) diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/avc/ForwardedSubscriptionEventCacheConfigSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/avc/ForwardedSubscriptionEventCacheConfigSpec.groovy new file mode 100644 index 0000000000..7448daf598 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/avc/ForwardedSubscriptionEventCacheConfigSpec.groovy @@ -0,0 +1,75 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023 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.avc + +import com.hazelcast.config.Config +import com.hazelcast.core.Hazelcast +import com.hazelcast.map.IMap +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import spock.lang.Specification + +@SpringBootTest(classes = [ForwardedSubscriptionEventCacheConfig]) +class ForwardedSubscriptionEventCacheConfigSpec extends Specification { + + @Autowired + private IMap<String, Set<String>> forwardedSubscriptionEventCache + + def 'Embedded (hazelcast) cache for Forwarded Subscription Event Cache.'() { + expect: 'system is able to create an instance of the Forwarded Subscription Event Cache' + assert null != forwardedSubscriptionEventCache + and: 'there is at least 1 instance' + assert Hazelcast.allHazelcastInstances.size() > 0 + and: 'Forwarded Subscription Event Cache is present' + assert Hazelcast.allHazelcastInstances.name.contains('hazelCastInstanceSubscriptionEvents') + } + + def 'Verify configs for Distributed Caches'(){ + given: 'the Forwarded Subscription Event Cache config' + def forwardedSubscriptionEventCacheConfig = Hazelcast.getHazelcastInstanceByName('hazelCastInstanceSubscriptionEvents').config.mapConfigs.get('forwardedSubscriptionEventCacheMapConfig') + expect: 'system created instance with correct config' + assert forwardedSubscriptionEventCacheConfig.backupCount == 3 + assert forwardedSubscriptionEventCacheConfig.asyncBackupCount == 3 + } + + def 'Verify deployment network configs for Distributed Caches'() { + given: 'the Forwarded Subscription Event Cache config' + def forwardedSubscriptionEventCacheNetworkConfig = Hazelcast.getHazelcastInstanceByName('hazelCastInstanceSubscriptionEvents').config.networkConfig + expect: 'system created instance with correct config' + assert forwardedSubscriptionEventCacheNetworkConfig.join.autoDetectionConfig.enabled + assert !forwardedSubscriptionEventCacheNetworkConfig.join.kubernetesConfig.enabled + } + + def 'Verify network config'() { + given: 'Synchronization config object and test configuration' + def objectUnderTest = new ForwardedSubscriptionEventCacheConfig() + def testConfig = new Config() + when: 'kubernetes properties are enabled' + objectUnderTest.cacheKubernetesEnabled = true + objectUnderTest.cacheKubernetesServiceName = 'test-service-name' + and: 'method called to update the discovery mode' + objectUnderTest.updateDiscoveryMode(testConfig) + then: 'applied properties are reflected' + assert testConfig.networkConfig.join.kubernetesConfig.enabled + assert testConfig.networkConfig.join.kubernetesConfig.properties.get('service-name') == 'test-service-name' + + } +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionEventResponseConsumerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionEventResponseConsumerSpec.groovy new file mode 100644 index 0000000000..a673462008 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/avc/SubscriptionEventResponseConsumerSpec.groovy @@ -0,0 +1,79 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (c) 2023 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.avc + +import com.fasterxml.jackson.databind.ObjectMapper +import com.hazelcast.map.IMap +import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec +import org.onap.cps.ncmp.api.models.SubscriptionEventResponse +import org.onap.cps.utils.JsonObjectMapper +import org.springframework.boot.test.context.SpringBootTest + +@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper]) +class SubscriptionEventResponseConsumerSpec extends MessagingBaseSpec { + + IMap<String, Set<String>> mockForwardedSubscriptionEventCache = Mock(IMap<String, Set<String>>) + + def objectUnderTest = new SubscriptionEventResponseConsumer(mockForwardedSubscriptionEventCache) + + + def 'Consume Subscription Event Response where all DMIs have responded'() { + given: 'a subscription event response with a clientId, subscriptionName and dmiName' + def testEventReceived = new SubscriptionEventResponse() + testEventReceived.clientId = 'some-client-id' + testEventReceived.subscriptionName = 'some-subscription-name' + testEventReceived.dmiName = 'some-dmi-name' + and: 'notifications are enabled' + objectUnderTest.notificationFeatureEnabled = true + and: 'subscription model loader is enabled' + objectUnderTest.subscriptionModelLoaderEnabled = true + when: 'the valid event is consumed' + objectUnderTest.consumeSubscriptionEventResponse(testEventReceived) + then: 'the forwarded subscription event cache returns only the received dmiName existing for the subscription create event' + 1 * mockForwardedSubscriptionEventCache.containsKey('some-client-idsome-subscription-name') >> true + 1 * mockForwardedSubscriptionEventCache.get('some-client-idsome-subscription-name') >> (['some-dmi-name'] as Set) + and: 'the forwarded subscription event cache returns an empty Map when the dmiName has been removed' + 1 * mockForwardedSubscriptionEventCache.get('some-client-idsome-subscription-name') >> ([] as Set) + and: 'the subscription event is removed from the map' + 1 * mockForwardedSubscriptionEventCache.remove('some-client-idsome-subscription-name') + } + + def 'Consume Subscription Event Response where another DMI has not yet responded'() { + given: 'a subscription event response with a clientId, subscriptionName and dmiName' + def testEventReceived = new SubscriptionEventResponse() + testEventReceived.clientId = 'some-client-id' + testEventReceived.subscriptionName = 'some-subscription-name' + testEventReceived.dmiName = 'some-dmi-name' + and: 'notifications are enabled' + objectUnderTest.notificationFeatureEnabled = true + and: 'subscription model loader is enabled' + objectUnderTest.subscriptionModelLoaderEnabled = true + when: 'the valid event is consumed' + objectUnderTest.consumeSubscriptionEventResponse(testEventReceived) + then: 'the forwarded subscription event cache returns only the received dmiName existing for the subscription create event' + 1 * mockForwardedSubscriptionEventCache.containsKey('some-client-idsome-subscription-name') >> true + 1 * mockForwardedSubscriptionEventCache.get('some-client-idsome-subscription-name') >> (['some-dmi-name', 'non-responded-dmi'] as Set) + and: 'the forwarded subscription event cache returns an empty Map when the dmiName has been removed' + 1 * mockForwardedSubscriptionEventCache.get('some-client-idsome-subscription-name') >> (['non-responded-dmi'] as Set) + and: 'the subscription event is not removed from the map' + 0 * mockForwardedSubscriptionEventCache.remove(_) + } +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avc/SubscriptionEventMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avc/SubscriptionEventMapperSpec.groovy index 3a7aa481c3..f2ff1f7b23 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avc/SubscriptionEventMapperSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avc/SubscriptionEventMapperSpec.groovy @@ -48,7 +48,7 @@ class SubscriptionEventMapperSpec extends Specification { def result = objectUnderTest.toYangModelSubscriptionEvent(testEventToMap) then: 'the resulting yang model subscription event contains the correct clientId' assert result.clientId == "SCO-9989752" - and: 'client name' + and: 'subscription name' assert result.subscriptionName == "cm-subscription-001" and: 'is tagged value is false' assert !result.isTagged @@ -60,4 +60,21 @@ class SubscriptionEventMapperSpec extends Specification { assert result.topic == null } + def 'Map null subscription event to yang model subscription event where #scenario'() { + given: 'a new Subscription Event with no data' + def testEventToMap = new SubscriptionEvent() + when: 'the event is mapped to a yang model subscription' + def result = objectUnderTest.toYangModelSubscriptionEvent(testEventToMap) + then: 'the resulting yang model subscription event contains null clientId' + assert result.clientId == null + and: 'subscription name is null' + assert result.subscriptionName == null + and: 'is tagged value is false' + assert result.isTagged == false + and: 'predicates is null' + assert result.predicates == null + and: 'the topic is null' + assert result.topic == null + } + }
\ No newline at end of file diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventForwarderSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventForwarderSpec.groovy index 2b0adf3420..457eb6fa99 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventForwarderSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avcsubscription/SubscriptionEventForwarderSpec.groovy @@ -21,6 +21,7 @@ package org.onap.cps.ncmp.api.impl.events.avcsubscription import com.fasterxml.jackson.databind.ObjectMapper +import com.hazelcast.map.IMap import org.onap.cps.ncmp.api.impl.events.EventsPublisher import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle import org.onap.cps.ncmp.api.inventory.InventoryPersistence @@ -29,20 +30,28 @@ import org.onap.cps.ncmp.event.model.SubscriptionEvent import org.onap.cps.ncmp.utils.TestUtils import org.onap.cps.spi.exceptions.OperationNotYetSupportedException import org.onap.cps.utils.JsonObjectMapper +import org.spockframework.spring.SpringBean import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest +import spock.util.concurrent.BlockingVariable -@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper]) +@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper, SubscriptionEventForwarder]) class SubscriptionEventForwarderSpec extends MessagingBaseSpec { - def mockInventoryPersistence = Mock(InventoryPersistence) - def mockSubscriptionEventPublisher = Mock(EventsPublisher<SubscriptionEvent>) - def objectUnderTest = new SubscriptionEventForwarder(mockInventoryPersistence, mockSubscriptionEventPublisher) + @Autowired + SubscriptionEventForwarder objectUnderTest + + @SpringBean + InventoryPersistence mockInventoryPersistence = Mock(InventoryPersistence) + @SpringBean + EventsPublisher<SubscriptionEvent> mockSubscriptionEventPublisher = Mock(EventsPublisher<SubscriptionEvent>) + @SpringBean + IMap<String, Set<String>> mockForwardedSubscriptionEventCache = Mock(IMap<String, Set<String>>) @Autowired JsonObjectMapper jsonObjectMapper - def 'Forward valid CM create subscription'() { + def 'Forward valid CM create subscription and simulate timeout where #scenario'() { given: 'an event' def jsonData = TestUtils.getResourceFileContent('avcSubscriptionCreationEvent.json') def testEventSent = jsonObjectMapper.convertJsonString(jsonData, SubscriptionEvent.class) @@ -52,9 +61,17 @@ class SubscriptionEventForwarderSpec extends MessagingBaseSpec { createYangModelCmHandleWithDmiProperty(2, 1,"shape","square"), createYangModelCmHandleWithDmiProperty(3, 2,"shape","triangle") ] + and: 'the thread creation delay is reduced to 2 seconds for testing' + objectUnderTest.dmiResponseTimeoutInMs = 2000 + and: 'a Blocking Variable is used for the Asynchronous call with a timeout of 5 seconds' + def block = new BlockingVariable<Object>(5) when: 'the valid event is forwarded' objectUnderTest.forwardCreateSubscriptionEvent(testEventSent) - then: 'the event is forwarded twice with the CMHandle private properties and provides a valid listenable future' + then: 'An asynchronous call is made to the blocking variable' + block.get() + then: 'the event is added to the forwarded subscription event cache' + 1 * mockForwardedSubscriptionEventCache.put("SCO-9989752cm-subscription-001", ["DMIName1", "DMIName2"] as Set) + and: 'the event is forwarded twice with the CMHandle private properties and provides a valid listenable future' 1 * mockSubscriptionEventPublisher.publishEvent("ncmp-dmi-cm-avc-subscription-DMIName1", "SCO-9989752-cm-subscription-001-DMIName1", subscriptionEvent -> { Map targets = subscriptionEvent.getEvent().getPredicates().getTargets().get(0) @@ -68,6 +85,15 @@ class SubscriptionEventForwarderSpec extends MessagingBaseSpec { targets["CMHandle3"] == ["shape":"triangle"] } ) + and: 'a separate thread has been created where the map is polled' + 1 * mockForwardedSubscriptionEventCache.containsKey("SCO-9989752cm-subscription-001") >> true + 1 * mockForwardedSubscriptionEventCache.get(_) >> (DMINamesInMap) + and: 'the subscription id is removed from the event cache map returning the asynchronous blocking variable' + 1 * mockForwardedSubscriptionEventCache.remove("SCO-9989752cm-subscription-001") >> {block.set(_)} + where: + scenario | DMINamesInMap + 'there are dmis which have not responded' | ["DMIName1", "DMIName2"] as Set + 'all dmis have responded ' | [] as Set } def 'Forward CM create subscription where target CM Handles are #scenario'() { diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy index 03825c2bbf..89b3a2ff26 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2021-2022 Nordix Foundation + * Copyright (C) 2021-2023 Nordix Foundation * Modifications Copyright (C) 2022 Bell Canada * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -30,14 +30,14 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import org.springframework.http.ResponseEntity import org.springframework.test.context.ContextConfiguration +import org.springframework.http.HttpStatus import spock.lang.Shared -import static org.onap.cps.ncmp.api.impl.operations.DmiOperations.DataStoreEnum.PASSTHROUGH_OPERATIONAL -import static org.onap.cps.ncmp.api.impl.operations.DmiOperations.DataStoreEnum.PASSTHROUGH_RUNNING -import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.CREATE -import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.READ -import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.UPDATE -import org.springframework.http.HttpStatus +import static org.onap.cps.ncmp.api.impl.operations.DataStoreEnum.PASSTHROUGH_OPERATIONAL +import static org.onap.cps.ncmp.api.impl.operations.DataStoreEnum.PASSTHROUGH_RUNNING +import static org.onap.cps.ncmp.api.impl.operations.OperationEnum.CREATE +import static org.onap.cps.ncmp.api.impl.operations.OperationEnum.READ +import static org.onap.cps.ncmp.api.impl.operations.OperationEnum.UPDATE @SpringBootTest @ContextConfiguration(classes = [NcmpConfiguration.DmiProperties, DmiDataOperations]) @@ -50,6 +50,8 @@ class DmiDataOperationsSpec extends DmiOperationsBaseSpec { def NO_REQUEST_ID = null @Shared def OPTIONS_PARAM = '(a=1,b=2)' + @Shared + def expectedBulkRequestAsJson = '{"operation": "read","data": {"fe1c1f1a070c4ce5bbfda7198592a0d3": {"neType": "RadioNode"},"b8e42eed0d9541ed8d8839e8eb86b3e0": {"neType": "RadioNode"}},"requestId": "bbb67474-f705-410a-93d1-b2844e7f45fd"}' @SpringBean JsonObjectMapper spiedJsonObjectMapper = Spy(new JsonObjectMapper(new ObjectMapper())) @@ -66,8 +68,8 @@ class DmiDataOperationsSpec extends DmiOperationsBaseSpec { mockDmiRestClient.postOperationWithJsonData(expectedUrl, expectedJson, READ) >> responseFromDmi dmiServiceUrlBuilder.getDmiDatastoreUrl(_, _) >> expectedUrl when: 'get resource data is invoked' - def result = objectUnderTest.getResourceDataFromDmi(cmHandleId, resourceIdentifier, - options, dataStore, NO_REQUEST_ID, NO_TOPIC) + def result = objectUnderTest.getResourceDataFromDmi(dataStore.value, cmHandleId, resourceIdentifier, + options, NO_TOPIC, NO_REQUEST_ID) then: 'the result is the response from the DMI service' assert result == responseFromDmi where: 'the following parameters are used' @@ -80,6 +82,25 @@ class DmiDataOperationsSpec extends DmiOperationsBaseSpec { 'datastore running with properties' | [yangModelCmHandleProperty] | PASSTHROUGH_RUNNING | OPTIONS_PARAM || '{"operation":"read","cmHandleProperties":{"prop1":"val1"}}' | 'passthrough-running' | '&options=(a=1,b=2)' } + def 'call get bulk resource data for #dataStore from DMI service with topic #scenario.'() { + given: 'collection of yang model cm Handles' + mockYangModelCmHandleCollectionRetrieval([yangModelCmHandleProperty]) + and: 'a positive response from DMI service when it is called with the expected parameters' + def responseFromDmi = new ResponseEntity<Object>(HttpStatus.ACCEPTED) + def expectedDmiBulkResourceDataUrl = "ncmp/v1/batch/data/ds/${dataStore}?resourceIdentifier=parent/child%26options=(a=1,b=2)&topic=my-topic-name&options=(fields=schemas/schema)" + mockDmiRestClient.postOperationWithJsonData(expectedDmiBulkResourceDataUrl, expectedBulkRequestAsJson, READ) >> responseFromDmi + dmiServiceUrlBuilder.getBulkRequestUrl(_, _) >> expectedDmiBulkResourceDataUrl + when: 'get resource data for bulk cm handle is invoked' + def result = objectUnderTest.getResourceDataFromDmi( dataStore.value, [cmHandleId], resourceIdentifier, + OPTIONS_PARAM, 'some-topic','requestId') + then: 'the result is the response from the DMI service' + assert result == responseFromDmi + where: 'the following parameters are used' + scenario | dataStore + 'datastore operational' | PASSTHROUGH_OPERATIONAL + 'datastore running' | PASSTHROUGH_RUNNING + } + def 'call get all resource data.'() { given: 'the system returns a cm handle with a sample property' mockYangModelCmHandleRetrieval([yangModelCmHandleProperty]) @@ -89,7 +110,7 @@ class DmiDataOperationsSpec extends DmiOperationsBaseSpec { mockDmiRestClient.postOperationWithJsonData(expectedUrl, '{"operation":"read","cmHandleProperties":{"prop1":"val1"}}', READ) >> responseFromDmi dmiServiceUrlBuilder.getDmiDatastoreUrl(_, _) >> expectedUrl when: 'get resource data is invoked' - def result = objectUnderTest.getResourceDataFromDmi(cmHandleId, PASSTHROUGH_OPERATIONAL, NO_REQUEST_ID) + def result = objectUnderTest.getResourceDataFromDmi( PASSTHROUGH_OPERATIONAL.value, cmHandleId, NO_REQUEST_ID) then: 'the result is the response from the DMI service' assert result == responseFromDmi } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiModelOperationsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiModelOperationsSpec.groovy index ed8f08698d..ed74ad3342 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiModelOperationsSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiModelOperationsSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2021-2022 Nordix Foundation + * Copyright (C) 2021-2023 Nordix Foundation * Modifications Copyright (C) 2022 Bell Canada * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,6 +24,8 @@ package org.onap.cps.ncmp.api.impl.operations import com.fasterxml.jackson.core.JsonProcessingException import com.fasterxml.jackson.databind.ObjectMapper import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration +import org.onap.cps.ncmp.api.impl.executor.TaskExecutor +import org.onap.cps.ncmp.api.impl.utils.DmiServiceNameOrganizer import org.onap.cps.spi.model.ModuleReference import org.onap.cps.utils.JsonObjectMapper import org.spockframework.spring.SpringBean @@ -34,7 +36,7 @@ import org.springframework.http.ResponseEntity import org.springframework.test.context.ContextConfiguration import spock.lang.Shared -import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.READ +import static org.onap.cps.ncmp.api.impl.operations.OperationEnum.READ @SpringBootTest @ContextConfiguration(classes = [NcmpConfiguration.DmiProperties, DmiModelOperations]) @@ -49,6 +51,12 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec { @SpringBean JsonObjectMapper spiedJsonObjectMapper = Spy(new JsonObjectMapper(new ObjectMapper())) + @SpringBean + TaskExecutor stubbedTaskExecutor = Stub() + + @SpringBean + DmiServiceNameOrganizer stubbedDmiServiceNameOrganizer = Stub() + def 'Retrieving module references.'() { given: 'a cm handle' mockYangModelCmHandleRetrieval([]) @@ -89,7 +97,7 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec { and: 'a positive response from DMI service when it is called with tha expected parameters' def responseFromDmi = new ResponseEntity<String>(HttpStatus.OK) mockDmiRestClient.postOperationWithJsonData("${dmiServiceName}/dmi/v1/ch/${cmHandleId}/modules", - '{"cmHandleProperties":' + expectedAdditionalPropertiesInRequest + '}', READ) >> responseFromDmi + '{"cmHandleProperties":' + expectedAdditionalPropertiesInRequest + '}', READ) >> responseFromDmi when: 'a get module references is called' def result = objectUnderTest.getModuleReferences(yangModelCmHandle) then: 'the result is the response from DMI service' @@ -108,7 +116,7 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec { [moduleName: 'mod2', revision: 'C', yangSource: 'other yang source']], HttpStatus.OK) def expectedModuleReferencesInRequest = '{"name":"mod1","revision":"A"},{"name":"mod2","revision":"X"}' mockDmiRestClient.postOperationWithJsonData("${dmiServiceName}/dmi/v1/ch/${cmHandleId}/moduleResources", - '{"data":{"modules":[' + expectedModuleReferencesInRequest + ']},"cmHandleProperties":{}}', READ) >> responseFromDmi + '{"data":{"modules":[' + expectedModuleReferencesInRequest + ']},"cmHandleProperties":{}}', READ) >> responseFromDmi when: 'get new yang resources from DMI service' def result = objectUnderTest.getNewYangResourcesFromDmi(yangModelCmHandle, newModuleReferences) then: 'the result has the 2 expected yang (re)sources (order is not guaranteed)' @@ -140,7 +148,7 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec { and: 'a positive response from DMI service when it is called with the expected parameters' def responseFromDmi = new ResponseEntity<>([[moduleName: 'mod1', revision: 'A', yangSource: 'some yang source']], HttpStatus.OK) mockDmiRestClient.postOperationWithJsonData("${dmiServiceName}/dmi/v1/ch/${cmHandleId}/moduleResources", - '{"data":{"modules":[' + expectedModuleReferencesInRequest + ']},"cmHandleProperties":' + expectedAdditionalPropertiesInRequest + '}', READ) >> responseFromDmi + '{"data":{"modules":[' + expectedModuleReferencesInRequest + ']},"cmHandleProperties":' + expectedAdditionalPropertiesInRequest + '}', READ) >> responseFromDmi when: 'get new yang resources from DMI service' def result = objectUnderTest.getNewYangResourcesFromDmi(yangModelCmHandle, unknownModuleReferences) then: 'the result is the response from DMI service' diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy index c4d0020a6c..1b2c50ae76 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy @@ -58,12 +58,21 @@ abstract class DmiOperationsBaseSpec extends Specification { def static resourceIdentifier = 'parent/child' def mockYangModelCmHandleRetrieval(dmiProperties) { + populateYangModelCmHandle(dmiProperties) + mockInventoryPersistence.getYangModelCmHandle(cmHandleId) >> yangModelCmHandle + } + + def mockYangModelCmHandleCollectionRetrieval(dmiProperties) { + populateYangModelCmHandle(dmiProperties) + mockInventoryPersistence.getYangModelCmHandles(_) >> [yangModelCmHandle] + } + + def populateYangModelCmHandle(dmiProperties) { yangModelCmHandle.dmiDataServiceName = dmiServiceName yangModelCmHandle.dmiServiceName = dmiServiceName yangModelCmHandle.dmiProperties = dmiProperties yangModelCmHandle.id = cmHandleId yangModelCmHandle.compositeState = new CompositeState() yangModelCmHandle.compositeState.cmHandleState = CmHandleState.READY - mockInventoryPersistence.getYangModelCmHandle(cmHandleId) >> yangModelCmHandle } } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilderSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilderSpec.groovy index 01569887ce..6ca3105500 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilderSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilderSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2022 Nordix Foundation + * Copyright (C) 2022-2023 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,9 +20,10 @@ package org.onap.cps.ncmp.api.impl.utils +import org.onap.cps.ncmp.api.impl.operations.RequiredDmiService import org.onap.cps.spi.utils.CpsValidator -import static org.onap.cps.ncmp.api.impl.operations.DmiOperations.DataStoreEnum.PASSTHROUGH_RUNNING +import static org.onap.cps.ncmp.api.impl.operations.DataStoreEnum.PASSTHROUGH_RUNNING import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration @@ -45,8 +46,8 @@ class DmiServiceUrlBuilderSpec extends Specification { def 'Create the dmi service url with #scenario.'() { given: 'uri variables' dmiProperties.dmiBasePath = 'dmi' - def uriVars = objectUnderTest.populateUriVariables(yangModelCmHandle, - "cmHandle", PASSTHROUGH_RUNNING) + def uriVars = objectUnderTest.populateUriVariables(PASSTHROUGH_RUNNING.value, yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA), + "cmHandle") and: 'query params' def uriQueries = objectUnderTest.populateQueryParams(resourceId, 'optionsParamInQuery', topic) @@ -65,8 +66,8 @@ class DmiServiceUrlBuilderSpec extends Specification { def 'Populate dmi data store url #scenario.'() { given: 'uri variables are created' dmiProperties.dmiBasePath = dmiBasePath - def uriVars = objectUnderTest.populateUriVariables(yangModelCmHandle, - "cmHandle", PASSTHROUGH_RUNNING) + def uriVars = objectUnderTest.populateUriVariables(PASSTHROUGH_RUNNING.value, yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA), + "cmHandle") and: 'null query params' def uriQueries = objectUnderTest.populateQueryParams(null, null, null) diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/SyncUtilsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/SyncUtilsSpec.groovy index f4176d6212..8164dcf9ca 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/SyncUtilsSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/SyncUtilsSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2022 Nordix Foundation + * Copyright (C) 2022-2023 Nordix Foundation * Modifications Copyright (C) 2022 Bell Canada * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,10 +21,11 @@ package org.onap.cps.ncmp.api.inventory.sync +import static org.onap.cps.ncmp.api.impl.operations.DataStoreEnum.PASSTHROUGH_OPERATIONAL + import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.ObjectMapper import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations -import org.onap.cps.ncmp.api.impl.operations.DmiOperations import org.onap.cps.ncmp.api.inventory.CmHandleQueries import org.onap.cps.ncmp.api.inventory.CmHandleState import org.onap.cps.ncmp.api.inventory.CompositeState @@ -38,7 +39,6 @@ import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity import spock.lang.Shared import spock.lang.Specification - import java.time.OffsetDateTime import java.time.format.DateTimeFormatter import java.util.stream.Collectors @@ -137,7 +137,7 @@ class SyncUtilsSpec extends Specification{ def jsonString = '{"stores:bookstore":{"categories":[{"code":"01"}]}}' JsonNode jsonNode = jsonObjectMapper.convertToJsonNode(jsonString); def responseEntity = new ResponseEntity<>(jsonNode, HttpStatus.OK) - mockDmiDataOperations.getResourceDataFromDmi('cm-handle-123', DmiOperations.DataStoreEnum.PASSTHROUGH_OPERATIONAL, _) >> responseEntity + mockDmiDataOperations.getResourceDataFromDmi(PASSTHROUGH_OPERATIONAL.value, 'cm-handle-123', _) >> responseEntity when: 'get resource data is called' def result = objectUnderTest.getResourceData('cm-handle-123') then: 'the returned data is correct' diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/SubscriptionModelLoaderSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/SubscriptionModelLoaderSpec.groovy index aa8bc53c9d..a14a0f286c 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/SubscriptionModelLoaderSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/SubscriptionModelLoaderSpec.groovy @@ -32,6 +32,7 @@ import org.onap.cps.ncmp.api.impl.exception.NcmpStartUpException import org.onap.cps.spi.exceptions.AlreadyDefinedException import org.onap.cps.spi.exceptions.DataValidationException import org.onap.cps.spi.exceptions.SchemaSetNotFoundException +import org.onap.cps.spi.model.Dataspace import org.springframework.boot.SpringApplication import org.slf4j.LoggerFactory import org.springframework.boot.context.event.ApplicationReadyEvent @@ -73,9 +74,15 @@ class SubscriptionModelLoaderSpec extends Specification { } def 'Onboard subscription model successfully via application ready event'() { - when:'model loader is enabled' + given: 'dataspace is ready for use' + mockCpsAdminService.getDataspace('NCMP-Admin') >> new Dataspace('NCMP-Admin') + and:'model loader is enabled' objectUnderTest.subscriptionModelLoaderEnabled = true - and: 'the application is ready' + and: 'maximum attempt count is set' + objectUnderTest.maximumAttemptCount = 20 + and: 'retry time is set' + objectUnderTest.retryTimeMs = 100 + when: 'the application is ready' objectUnderTest.onApplicationEvent(applicationReadyEvent) then: 'the module service to create schema set is called once' 1 * mockCpsModuleService.createSchemaSet('NCMP-Admin', 'subscriptions',sampleYangContentMap) @@ -90,6 +97,8 @@ class SubscriptionModelLoaderSpec extends Specification { objectUnderTest.subscriptionModelLoaderEnabled = false and: 'application is ready' objectUnderTest.onApplicationEvent(applicationReadyEvent) + and: 'dataspace is ready for use' + mockCpsAdminService.getDataspace('NCMP-Admin') >> new Dataspace('NCMP-Admin') then: 'the module service to create schema set was not called' 0 * mockCpsModuleService.createSchemaSet(*_) and: 'the admin service to create an anchor set was not called' @@ -98,11 +107,34 @@ class SubscriptionModelLoaderSpec extends Specification { 0 * mockCpsDataService.saveData(*_) } + def 'Onboard subscription model fails as NCMP dataspace does not exist' () { + given: 'model loader is enabled' + objectUnderTest.subscriptionModelLoaderEnabled = true + and: 'maximum attempt count is set' + objectUnderTest.maximumAttemptCount = 20 + and: 'retry time is set' + objectUnderTest.retryTimeMs = 100 + when: 'the application is ready' + objectUnderTest.onApplicationEvent(applicationReadyEvent) + then: 'the module service to create schema set was not called' + 0 * mockCpsModuleService.createSchemaSet(*_) + and: 'the admin service to create an anchor set was not called' + 0 * mockCpsAdminService.createAnchor(*_) + and: 'the data service to create a top level datanode was not called' + 0 * mockCpsDataService.saveData(*_) + and: 'the log message contains the correct exception message' + def logs = appender.list.toString() + assert logs.contains("Retrieval of NCMP dataspace fails") + } + + def 'Exception occurred while schema set creation' () { given: 'creating a schema set throws an exception' mockCpsModuleService.createSchemaSet(*_) >> { throw new DataValidationException(*_) } and: 'model loader is enabled' objectUnderTest.subscriptionModelLoaderEnabled = true + and: 'dataspace is ready for use' + mockCpsAdminService.getDataspace('NCMP-Admin') >> new Dataspace('NCMP-Admin') when: 'application is ready' objectUnderTest.onApplicationEvent(applicationReadyEvent) then: 'the admin service to create an anchor set was not called' diff --git a/cps-ncmp-service/src/test/resources/application.yml b/cps-ncmp-service/src/test/resources/application.yml index e66f23d23f..679248ba86 100644 --- a/cps-ncmp-service/src/test/resources/application.yml +++ b/cps-ncmp-service/src/test/resources/application.yml @@ -35,4 +35,11 @@ ncmp: parallelism-level: 3 model-loader: - subscription: true
\ No newline at end of file + subscription: true + +# Custom Hazelcast Config. +hazelcast: + mode: + kubernetes: + enabled: false + service-name: "cps-and-ncmp-service"
\ No newline at end of file |