diff options
Diffstat (limited to 'cps-service/src/test')
4 files changed, 223 insertions, 9 deletions
diff --git a/cps-service/src/test/groovy/org/onap/cps/events/CpsDataUpdateEventsServiceSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/events/CpsDataUpdateEventsServiceSpec.groovy index 5dee8fc28b..6d9ff12060 100644 --- a/cps-service/src/test/groovy/org/onap/cps/events/CpsDataUpdateEventsServiceSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/events/CpsDataUpdateEventsServiceSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2024 TechMahindra Ltd. + * Copyright (C) 2024-2025 TechMahindra Ltd. * Copyright (C) 2024 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,6 +25,7 @@ import static org.onap.cps.events.model.Data.Operation.CREATE import static org.onap.cps.events.model.Data.Operation.DELETE import static org.onap.cps.events.model.Data.Operation.UPDATE +import org.onap.cps.api.CpsNotificationService import com.fasterxml.jackson.databind.ObjectMapper import io.cloudevents.CloudEvent import io.cloudevents.core.CloudEventUtils @@ -41,8 +42,13 @@ import java.time.OffsetDateTime class CpsDataUpdateEventsServiceSpec extends Specification { def mockEventsPublisher = Mock(EventsPublisher) def objectMapper = new ObjectMapper(); + def mockCpsNotificationService = Mock(CpsNotificationService) - def objectUnderTest = new CpsDataUpdateEventsService(mockEventsPublisher) + def objectUnderTest = new CpsDataUpdateEventsService(mockEventsPublisher, mockCpsNotificationService) + + def setup() { + mockCpsNotificationService.isNotificationEnabled('dataspace01', 'anchor01') >> true + } def 'Create and Publish cps update event where events are #scenario'() { given: 'an anchor, operation and observed timestamp' diff --git a/cps-service/src/test/groovy/org/onap/cps/impl/CpsNotificationServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/impl/CpsNotificationServiceImplSpec.groovy new file mode 100644 index 0000000000..0f563272d1 --- /dev/null +++ b/cps-service/src/test/groovy/org/onap/cps/impl/CpsNotificationServiceImplSpec.groovy @@ -0,0 +1,166 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2025 TechMahindra Ltd. + * ================================================================================ + * 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.impl + +import com.fasterxml.jackson.databind.ObjectMapper +import org.onap.cps.api.CpsAnchorService +import org.onap.cps.api.exceptions.DataNodeNotFoundException +import org.onap.cps.api.exceptions.DataValidationException +import org.onap.cps.api.model.Anchor +import org.onap.cps.api.parameters.FetchDescendantsOption; +import org.onap.cps.spi.CpsDataPersistenceService +import org.onap.cps.utils.JsonObjectMapper +import org.onap.cps.utils.PrefixResolver +import org.onap.cps.utils.YangParser +import org.onap.cps.TestUtils +import org.onap.cps.utils.YangParserHelper +import org.onap.cps.yang.TimedYangTextSchemaSourceSetBuilder +import org.onap.cps.yang.YangTextSchemaSourceSet +import org.onap.cps.yang.YangTextSchemaSourceSetBuilder +import org.springframework.test.context.ContextConfiguration + +import spock.lang.Specification + +@ContextConfiguration(classes = [ObjectMapper, JsonObjectMapper]) +class CpsNotificationServiceImplSpec extends Specification { + + def dataspaceName = 'CPS-Admin' + def anchorName = 'cps-notification-subscriptions' + def schemaSetName = 'cps-notification-subscriptions' + def anchor = new Anchor(anchorName, dataspaceName, schemaSetName) + + def mockCpsDataPersistenceService = Mock(CpsDataPersistenceService) + def mockCpsAnchorService = Mock(CpsAnchorService) + def mockYangTextSchemaSourceSetCache = Mock(YangTextSchemaSourceSetCache) + def mockTimedYangTextSchemaSourceSetBuilder = Mock(TimedYangTextSchemaSourceSetBuilder) + def yangParser = new YangParser(new YangParserHelper(), mockYangTextSchemaSourceSetCache, mockTimedYangTextSchemaSourceSetBuilder) + def mockPrefixResolver = Mock(PrefixResolver) + def objectUnderTest = new CpsNotificationServiceImpl(mockCpsAnchorService, mockCpsDataPersistenceService, yangParser, mockPrefixResolver) + + def 'add notification subscription for list of dataspaces'() { + given: 'details for notification subscription and subscription root node xpath' + def notificationSubscriptionAsjson = '{"dataspace":[{"name":"ds01"},{"name":"ds02"}]}' + def xpath = '/dataspaces' + and: 'schema set for given anchor and dataspace references notification subscription model' + setupSchemaSetMocks('cps-notification-subscriptions@2024-07-03.yang') + and: 'anchor is provided' + mockCpsAnchorService.getAnchor(dataspaceName, anchorName) >> anchor + when: 'create notification subscription is called' + objectUnderTest.createNotificationSubscription(notificationSubscriptionAsjson, xpath) + then: 'the persistence service is called once with the correct parameters' + 1 * mockCpsDataPersistenceService.addListElements('CPS-Admin', 'cps-notification-subscriptions', xpath, { dataNodeCollection -> + { + assert dataNodeCollection.size() == 2 + assert dataNodeCollection.collect { it.getXpath() } + .containsAll(['/dataspaces/dataspace[@name=\'ds01\']', '/dataspaces/dataspace[@name=\'ds02\']']) + } + }) + } + + def 'add notification subscription fails with exception'() { + given: 'details for notification subscription' + def jsonData = '{"dataspace":[{"name":"ds01"},{"name":"ds02"}]}' + and: 'schema set for given anchor and dataspace references invalid data model' + setupSchemaSetMocks('test-tree.yang') + and: 'anchor is provided' + mockCpsAnchorService.getAnchor(dataspaceName, anchorName) >> anchor + when: 'create notification subscription is called' + objectUnderTest.createNotificationSubscription(jsonData, '/somepath') + then: 'data validation exception is thrown ' + thrown(DataValidationException) + } + + def 'delete notification subscription for given xpath'() { + given: 'details for notification subscription' + def xpath = '/some/path' + when: 'delete notification subscription is called' + objectUnderTest.deleteNotificationSubscription(xpath) + then: 'the persistence service is called once with the correct parameters' + 1 * mockCpsDataPersistenceService.deleteDataNode(dataspaceName, anchorName, xpath) + } + + def 'get notification subscription for given xpath'() { + given: 'details for notification subscription' + def xpath = '/some/path' + and: 'persistence service returns data nodes for subscribed data' + mockCpsDataPersistenceService.getDataNodes(dataspaceName, anchorName, + xpath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> + [new DataNodeBuilder().withXpath('/some/path').withLeaves([leaf: 'dataspace', leafList: ['ds01', 'ds02']]).build()] + when: 'delete notification subscription is called' + def result = objectUnderTest.getNotificationSubscription(xpath) + then: 'the result is a json representation of the data node(s) returned by the data persistence service' + assert result.get(0).toString() == '{path={leaf=dataspace, leafList=[ds01, ds02]}}' + } + + def 'is notification enabled for given anchor'() { + given: 'data nodes available for given anchor' + mockCpsDataPersistenceService.getDataNodes(dataspaceName, anchorName, "/dataspaces", FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> + [new DataNodeBuilder().withXpath('/xpath-1').build()] + when: 'is notification enabled is called' + boolean isNotificationEnabled = objectUnderTest.isNotificationEnabled(dataspaceName, anchorName) + then: 'the notification is enabled' + assert isNotificationEnabled + } + + def 'is notification disabled for given anchor'() { + given: 'data nodes not available for given anchor' + mockCpsDataPersistenceService.getDataNodes(dataspaceName, anchorName, "/dataspaces/dataspace[@name='ds01']/anchors/anchor[@name='anchor-01']", FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> + { throw new DataNodeNotFoundException(dataspaceName, anchorName) } + when: 'is notification enabled is called' + boolean isNotificationEnabled = objectUnderTest.isNotificationEnabled('ds01', 'anchor-01') + then: 'the notification is disabled' + assert !isNotificationEnabled + } + + def 'is notification enabled for all anchors in a dataspace'() { + given: 'data nodes available for given dataspace' + mockCpsDataPersistenceService.getDataNodes(dataspaceName, anchorName, "/dataspaces/dataspace[@name='ds01']", FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> + [new DataNodeBuilder().withXpath('/xpath-1').build()] + and: 'data nodes not available for any specific anchor' + mockCpsDataPersistenceService.getDataNodes(dataspaceName, anchorName, "/dataspaces/dataspace[@name='ds01']/anchors", FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> + { throw new DataNodeNotFoundException(dataspaceName, anchorName) } + when: 'is notification enabled is called' + boolean isNotificationEnabled = objectUnderTest.notificationEnabledForAllAnchors('ds01') + then: 'the notification is enabled' + assert isNotificationEnabled + } + + def 'is notification disabled for all anchors in a dataspace'() { + given: 'data nodes available for given dataspace' + mockCpsDataPersistenceService.getDataNodes(dataspaceName, anchorName, "/dataspaces/dataspace[@name='ds01']", FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> + [new DataNodeBuilder().withXpath('/xpath-1').build()] + and: 'data nodes also available for any specific anchor' + mockCpsDataPersistenceService.getDataNodes(dataspaceName, anchorName, "/dataspaces/dataspace[@name='ds01']/anchors", FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> + [new DataNodeBuilder().withXpath('/xpath-1').build()] + when: 'is notification enabled is called' + boolean isNotificationEnabled = objectUnderTest.notificationEnabledForAllAnchors('ds01') + then: 'the notification is disabled' + assert !isNotificationEnabled + } + + def setupSchemaSetMocks(String... yangResources) { + def mockYangTextSchemaSourceSet = Mock(YangTextSchemaSourceSet) + mockYangTextSchemaSourceSetCache.get(dataspaceName, schemaSetName) >> mockYangTextSchemaSourceSet + def yangResourceNameToContent = TestUtils.getYangResourcesAsMap(yangResources) + def schemaContext = YangTextSchemaSourceSetBuilder.of(yangResourceNameToContent).getSchemaContext() + mockYangTextSchemaSourceSet.getSchemaContext() >> schemaContext + } +} diff --git a/cps-service/src/test/groovy/org/onap/cps/init/CpsNotificationSubscriptionModelLoaderSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/init/CpsNotificationSubscriptionModelLoaderSpec.groovy index 0d515f90ac..1e2dc54424 100644 --- a/cps-service/src/test/groovy/org/onap/cps/init/CpsNotificationSubscriptionModelLoaderSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/init/CpsNotificationSubscriptionModelLoaderSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2024 TechMahindra Ltd. + * Copyright (C) 2024-2025 TechMahindra Ltd. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -78,10 +78,4 @@ class CpsNotificationSubscriptionModelLoaderSpec extends Specification { and: 'the data service to create a top level datanode is called once' 1 * mockCpsDataService.saveData(CPS_DATASPACE_NAME, ANCHOR_NAME, '{"dataspaces":{}}', _) } - - private void assertLogContains(String message) { - def logs = loggingListAppender.list.toString() - assert logs.contains(message) - } - } diff --git a/cps-service/src/test/resources/cps-notification-subscriptions@2024-07-03.yang b/cps-service/src/test/resources/cps-notification-subscriptions@2024-07-03.yang new file mode 100644 index 0000000000..1cab7923ea --- /dev/null +++ b/cps-service/src/test/resources/cps-notification-subscriptions@2024-07-03.yang @@ -0,0 +1,48 @@ +module cps-notification-subscriptions { + yang-version 1.1; + namespace "org:onap:cps"; + + prefix cps-notification-subscriptions; + + revision "2024-08-05" { + description + "First release of cps notification subscriptions model"; + } + container dataspaces { + + list dataspace { + key "name"; + + leaf name { + type string; + } + + container anchors { + + list anchor { + key "name"; + + leaf name { + type string; + } + + container xpaths { + + list xpath { + key "path"; + leaf path { + type string; + } + } + } + } + } + leaf-list subscriptionIds { + type string; + } + leaf topic { + type string; + } + } + } +}
\ No newline at end of file |