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)
 
  55     def 'Update DMI Registration'() {
 
  56         given: 'an (updated) dmi plugin registration'
 
  57             def dmiPluginRegistration = Mock(DmiPluginRegistration)
 
  58         when: 'the registration is submitted '
 
  59            objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
 
  60         then: 'the call is delegated to the cm handle registration service'
 
  61             1 * mockCmHandleRegistrationService.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
 
  64     def 'Execute cm handle id search for inventory'() {
 
  65         given: 'a ConditionApiProperties object'
 
  66             def conditionProperties = new ConditionProperties()
 
  67             conditionProperties.conditionName = 'hasAllProperties'
 
  68             conditionProperties.conditionParameters = [ [ 'some-key' : 'some-value' ] ]
 
  69             def cmHandleQueryServiceParameters = new CmHandleQueryServiceParameters()
 
  70             cmHandleQueryServiceParameters.cmHandleQueryParameters = [conditionProperties] as List<ConditionProperties>
 
  71         and: 'the system returns an set of cmHandle ids'
 
  72             mockParameterizedCmHandleQueryService.queryCmHandleIdsForInventory(*_) >> [ 'cmHandle1', 'cmHandle2' ]
 
  73         when: 'executing the search'
 
  74             def result = objectUnderTest.executeParameterizedCmHandleIdSearch(cmHandleQueryServiceParameters)
 
  75         then: 'the result returns the correct 2 elements'
 
  76             assert result.size() == 2
 
  77             assert result.contains('cmHandle1')
 
  78             assert result.contains('cmHandle2')
 
  81     def 'Get all cm handle IDs by DMI plugin identifier.' () {
 
  82         given: 'cm handle queries service returns cm handles'
 
  83             1 * mockCmHandleQueryService.getCmHandleIdsByDmiPluginIdentifier('some-dmi-plugin-identifier') >> ['cm-handle-1','cm-handle-2']
 
  84         when: 'cm handle Ids are requested with dmi plugin identifier'
 
  85             def result = objectUnderTest.getAllCmHandleIdsByDmiPluginIdentifier('some-dmi-plugin-identifier')
 
  86         then: 'the result size is correct'
 
  87             assert result.size() == 2
 
  88         and: 'the result returns the correct details'
 
  89             assert result.containsAll('cm-handle-1','cm-handle-2')
 
  92     def 'Getting Yang Resources for a given #scenario'() {
 
  93         when: 'yang resources is called'
 
  94             objectUnderTest.getYangResourcesModuleReferences(cmHandleRef)
 
  95         then: 'alternate id matcher is called'
 
  96             mockAlternateIdMatcher.getCmHandleId(cmHandleRef) >> 'some-cm-handle'
 
  97         and: 'CPS module services is invoked for the correct cm handle'
 
  98             1 * mockInventoryPersistence.getYangResourcesModuleReferences('some-cm-handle')
 
  99         where: 'following cm handle reference is used'
 
 100             scenario                              | cmHandleRef
 
 101             'Cm Handle Reference as cm handle-id' | 'some-cm-handle'
 
 102             'Cm Handle Reference as alternate-id' | 'some-alternate-id'
 
 105     def 'Get a cm handle details using #scenario'() {
 
 106         given: 'the system returns a yang modelled cm handle'
 
 107             def dmiServiceName = 'some service name'
 
 108             def compositeState = new CompositeState(cmHandleState: CmHandleState.ADVISED,
 
 109                 lockReason: CompositeState.LockReason.builder().lockReasonCategory(LockReasonCategory.MODULE_SYNC_FAILED).details('lock details').build(),
 
 110                 lastUpdateTime: 'some-timestamp',
 
 111                 dataSyncEnabled: false,
 
 112                 dataStores: dataStores())
 
 113             def dmiProperties = [new YangModelCmHandle.Property('Book', 'Romance Novel')]
 
 114             def publicProperties = [new YangModelCmHandle.Property('Public Book', 'Public Romance Novel')]
 
 115             def moduleSetTag = 'some-module-set-tag'
 
 116             def alternateId = 'some-alternate-id'
 
 117             def yangModelCmHandle = new YangModelCmHandle(id: 'some-cm-handle', dmiServiceName: dmiServiceName, dmiProperties: dmiProperties,
 
 118                  publicProperties: publicProperties, compositeState: compositeState, moduleSetTag: moduleSetTag, alternateId: alternateId)
 
 119             mockAlternateIdMatcher.getCmHandleId(cmHandleRef) >> 'some-cm-handle'
 
 120             1 * mockInventoryPersistence.getYangModelCmHandle('some-cm-handle') >> yangModelCmHandle
 
 121         and: 'a trust level for the cm handle in the cache'
 
 122             mockTrustLevelManager.getEffectiveTrustLevel(*_) >> TrustLevel.COMPLETE
 
 123         when: 'getting cm handle details for a given cm handle id from ncmp service'
 
 124             def result = objectUnderTest.getNcmpServiceCmHandle(cmHandleRef)
 
 125         then: 'the result is a ncmpServiceCmHandle'
 
 126             assert result.class == NcmpServiceCmHandle.class
 
 127         and: 'the cm handle contains the cm handle id'
 
 128             assert result.cmHandleId == 'some-cm-handle'
 
 129         and: 'the cm handle contains the alternate id'
 
 130             assert result.alternateId == 'some-alternate-id'
 
 131         and: 'the cm handle contains the module-set-tag'
 
 132             assert result.moduleSetTag == 'some-module-set-tag'
 
 133         and: 'the cm handle contains the DMI Properties'
 
 134             assert result.dmiProperties ==[ Book:'Romance Novel' ]
 
 135         and: 'the cm handle contains the public Properties'
 
 136             assert result.publicProperties == [ "Public Book":'Public Romance Novel' ]
 
 137         and: 'the cm handle contains the cm handle composite state'
 
 138             assert result.compositeState == compositeState
 
 139         and: 'the cm handle contains the trust level from the cache'
 
 140             assert result.currentTrustLevel == TrustLevel.COMPLETE
 
 141         where: 'following cm handle reference is used'
 
 142             scenario                              | cmHandleRef
 
 143             'Cm Handle Reference as cm handle-id' | 'some-cm-handle'
 
 144             'Cm Handle Reference as alternate-id' | 'some-alternate-id'
 
 147     def 'Get cm handle public properties using #scenario'() {
 
 148         given: 'a yang modelled cm handle'
 
 149             def dmiProperties = [new YangModelCmHandle.Property('prop', 'some DMI property')]
 
 150             def publicProperties = [new YangModelCmHandle.Property('public prop', 'some public prop')]
 
 151             def cmHandleId = 'some-cm-handle'
 
 152             def alternateId = 'some-alternate-id'
 
 153             def yangModelCmHandle = new YangModelCmHandle(id:cmHandleId, alternateId: alternateId, dmiServiceName: 'some service name', dmiProperties: dmiProperties, publicProperties: publicProperties)
 
 154         and: 'we have corresponding cm handle for the cm handle reference'
 
 155             1 * mockAlternateIdMatcher.getCmHandleId(cmHandleRef) >> cmHandleId
 
 156         and: 'the system returns this yang modelled cm handle'
 
 157             1 * mockInventoryPersistence.getYangModelCmHandle(cmHandleId) >> yangModelCmHandle
 
 158         when: 'getting cm handle public properties for a given cm handle reference from ncmp service'
 
 159             def result = objectUnderTest.getCmHandlePublicProperties(cmHandleRef)
 
 160         then: 'the result returns the correct data'
 
 161             assert result == [ 'public prop' : 'some public prop' ]
 
 162         where: 'following cm handle reference is used'
 
 163             scenario                              | cmHandleRef
 
 164             'Cm Handle Reference as cm handle-id' | 'some-cm-handle'
 
 165             'Cm Handle Reference as alternate-id' | 'some-alternate-id'
 
 168     def 'Get cm handle composite state using #scenario'() {
 
 169         given: 'a yang modelled cm handle'
 
 170             def compositeState = new CompositeState(cmHandleState: CmHandleState.ADVISED,
 
 171                 lockReason: CompositeState.LockReason.builder().lockReasonCategory(LockReasonCategory.MODULE_SYNC_FAILED).details("lock details").build(),
 
 172                 lastUpdateTime: 'some-timestamp',
 
 173                 dataSyncEnabled: false,
 
 174                 dataStores: dataStores())
 
 175             def dmiProperties = [new YangModelCmHandle.Property('prop', 'some DMI property')]
 
 176             def publicProperties = [new YangModelCmHandle.Property('public prop', 'some public prop')]
 
 177             def cmHandleId = 'some-cm-handle'
 
 178             def alternateId = 'some-alternate-id'
 
 179             def yangModelCmHandle = new YangModelCmHandle(id:cmHandleId, alternateId: alternateId, dmiServiceName: 'some service name', dmiProperties: dmiProperties, publicProperties: publicProperties, compositeState: compositeState)
 
 180         and: 'we have corresponding cm handle for the cm handle reference'
 
 181             1 * mockAlternateIdMatcher.getCmHandleId(cmHandleRef) >> cmHandleId
 
 182         and: 'the system returns this yang modelled cm handle'
 
 183             1 * mockInventoryPersistence.getYangModelCmHandle(cmHandleId) >> yangModelCmHandle
 
 184         when: 'getting cm handle composite state for a given cm handle id from ncmp service'
 
 185             def result = objectUnderTest.getCmHandleCompositeState(cmHandleRef)
 
 186         then: 'the result returns the correct data'
 
 187             assert result == compositeState
 
 188         where: 'following cm handle reference is used'
 
 189             scenario                              | cmHandleRef
 
 190             'Cm Handle Reference as cm handle-id' | 'some-cm-handle'
 
 191             'Cm Handle Reference as alternate-id' | 'some-alternate-id'
 
 194     def 'Execute cm handle id search'() {
 
 195         given: 'valid CmHandleQueryApiParameters input'
 
 196             def cmHandleQueryApiParameters = new CmHandleQueryApiParameters()
 
 197             def conditionApiProperties = new ConditionApiProperties()
 
 198             conditionApiProperties.conditionName = 'hasAllModules'
 
 199             conditionApiProperties.conditionParameters = [[moduleName: 'module-name-1']]
 
 200             cmHandleQueryApiParameters.cmHandleQueryParameters = [conditionApiProperties]
 
 201         and: 'query cm handle method return with a data node list'
 
 202             mockParameterizedCmHandleQueryService.queryCmHandleIds(
 
 203                 spiedJsonObjectMapper.convertToValueType(cmHandleQueryApiParameters, CmHandleQueryServiceParameters.class))
 
 204                 >> ['cm-handle-id-1']
 
 205         when: 'execute cm handle search is called'
 
 206             def result = objectUnderTest.executeCmHandleIdSearch(cmHandleQueryApiParameters)
 
 207         then: 'result is the same collection as returned by the CPS Data Service'
 
 208             assert result == ['cm-handle-id-1']
 
 211     def 'Getting module definitions by module for a given #scenario'() {
 
 212         when: 'get module definitions is performed with module name and cm handle reference'
 
 213             objectUnderTest.getModuleDefinitionsByCmHandleAndModule(cmHandleRef, 'some-module', '2021-08-04')
 
 214         then: 'alternate id matcher returns some cm handle id for a given cm handle reference'
 
 215             mockAlternateIdMatcher.getCmHandleId(cmHandleRef) >> 'some-cm-handle'
 
 216         and: 'ncmp inventory persistence service is invoked once with correct parameters'
 
 217             1 * mockInventoryPersistence.getModuleDefinitionsByCmHandleAndModule('some-cm-handle', 'some-module', '2021-08-04')
 
 218         where: 'following cm handle reference is used'
 
 219             scenario                              | cmHandleRef
 
 220             'Cm Handle Reference as cm handle-id' | 'some-cm-handle'
 
 221             'Cm Handle Reference as alternate-id' | 'some-alternate-id'
 
 224     def 'Getting module definitions for a given #scenario'() {
 
 225         when: 'get module definitions is performed with cm handle reference'
 
 226             objectUnderTest.getModuleDefinitionsByCmHandleReference(cmHandleRef)
 
 227         then: 'alternate id matcher returns some cm handle id for a given cm handle reference'
 
 228             mockAlternateIdMatcher.getCmHandleId(cmHandleRef) >> 'some-cm-handle'
 
 229         then: 'ncmp inventory persistence service is invoked once with correct parameter'
 
 230             1 * mockInventoryPersistence.getModuleDefinitionsByCmHandleId('some-cm-handle')
 
 231         where: 'following cm handle reference is used'
 
 232             scenario                              | cmHandleRef
 
 233             'Cm Handle Reference as cm handle-id' | 'some-cm-handle'
 
 234             'Cm Handle Reference as alternate-id' | 'some-alternate-id'
 
 237     def 'Execute cm handle search'() {
 
 238         given: 'valid CmHandleQueryApiParameters input'
 
 239             def cmHandleQueryApiParameters = new CmHandleQueryApiParameters()
 
 240             def conditionApiProperties = new ConditionApiProperties()
 
 241             conditionApiProperties.conditionName = 'hasAllModules'
 
 242             conditionApiProperties.conditionParameters = [[moduleName: 'module-name-1']]
 
 243             cmHandleQueryApiParameters.cmHandleQueryParameters = [conditionApiProperties]
 
 244         and: 'query cm handle method returns two cm handles'
 
 245             mockParameterizedCmHandleQueryService.queryCmHandles(
 
 246                 spiedJsonObjectMapper.convertToValueType(cmHandleQueryApiParameters, CmHandleQueryServiceParameters.class))
 
 247                 >> [new NcmpServiceCmHandle(cmHandleId: 'ch-0'), new NcmpServiceCmHandle(cmHandleId: 'ch-1')]
 
 248         and: 'a trust level for cm handles'
 
 249             mockTrustLevelManager.getEffectiveTrustLevel(*_) >> TrustLevel.COMPLETE
 
 250         when: 'execute cm handle search is called'
 
 251             def result = objectUnderTest.executeCmHandleSearch(cmHandleQueryApiParameters)
 
 252         then: 'result consists of the two cm handles returned by the CPS Data Service'
 
 253             assert result.size() == 2
 
 254             assert result[0].cmHandleId == 'ch-0'
 
 255             assert result[1].cmHandleId == 'ch-1'
 
 256         and: 'cm handles have trust level'
 
 257             assert result[0].currentTrustLevel == TrustLevel.COMPLETE
 
 258             assert result[1].currentTrustLevel == TrustLevel.COMPLETE
 
 261     def 'Set Cm Handle Data Sync flag.'() {
 
 262         when: 'setting data sync enabled flag'
 
 263             objectUnderTest.setDataSyncEnabled('ch-1',true)
 
 264         then: 'call is delegated to the cm handle registration service'
 
 265             mockCmHandleRegistrationService.setDataSyncEnabled('ch-1', true)
 
 269         CompositeState.DataStores.builder().operationalDataStore(CompositeState.Operational.builder()
 
 270                 .dataStoreSyncState(DataStoreSyncState.NONE_REQUESTED)
 
 271                 .lastSyncTime('some-timestamp').build()).build()