79becb34543292817b70aebeddd9dbc8e2302d74
[cps.git] /
1 /*
2  * ============LICENSE_START=======================================================
3  * Copyright (c) 2024-2025 OpenInfra Foundation Europe. All rights reserved.
4  *  ================================================================================
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *        http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an 'AS IS' BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  *  SPDX-License-Identifier: Apache-2.0
18  *  ============LICENSE_END=========================================================
19  */
20
21 package org.onap.cps.ncmp.impl.datajobs.subscription.ncmp
22
23
24 import org.onap.cps.ncmp.impl.datajobs.subscription.client_to_ncmp.DataSelector
25 import org.onap.cps.ncmp.impl.datajobs.subscription.ncmp_to_dmi.DataJobSubscriptionDmiInEvent
26 import org.onap.cps.ncmp.impl.datajobs.subscription.dmi.DmiInEventMapper
27 import org.onap.cps.ncmp.impl.datajobs.subscription.dmi.EventProducer
28 import org.onap.cps.ncmp.impl.datajobs.subscription.utils.CmDataJobSubscriptionPersistenceService
29 import org.onap.cps.ncmp.impl.inventory.InventoryPersistence
30 import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle
31 import org.onap.cps.ncmp.impl.utils.AlternateIdMatcher
32 import org.onap.cps.ncmp.impl.utils.JexParser
33 import spock.lang.Specification
34
35 class CmSubscriptionHandlerImplSpec extends Specification {
36
37     def mockCmSubscriptionPersistenceService = Mock(CmDataJobSubscriptionPersistenceService)
38     def mockDmiInEventMapper = Mock(DmiInEventMapper)
39     def mockDmiInEventProducer = Mock(EventProducer)
40     def mockInventoryPersistence = Mock(InventoryPersistence)
41     def mockAlternateIdMatcher = Mock(AlternateIdMatcher)
42
43     def objectUnderTest = new CmSubscriptionHandlerImpl(mockCmSubscriptionPersistenceService, mockDmiInEventMapper,
44         mockDmiInEventProducer, mockInventoryPersistence, mockAlternateIdMatcher)
45
46     def 'Process subscription CREATE request for new target [non existing]'() {
47         given: 'relevant subscription details'
48             def mySubId = 'dataJobId'
49             def myDataNodeSelectors = ['/parent[id="1"]'].toList()
50             def notificationTypes = []
51             def notificationFilter = ''
52             def dataSelector = new DataSelector(notificationTypes: notificationTypes, notificationFilter: notificationFilter)
53         and: 'alternate Id matcher returns cm handle id for given data node selector'
54             def fdn = getFdn(myDataNodeSelectors.iterator().next())
55             mockAlternateIdMatcher.getCmHandleId(fdn) >> 'myCmHandleId'
56         and: 'returns inactive data node selector(s)'
57             mockCmSubscriptionPersistenceService.getInactiveDataNodeSelectors(mySubId) >> ['/parent[id="1"]']
58         and: 'the inventory persistence service returns cm handle'
59             mockInventoryPersistence.getYangModelCmHandle('myCmHandleId') >> new YangModelCmHandle(dmiServiceName: 'myDmiService')
60         and: 'DMI in event mapper returns event'
61             def myDmiInEvent = new DataJobSubscriptionDmiInEvent()
62             mockDmiInEventMapper.toDmiInEvent(['myCmHandleId'], myDataNodeSelectors, notificationTypes, notificationFilter) >> myDmiInEvent
63         when: 'the method to process subscription create request is called'
64             objectUnderTest.processSubscriptionCreate(dataSelector, mySubId, myDataNodeSelectors)
65         then: 'the persistence service is called'
66             1 * mockCmSubscriptionPersistenceService.add(mySubId, '/parent[id="1"]')
67         and: 'the event is sent to correct DMI'
68             1 * mockDmiInEventProducer.send(mySubId, 'myDmiService', 'subscriptionCreateRequest', _)
69     }
70
71     def 'Process subscription CREATE request for new targets [non existing] to be sent to multiple DMIs'() {
72         given: 'relevant subscription details'
73             def mySubId = 'dataJobId'
74             def myDataNodeSelectors = [
75                 '/parent[id="forDmi1"]',
76                 '/parent[id="forDmi1"]/child',
77                 '/parent[id="forDmi2"]'].toList()
78             def someAttr1 = []
79             def someAttr2 = ''
80             def dataSelector = new DataSelector(notificationTypes: someAttr1, notificationFilter: someAttr2)
81         and: 'alternate Id matcher returns cm handle ids for given data node selectors'
82             def fdn1 = getFdn(myDataNodeSelectors.get(0))
83             def fdn2 = getFdn(myDataNodeSelectors.get(1))
84             def fdn3 = getFdn(myDataNodeSelectors.get(2))
85             mockAlternateIdMatcher.getCmHandleId(fdn1) >> 'myCmHandleId1'
86             mockAlternateIdMatcher.getCmHandleId(fdn2) >> 'myCmHandleId1'
87             mockAlternateIdMatcher.getCmHandleId(fdn3) >> 'myCmHandleId2'
88         and: 'returns inactive data node selector(s)'
89             mockCmSubscriptionPersistenceService.getInactiveDataNodeSelectors(mySubId) >> [
90                 '/parent[id="forDmi1"]',
91                 '/parent[id="forDmi1"]/child',
92                 '/parent[id="forDmi2"]']
93         and: 'the inventory persistence service returns cm handles with dmi information'
94             mockInventoryPersistence.getYangModelCmHandle('myCmHandleId1') >> new YangModelCmHandle(dmiServiceName: 'myDmiService1')
95             mockInventoryPersistence.getYangModelCmHandle('myCmHandleId2') >> new YangModelCmHandle(dmiServiceName: 'myDmiService2')
96         and: 'DMI in event mapper returns events'
97             def myDmiInEvent1 = new DataJobSubscriptionDmiInEvent()
98             def myDmiInEvent2 = new DataJobSubscriptionDmiInEvent()
99             mockDmiInEventMapper.toDmiInEvent(['myCmHandleId1'], ['/parent[id="forDmi1"]', '/parent[id="forDmi1"]/child'], someAttr1, someAttr2) >> myDmiInEvent1
100             mockDmiInEventMapper.toDmiInEvent(['myCmHandleId2'], ['/parent[id="forDmi2"]'], someAttr1, someAttr2) >> myDmiInEvent2
101         when: 'the method to process subscription create request is called'
102             objectUnderTest.processSubscriptionCreate(dataSelector, mySubId, myDataNodeSelectors)
103         then: 'the persistence service is called'
104             myDataNodeSelectors.each { dataNodeSelector ->
105                 1 * mockCmSubscriptionPersistenceService.add(_, dataNodeSelector)}
106         and: 'the event is sent to correct DMIs'
107             1 * mockDmiInEventProducer.send(mySubId, 'myDmiService1', 'subscriptionCreateRequest', myDmiInEvent1)
108             1 * mockDmiInEventProducer.send(mySubId, 'myDmiService2', 'subscriptionCreateRequest', myDmiInEvent2)
109     }
110
111     def 'Process subscription CREATE request for overlapping targets [non existing & existing]'() {
112         given: 'relevant subscription details'
113             def myNewSubId = 'newId'
114             def myDataNodeSelectors = ['/newDataNodeSelector[id=""]'].toList()
115             def dataSelector = new DataSelector(notificationTypes: [], notificationFilter: '')
116         and: 'alternate id matcher always returns a cm handle id'
117             mockAlternateIdMatcher.getCmHandleId(_) >> 'someCmHandleId'
118         and: 'the inventory persistence service returns cm handles with dmi information'
119             mockInventoryPersistence.getYangModelCmHandle(_) >> new YangModelCmHandle(dmiServiceName: 'myDmiService')
120         and: 'returns inactive data node selector(s)'
121             mockCmSubscriptionPersistenceService.getInactiveDataNodeSelectors(myNewSubId) >> inactiveDataNodeSelectors
122         when: 'the method to process subscription create request is called'
123             objectUnderTest.processSubscriptionCreate(dataSelector, myNewSubId, myDataNodeSelectors)
124         then: 'the persistence service is called'
125             1 * mockCmSubscriptionPersistenceService.add(_, myDataNodeSelectors.iterator().next())
126         and: 'the event is sent to correct DMIs'
127             expectedCallsToDmi * mockDmiInEventProducer.send(myNewSubId, 'myDmiService', 'subscriptionCreateRequest', _)
128         where: 'following data are used'
129             scenario                                           | inactiveDataNodeSelectors                                         || expectedCallsToDmi
130             'new target overlaps with ACCEPTED targets'        | []                                                                || 0
131             'new target overlaps with REJECTED targets'        | ['/existingDataNodeSelector[id=""]','/newDataNodeSelector[id=""]']|| 1
132             'new target overlaps with UNKNOWN targets'         | ['/existingDataNodeSelector[id=""]','/newDataNodeSelector[id=""]']|| 1
133             'new target does not overlap with existing targets'| ['/newDataNodeSelector[id=""]']                                   || 1
134     }
135
136     def getFdn(dataNodeSelector) {
137         return JexParser.extractFdnPrefix(dataNodeSelector).orElse("")
138     }
139 }