2  *  ============LICENSE_START=======================================================
 
   3  *  Copyright (C) 2021-2024 Nordix Foundation
 
   4  *  Modifications Copyright (C) 2021 Pantheon.tech
 
   5  *  Modifications Copyright (C) 2021-2022 Bell Canada
 
   6  *  Modifications Copyright (C) 2023 TechMahindra Ltd.
 
   7  *  ================================================================================
 
   8  *  Licensed under the Apache License, Version 2.0 (the "License");
 
   9  *  you may not use this file except in compliance with the License.
 
  10  *  You may obtain a copy of the License at
 
  12  *        http://www.apache.org/licenses/LICENSE-2.0
 
  14  *  Unless required by applicable law or agreed to in writing, software
 
  15  *  distributed under the License is distributed on an "AS IS" BASIS,
 
  16  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
  17  *  See the License for the specific language governing permissions and
 
  18  *  limitations under the License.
 
  20  *  SPDX-License-Identifier: Apache-2.0
 
  21  *  ============LICENSE_END=========================================================
 
  24 package org.onap.cps.ncmp.impl.inventory
 
  26 import com.fasterxml.jackson.databind.ObjectMapper
 
  27 import org.onap.cps.ncmp.api.inventory.NetworkCmProxyInventoryFacade
 
  28 import org.onap.cps.ncmp.api.inventory.models.CmHandleQueryApiParameters
 
  29 import org.onap.cps.ncmp.api.inventory.models.CmHandleQueryServiceParameters
 
  30 import org.onap.cps.ncmp.api.inventory.models.CompositeState
 
  31 import org.onap.cps.ncmp.api.inventory.models.ConditionApiProperties
 
  32 import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistration
 
  33 import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle
 
  34 import org.onap.cps.ncmp.api.inventory.models.TrustLevel
 
  35 import org.onap.cps.ncmp.impl.inventory.models.CmHandleState
 
  36 import org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory
 
  37 import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle
 
  38 import org.onap.cps.ncmp.impl.inventory.trustlevel.TrustLevelManager
 
  39 import org.onap.cps.ncmp.impl.utils.AlternateIdMatcher
 
  40 import org.onap.cps.spi.model.ConditionProperties
 
  41 import org.onap.cps.utils.JsonObjectMapper
 
  42 import spock.lang.Specification
 
  44 class NetworkCmProxyInventoryFacadeSpec extends Specification {
 
  46     def mockCmHandleRegistrationService = Mock(CmHandleRegistrationService)
 
  47     def mockCmHandleQueryService = Mock(CmHandleQueryService)
 
  48     def mockParameterizedCmHandleQueryService = Mock(ParameterizedCmHandleQueryService)
 
  49     def spiedJsonObjectMapper = Spy(new JsonObjectMapper(new ObjectMapper()))
 
  50     def mockInventoryPersistence = Mock(InventoryPersistence)
 
  51     def mockTrustLevelManager = Mock(TrustLevelManager)
 
  52     def mockAlternateIdMatcher = Mock(AlternateIdMatcher)
 
  53     def objectUnderTest = new NetworkCmProxyInventoryFacade(mockCmHandleRegistrationService, mockCmHandleQueryService, mockParameterizedCmHandleQueryService, mockInventoryPersistence, spiedJsonObjectMapper, mockTrustLevelManager, mockAlternateIdMatcher)
 
  54     def trustLevelPerCmHandle = [:]
 
  56     def 'Update DMI Registration'() {
 
  57         given: 'an (updated) dmi plugin registration'
 
  58             def dmiPluginRegistration = Mock(DmiPluginRegistration)
 
  59         when: 'the registration is submitted '
 
  60            objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
 
  61         then: 'the call is delegated to the cm handle registration service'
 
  62             1 * mockCmHandleRegistrationService.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
 
  65     def 'Execute cm handle id search for inventory'() {
 
  66         given: 'a ConditionApiProperties object'
 
  67             def conditionProperties = new ConditionProperties()
 
  68             conditionProperties.conditionName = 'hasAllProperties'
 
  69             conditionProperties.conditionParameters = [ [ 'some-key' : 'some-value' ] ]
 
  70             def cmHandleQueryServiceParameters = new CmHandleQueryServiceParameters()
 
  71             cmHandleQueryServiceParameters.cmHandleQueryParameters = [conditionProperties] as List<ConditionProperties>
 
  72         and: 'the system returns an set of cmHandle ids'
 
  73             mockParameterizedCmHandleQueryService.queryCmHandleIdsForInventory(*_) >> [ 'cmHandle1', 'cmHandle2' ]
 
  74         when: 'executing the search'
 
  75             def result = objectUnderTest.executeParameterizedCmHandleIdSearch(cmHandleQueryServiceParameters)
 
  76         then: 'the result returns the correct 2 elements'
 
  77             assert result.size() == 2
 
  78             assert result.contains('cmHandle1')
 
  79             assert result.contains('cmHandle2')
 
  82     def 'Get all cm handle IDs by DMI plugin identifier.' () {
 
  83         given: 'cm handle queries service returns cm handles'
 
  84             1 * mockCmHandleQueryService.getCmHandleIdsByDmiPluginIdentifier('some-dmi-plugin-identifier') >> ['cm-handle-1','cm-handle-2']
 
  85         when: 'cm handle Ids are requested with dmi plugin identifier'
 
  86             def result = objectUnderTest.getAllCmHandleIdsByDmiPluginIdentifier('some-dmi-plugin-identifier')
 
  87         then: 'the result size is correct'
 
  88             assert result.size() == 2
 
  89         and: 'the result returns the correct details'
 
  90             assert result.containsAll('cm-handle-1','cm-handle-2')
 
  93     def 'Getting Yang Resources.'() {
 
  94         when: 'yang resources is called'
 
  95             objectUnderTest.getYangResourcesModuleReferences('some-cm-handle')
 
  96         then: 'CPS module services is invoked for the correct dataspace and cm handle'
 
  97             1 * mockInventoryPersistence.getYangResourcesModuleReferences('some-cm-handle')
 
 100     def 'Get a cm handle.'() {
 
 101         given: 'the system returns a yang modelled cm handle'
 
 102             def dmiServiceName = 'some service name'
 
 103             def compositeState = new CompositeState(cmHandleState: CmHandleState.ADVISED,
 
 104                 lockReason: CompositeState.LockReason.builder().lockReasonCategory(LockReasonCategory.MODULE_SYNC_FAILED).details('lock details').build(),
 
 105                 lastUpdateTime: 'some-timestamp',
 
 106                 dataSyncEnabled: false,
 
 107                 dataStores: dataStores())
 
 108             def dmiProperties = [new YangModelCmHandle.Property('Book', 'Romance Novel')]
 
 109             def publicProperties = [new YangModelCmHandle.Property('Public Book', 'Public Romance Novel')]
 
 110             def moduleSetTag = 'some-module-set-tag'
 
 111             def alternateId = 'some-alternate-id'
 
 112             def yangModelCmHandle = new YangModelCmHandle(id: 'ch-1', dmiServiceName: dmiServiceName, dmiProperties: dmiProperties,
 
 113                  publicProperties: publicProperties, compositeState: compositeState, moduleSetTag: moduleSetTag, alternateId: alternateId)
 
 114             1 * mockInventoryPersistence.getYangModelCmHandle('ch-1') >> yangModelCmHandle
 
 115         and: 'a trust level for the cm handle in the cache'
 
 116             mockTrustLevelManager.getEffectiveTrustLevel(*_) >> TrustLevel.COMPLETE
 
 117         when: 'getting cm handle details for a given cm handle id from ncmp service'
 
 118             def result = objectUnderTest.getNcmpServiceCmHandle('ch-1')
 
 119         then: 'the result is a ncmpServiceCmHandle'
 
 120             assert result.class == NcmpServiceCmHandle.class
 
 121         and: 'the cm handle contains the cm handle id'
 
 122             assert result.cmHandleId == 'ch-1'
 
 123         and: 'the cm handle contains the alternate id'
 
 124             assert result.alternateId == 'some-alternate-id'
 
 125         and: 'the cm handle contains the module-set-tag'
 
 126             assert result.moduleSetTag == 'some-module-set-tag'
 
 127         and: 'the cm handle contains the DMI Properties'
 
 128             assert result.dmiProperties ==[ Book:'Romance Novel' ]
 
 129         and: 'the cm handle contains the public Properties'
 
 130             assert result.publicProperties == [ "Public Book":'Public Romance Novel' ]
 
 131         and: 'the cm handle contains the cm handle composite state'
 
 132             assert result.compositeState == compositeState
 
 133         and: 'the cm handle contains the trust level from the cache'
 
 134             assert result.currentTrustLevel == TrustLevel.COMPLETE
 
 137     def 'Get cm handle public properties'() {
 
 138         given: 'a yang modelled cm handle'
 
 139             def dmiProperties = [new YangModelCmHandle.Property('prop', 'some DMI property')]
 
 140             def publicProperties = [new YangModelCmHandle.Property('public prop', 'some public prop')]
 
 141             def yangModelCmHandle = new YangModelCmHandle(id:'some-cm-handle', dmiServiceName: 'some service name', dmiProperties: dmiProperties, publicProperties: publicProperties)
 
 142         and: 'the system returns this yang modelled cm handle'
 
 143             1 * mockInventoryPersistence.getYangModelCmHandle('some-cm-handle') >> yangModelCmHandle
 
 144         when: 'getting cm handle public properties for a given cm handle id from ncmp service'
 
 145             def result = objectUnderTest.getCmHandlePublicProperties('some-cm-handle')
 
 146         then: 'the result returns the correct data'
 
 147             assert result == [ 'public prop' : 'some public prop' ]
 
 150     def 'Get cm handle composite state using #scenario'() {
 
 151         given: 'a yang modelled cm handle'
 
 152             def compositeState = new CompositeState(cmHandleState: CmHandleState.ADVISED,
 
 153                 lockReason: CompositeState.LockReason.builder().lockReasonCategory(LockReasonCategory.MODULE_SYNC_FAILED).details("lock details").build(),
 
 154                 lastUpdateTime: 'some-timestamp',
 
 155                 dataSyncEnabled: false,
 
 156                 dataStores: dataStores())
 
 157             def dmiProperties = [new YangModelCmHandle.Property('prop', 'some DMI property')]
 
 158             def publicProperties = [new YangModelCmHandle.Property('public prop', 'some public prop')]
 
 159             def cmHandleId = 'some-cm-handle'
 
 160             def alternateId = 'some-alternate-id'
 
 161             def yangModelCmHandle = new YangModelCmHandle(id:cmHandleId, alternateId: alternateId, dmiServiceName: 'some service name', dmiProperties: dmiProperties, publicProperties: publicProperties, compositeState: compositeState)
 
 162         and: 'we have corresponding cm handle for the cm handle reference'
 
 163             1 * mockAlternateIdMatcher.getCmHandleId(cmHandleRef) >> cmHandleId
 
 164         and: 'the system returns this yang modelled cm handle'
 
 165             1 * mockInventoryPersistence.getYangModelCmHandle(cmHandleId) >> yangModelCmHandle
 
 166         when: 'getting cm handle composite state for a given cm handle id from ncmp service'
 
 167             def result = objectUnderTest.getCmHandleCompositeState(cmHandleRef)
 
 168         then: 'the result returns the correct data'
 
 169             assert result == compositeState
 
 170         where: 'following cm handle reference is used'
 
 171             scenario                              | cmHandleRef
 
 172             'Cm Handle Reference as cm handle-id' | 'some-cm-handle'
 
 173             'Cm Handle Reference as alternate-id' | 'some-alternate-id'
 
 176     def 'Execute cm handle id search'() {
 
 177         given: 'valid CmHandleQueryApiParameters input'
 
 178             def cmHandleQueryApiParameters = new CmHandleQueryApiParameters()
 
 179             def conditionApiProperties = new ConditionApiProperties()
 
 180             conditionApiProperties.conditionName = 'hasAllModules'
 
 181             conditionApiProperties.conditionParameters = [[moduleName: 'module-name-1']]
 
 182             cmHandleQueryApiParameters.cmHandleQueryParameters = [conditionApiProperties]
 
 183         and: 'query cm handle method return with a data node list'
 
 184             mockParameterizedCmHandleQueryService.queryCmHandleIds(
 
 185                 spiedJsonObjectMapper.convertToValueType(cmHandleQueryApiParameters, CmHandleQueryServiceParameters.class))
 
 186                 >> ['cm-handle-id-1']
 
 187         when: 'execute cm handle search is called'
 
 188             def result = objectUnderTest.executeCmHandleIdSearch(cmHandleQueryApiParameters)
 
 189         then: 'result is the same collection as returned by the CPS Data Service'
 
 190             assert result == ['cm-handle-id-1']
 
 193     def 'Getting module definitions by module'() {
 
 194         when: 'get module definitions is performed with module name'
 
 195             objectUnderTest.getModuleDefinitionsByCmHandleAndModule('some-cm-handle', 'some-module', '2021-08-04')
 
 196         then: 'ncmp inventory persistence service is invoked once with correct parameters'
 
 197             1 * mockInventoryPersistence.getModuleDefinitionsByCmHandleAndModule('some-cm-handle', 'some-module', '2021-08-04')
 
 200     def 'Getting module definitions by cm handle id'() {
 
 201         when: 'get module definitions is performed with cm handle id'
 
 202             objectUnderTest.getModuleDefinitionsByCmHandleId('some-cm-handle')
 
 203         then: 'ncmp inventory persistence service is invoked once with correct parameter'
 
 204             1 * mockInventoryPersistence.getModuleDefinitionsByCmHandleId('some-cm-handle')
 
 207     def 'Execute cm handle search'() {
 
 208         given: 'valid CmHandleQueryApiParameters input'
 
 209             def cmHandleQueryApiParameters = new CmHandleQueryApiParameters()
 
 210             def conditionApiProperties = new ConditionApiProperties()
 
 211             conditionApiProperties.conditionName = 'hasAllModules'
 
 212             conditionApiProperties.conditionParameters = [[moduleName: 'module-name-1']]
 
 213             cmHandleQueryApiParameters.cmHandleQueryParameters = [conditionApiProperties]
 
 214         and: 'query cm handle method returns two cm handles'
 
 215             mockParameterizedCmHandleQueryService.queryCmHandles(
 
 216                 spiedJsonObjectMapper.convertToValueType(cmHandleQueryApiParameters, CmHandleQueryServiceParameters.class))
 
 217                 >> [new YangModelCmHandle(id: 'ch-0', dmiProperties: [], publicProperties: []),
 
 218                     new YangModelCmHandle(id: 'ch-1', dmiProperties: [], publicProperties: [])]
 
 219         and: 'a trust level for cm handles'
 
 220             mockTrustLevelManager.getEffectiveTrustLevel(*_) >> TrustLevel.COMPLETE
 
 221         when: 'execute cm handle search is called'
 
 222             def result = objectUnderTest.executeCmHandleSearch(cmHandleQueryApiParameters)
 
 223         then: 'result consists of the two cm handles returned by the CPS Data Service'
 
 224             assert result.size() == 2
 
 225             assert result[0].cmHandleId == 'ch-0'
 
 226             assert result[1].cmHandleId == 'ch-1'
 
 227         and: 'cm handles have trust level'
 
 228             assert result[0].currentTrustLevel == TrustLevel.COMPLETE
 
 229             assert result[1].currentTrustLevel == TrustLevel.COMPLETE
 
 232     def 'Set Cm Handle Data Sync flag.'() {
 
 233         when: 'setting data sync enabled flag'
 
 234             objectUnderTest.setDataSyncEnabled('ch-1',true)
 
 235         then: 'call is delegated to the cm handle registration service'
 
 236             mockCmHandleRegistrationService.setDataSyncEnabled('ch-1', true)
 
 240         CompositeState.DataStores.builder().operationalDataStore(CompositeState.Operational.builder()
 
 241                 .dataStoreSyncState(DataStoreSyncState.NONE_REQUESTED)
 
 242                 .lastSyncTime('some-timestamp').build()).build()