From: ToineSiebelink Date: Tue, 24 Feb 2026 10:08:37 +0000 (+0000) Subject: LCM Event fix: Include main properties in V2 version X-Git-Url: https://gerrit.onap.org/r/gitweb?a=commitdiff_plain;h=1303266c573b86d8eb4c5bf936be383e3a2201ad;p=cps.git LCM Event fix: Include main properties in V2 version - moduleSetTag now include in old and new properties for V2 if changed - dataProducerIdentifier now include in old and new properties for V2 if changed - alternateId now include in old and new properties for V2 if changed (probably not a real use case) - 'public properties' key-name is actualy "cmHandleProperties" for consistency with V1 - refactored code for consistency and readability - extended unit test to cover missed scenarios - add V2 variation of create and update integration test Issue-ID: CPS-2975 Change-Id: Ia6b6f7368dc8c7824d3270ffc25964016bf50b32 Signed-off-by: ToineSiebelink --- diff --git a/cps-charts/values.yaml b/cps-charts/values.yaml index 4b03d5a12f..78e3c0523d 100644 --- a/cps-charts/values.yaml +++ b/cps-charts/values.yaml @@ -263,4 +263,4 @@ policyExecutorStub: memory: "350Mi" limits: cpu: "1000m" - memory: "2Gi" \ No newline at end of file + memory: "2Gi" diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/PayloadFactory.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/PayloadFactory.java index 3ab8ca1481..29a34125fb 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/PayloadFactory.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/PayloadFactory.java @@ -20,15 +20,12 @@ package org.onap.cps.ncmp.impl.inventory.sync.lcm; -import com.google.common.collect.MapDifference; -import com.google.common.collect.Maps; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import lombok.AccessLevel; import lombok.NoArgsConstructor; -import org.onap.cps.ncmp.api.inventory.models.CmHandleState; import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle; import org.onap.cps.ncmp.events.lcm.PayloadV1; import org.onap.cps.ncmp.events.lcm.PayloadV2; @@ -37,6 +34,7 @@ import org.onap.cps.ncmp.events.lcm.Values; /** * Utility class for examining and identifying changes in CM handle properties. */ +@SuppressWarnings("java:S1192") // Ignore repetition warning for string literals like "alternateId" @NoArgsConstructor(access = AccessLevel.PRIVATE) public class PayloadFactory { @@ -69,60 +67,41 @@ public class PayloadFactory { final Map newProperties = new HashMap<>(); newProperties.put("dataSyncEnabled", ncmpServiceCmHandle.getCompositeState().getDataSyncEnabled()); newProperties.put("cmHandleState", ncmpServiceCmHandle.getCompositeState().getCmHandleState().name()); - newProperties.putAll(ncmpServiceCmHandle.getPublicProperties()); + newProperties.put("alternateId", ncmpServiceCmHandle.getAlternateId()); + newProperties.put("moduleSetTag", ncmpServiceCmHandle.getModuleSetTag()); + newProperties.put("dataProducerIdentifier", ncmpServiceCmHandle.getDataProducerIdentifier()); + newProperties.put("cmHandleProperties", ncmpServiceCmHandle.getPublicProperties()); payload.setNewValues(newProperties); return payload; } static PayloadV2 identifyChanges(final NcmpServiceCmHandle currentNcmpServiceCmHandle, final NcmpServiceCmHandle targetNcmpServiceCmHandle) { - final Boolean currentDataSync = currentNcmpServiceCmHandle.getCompositeState().getDataSyncEnabled(); - final Boolean targetDataSync = targetNcmpServiceCmHandle.getCompositeState().getDataSyncEnabled(); - final boolean dataSyncEnabledChanged = !Objects.equals(currentDataSync, targetDataSync); - - final CmHandleState currentCmHandleState = currentNcmpServiceCmHandle.getCompositeState().getCmHandleState(); - final CmHandleState targetCmHandleState = targetNcmpServiceCmHandle.getCompositeState().getCmHandleState(); - final boolean cmHandleStateChanged = !Objects.equals(currentCmHandleState, targetCmHandleState); - - final Map currentPublicProperties = currentNcmpServiceCmHandle.getPublicProperties(); - final Map targetPublicProperties = targetNcmpServiceCmHandle.getPublicProperties(); - final boolean publicPropertiesChanged = !Objects.equals(currentPublicProperties, targetPublicProperties); - - final PayloadV2 payload = new PayloadV2(); - if (!dataSyncEnabledChanged && !cmHandleStateChanged && !publicPropertiesChanged) { - return payload; - } - final Map oldProperties = new HashMap<>(); final Map newProperties = new HashMap<>(); - if (dataSyncEnabledChanged) { - oldProperties.put("dataSyncEnabled", currentDataSync); - newProperties.put("dataSyncEnabled", targetDataSync); - } - - if (cmHandleStateChanged) { - oldProperties.put("cmHandleState", - currentNcmpServiceCmHandle.getCompositeState().getCmHandleState().name()); - newProperties.put("cmHandleState", + trackChange(oldProperties, newProperties, "dataSyncEnabled", + currentNcmpServiceCmHandle.getCompositeState().getDataSyncEnabled(), + targetNcmpServiceCmHandle.getCompositeState().getDataSyncEnabled()); + trackChange(oldProperties, newProperties, "cmHandleState", + currentNcmpServiceCmHandle.getCompositeState().getCmHandleState().name(), targetNcmpServiceCmHandle.getCompositeState().getCmHandleState().name()); - } - - if (publicPropertiesChanged) { - final MapDifference mapDifference = Maps.difference( - targetNcmpServiceCmHandle.getPublicProperties(), - currentNcmpServiceCmHandle.getPublicProperties()); + trackChange(oldProperties, newProperties, "alternateId", + currentNcmpServiceCmHandle.getAlternateId(), targetNcmpServiceCmHandle.getAlternateId()); + trackChange(oldProperties, newProperties, "moduleSetTag", + currentNcmpServiceCmHandle.getModuleSetTag(), targetNcmpServiceCmHandle.getModuleSetTag()); + trackChange(oldProperties, newProperties, "dataProducerIdentifier", + currentNcmpServiceCmHandle.getDataProducerIdentifier(), + targetNcmpServiceCmHandle.getDataProducerIdentifier()); + trackChange(oldProperties, newProperties, "cmHandleProperties", + currentNcmpServiceCmHandle.getPublicProperties(), + targetNcmpServiceCmHandle.getPublicProperties()); - oldProperties.putAll(mapDifference.entriesOnlyOnRight()); - newProperties.putAll(mapDifference.entriesOnlyOnLeft()); - - mapDifference.entriesDiffering().forEach((key, valueDifference) -> { - oldProperties.put(key, valueDifference.rightValue()); - newProperties.put(key, valueDifference.leftValue()); - }); + final PayloadV2 payload = new PayloadV2(); + if (!oldProperties.isEmpty()) { + payload.setOldValues(oldProperties); + payload.setNewValues(newProperties); } - payload.setOldValues(oldProperties); - payload.setNewValues(newProperties); return payload; } @@ -146,16 +125,21 @@ public class PayloadFactory { if (properties.containsKey("cmHandleState")) { values.setCmHandleState(Values.CmHandleState.fromValue((String) properties.get("cmHandleState"))); } - final Map publicProperties = new HashMap<>(); - properties.forEach((key, value) -> { - if (!"dataSyncEnabled".equals(key) && !"cmHandleState".equals(key)) { - publicProperties.put(key, (String) value); - } - }); - if (!publicProperties.isEmpty()) { - values.setCmHandleProperties(List.of(publicProperties)); + if (properties.containsKey("cmHandleProperties")) { + values.setCmHandleProperties(List.of((Map) properties.get("cmHandleProperties"))); } return values; } + private static void trackChange(final Map oldProperties, + final Map newProperties, + final String propertyName, + final Object oldValue, + final Object newValue) { + if (!Objects.equals(oldValue, newValue)) { + oldProperties.put(propertyName, oldValue); + newProperties.put(propertyName, newValue); + } + } + } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventObjectCreatorSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventObjectCreatorSpec.groovy index 381b731602..06118892ef 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventObjectCreatorSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventObjectCreatorSpec.groovy @@ -32,6 +32,7 @@ import static org.onap.cps.ncmp.api.inventory.models.CmHandleState.READY class LcmEventObjectCreatorSpec extends Specification { + def defaultState = new CompositeState(dataSyncEnabled: true, cmHandleState: READY) def objectUnderTest = new LcmEventObjectCreator() def cmHandleId = 'test-cm-handle' @@ -63,10 +64,8 @@ class LcmEventObjectCreatorSpec extends Specification { def 'Map the LcmEvent for all properties NO CHANGE'() { given: 'NCMP cm handle details without any changes' def publicProperties = ['publicProperty1': 'value3', 'publicProperty2': 'value4'] - def currentNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: new CompositeState(dataSyncEnabled: true, cmHandleState: READY), - publicProperties: publicProperties) - def targetNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: new CompositeState(dataSyncEnabled: true, cmHandleState: READY), - publicProperties: publicProperties) + def currentNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: defaultState, publicProperties: publicProperties) + def targetNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: defaultState, publicProperties: publicProperties) when: 'the lcm event is created' def result = objectUnderTest.createLcmEventV1(currentNcmpServiceCmHandle, targetNcmpServiceCmHandle) then: 'Properties are just the one which are same' @@ -76,9 +75,8 @@ class LcmEventObjectCreatorSpec extends Specification { def 'Map the LcmEvent for operation CREATE'() { given: 'NCMP cm handle details' - def targetNcmpServiceCmhandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: new CompositeState(dataSyncEnabled: false, cmHandleState: READY), - publicProperties: ['publicProperty1': 'value11', 'publicProperty2': 'value22']) def currentNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, publicProperties: ['publicProperty1': 'value1', 'publicProperty2': 'value2']) + def targetNcmpServiceCmhandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: defaultState, publicProperties: ['publicProperty1': 'value11', 'publicProperty2': 'value22']) when: 'the lcm event is created' def result = objectUnderTest.createLcmEventV1(currentNcmpServiceCmHandle, targetNcmpServiceCmhandle) then: 'event header is mapped correctly' @@ -88,7 +86,7 @@ class LcmEventObjectCreatorSpec extends Specification { and: 'event payload is mapped correctly' assert result.event.cmHandleId == cmHandleId assert result.event.newValues.cmHandleState == Values.CmHandleState.READY - assert result.event.newValues.dataSyncEnabled == false + assert result.event.newValues.dataSyncEnabled == true assert result.event.newValues.cmHandleProperties == [['publicProperty1': 'value11', 'publicProperty2': 'value22']] and: 'it should not have any old values' assert result.event.oldValues == null @@ -158,8 +156,8 @@ class LcmEventObjectCreatorSpec extends Specification { def 'Map the LcmEvent for alternate ID, data producer identifier, and module set tag when they contain #scenario'() { given: 'NCMP cm handle details with current and old values for alternate ID, module set tag, and data producer identifier' - def currentNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, alternateId: currentAlternateId, moduleSetTag: currentModuleSetTag, dataProducerIdentifier: currentDataProducerIdentifier, compositeState: new CompositeState(dataSyncEnabled: false)) - def targetNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, alternateId: targetAlternateId, moduleSetTag: targetModuleSetTag, dataProducerIdentifier: targetDataProducerIdentifier, compositeState: new CompositeState(dataSyncEnabled: false)) + def currentNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, alternateId: currentAlternateId, moduleSetTag: currentModuleSetTag, dataProducerIdentifier: currentDataProducerIdentifier, compositeState: defaultState) + def targetNcmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, alternateId: targetAlternateId, moduleSetTag: targetModuleSetTag, dataProducerIdentifier: targetDataProducerIdentifier, compositeState: defaultState) when: 'the lcm event is created' def result = objectUnderTest.createLcmEventV1(currentNcmpServiceCmHandle, targetNcmpServiceCmHandle) then: 'the alternate ID, module set tag, and data producer identifier are present or are an empty string in the payload' diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/PayloadFactorySpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/PayloadFactorySpec.groovy index d711305d8f..c4ad8780ff 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/PayloadFactorySpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/PayloadFactorySpec.groovy @@ -20,141 +20,159 @@ package org.onap.cps.ncmp.impl.inventory.sync.lcm -import org.onap.cps.ncmp.api.inventory.models.CmHandleState +import spock.lang.Specification + +import static org.onap.cps.ncmp.api.inventory.models.CmHandleState.ADVISED +import static org.onap.cps.ncmp.api.inventory.models.CmHandleState.DELETED +import static org.onap.cps.ncmp.api.inventory.models.CmHandleState.READY +import static org.onap.cps.ncmp.events.lcm.Values.CmHandleState.ADVISED as LCM_ADVISED +import static org.onap.cps.ncmp.events.lcm.Values.CmHandleState.READY as LCM_READY +import static org.onap.cps.ncmp.impl.inventory.sync.lcm.LcmEventType.CREATE +import static org.onap.cps.ncmp.impl.inventory.sync.lcm.LcmEventType.DELETE +import static org.onap.cps.ncmp.impl.inventory.sync.lcm.LcmEventType.UPDATE + import org.onap.cps.ncmp.api.inventory.models.CompositeState import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle -import org.onap.cps.ncmp.events.lcm.Values -import spock.lang.Specification class PayloadFactorySpec extends Specification { + + def defaultState = new CompositeState(dataSyncEnabled: true, cmHandleState: READY) + def 'Create payload for create operation.'() { given: 'a new cm handle' - def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: 'ch', - compositeState: new CompositeState(dataSyncEnabled: true, cmHandleState: CmHandleState.READY), - publicProperties: ['prop1': 'value1'] - ) + def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: 'ch1', compositeState: defaultState, publicProperties: [prop1: 'value1'] ) when: 'payload is created for create' - def result = PayloadFactory.createPayloadV1(LcmEventType.CREATE, null, ncmpServiceCmHandle) + def result = PayloadFactory.createPayloadV1(CREATE, null, ncmpServiceCmHandle) then: 'new values are populated' - assert result.cmHandleId == 'ch' + assert result.cmHandleId == 'ch1' assert result.newValues.dataSyncEnabled == true - assert result.newValues.cmHandleState == Values.CmHandleState.READY - assert result.newValues.cmHandleProperties == [['prop1': 'value1']] + assert result.newValues.cmHandleState == LCM_READY + and: 'the public properties are store as a list (fluke in old schema) of maps as cm handle properties (legacy name)' + assert result.newValues.cmHandleProperties == [[prop1: 'value1']] and: 'old values are not set' assert result.oldValues == null } def 'Create payload when no changes detected.'() { given: 'current and target cm handles with same properties' - def currentCmHandle = new NcmpServiceCmHandle( - compositeState: new CompositeState(dataSyncEnabled: true, cmHandleState: CmHandleState.READY), - publicProperties: ['prop1': 'value1'] - ) - def targetCmHandle = new NcmpServiceCmHandle(cmHandleId: 'ch', - compositeState: new CompositeState(dataSyncEnabled: true, cmHandleState: CmHandleState.READY), - publicProperties: ['prop1': 'value1'] - ) + def currentCmHandle = new NcmpServiceCmHandle(cmHandleId: 'ch1', compositeState: defaultState, publicProperties: [prop1: 'value1'] ) + def targetCmHandle = new NcmpServiceCmHandle(cmHandleId: 'ch1', compositeState: defaultState, publicProperties: [prop1: 'value1']) when: 'payload is created' - def result = PayloadFactory.createPayloadV1(LcmEventType.UPDATE, currentCmHandle, targetCmHandle) + def result = PayloadFactory.createPayloadV1(UPDATE, currentCmHandle, targetCmHandle) then: 'no updates are detected' - assert result.cmHandleId == 'ch' + assert result.cmHandleId == 'ch1' assert result.oldValues == null assert result.newValues == null } def 'Create payload when data sync flag changes.'() { given: 'current and target cm handles with different data sync flags' - def currentCmHandle = new NcmpServiceCmHandle( - compositeState: new CompositeState(dataSyncEnabled: false, cmHandleState: CmHandleState.READY), - publicProperties: [:] - ) - def targetCmHandle = new NcmpServiceCmHandle( - compositeState: new CompositeState(dataSyncEnabled: true, cmHandleState: CmHandleState.READY), - publicProperties: [:] - ) + def currentCmHandle = new NcmpServiceCmHandle(compositeState: defaultState) + def targetCmHandle = new NcmpServiceCmHandle(compositeState: new CompositeState(dataSyncEnabled: false, cmHandleState: READY)) when: 'payload is created' - def result = PayloadFactory.createPayloadV1(LcmEventType.UPDATE,currentCmHandle, targetCmHandle) + def result = PayloadFactory.createPayloadV1(UPDATE,currentCmHandle, targetCmHandle) then: 'data sync flag change is detected' - assert result.oldValues.dataSyncEnabled == false - assert result.newValues.dataSyncEnabled == true + assert result.oldValues.dataSyncEnabled == true + assert result.newValues.dataSyncEnabled == false } def 'Create payload when cm handle state changes.'() { given: 'current and target cm handles with different states' - def currentCmHandle = new NcmpServiceCmHandle( - compositeState: new CompositeState(dataSyncEnabled: true, cmHandleState: CmHandleState.ADVISED), - publicProperties: [:] - ) - def targetCmHandle = new NcmpServiceCmHandle( - compositeState: new CompositeState(dataSyncEnabled: true, cmHandleState: CmHandleState.READY), - publicProperties: [:] - ) + def currentCmHandle = new NcmpServiceCmHandle(compositeState: defaultState) + def targetCmHandle = new NcmpServiceCmHandle(compositeState: new CompositeState(dataSyncEnabled: true, cmHandleState: ADVISED)) when: 'payload is created' - def result = PayloadFactory.createPayloadV1(LcmEventType.UPDATE,currentCmHandle, targetCmHandle) + def result = PayloadFactory.createPayloadV1(UPDATE,currentCmHandle, targetCmHandle) then: 'state change is detected' - assert result.oldValues.cmHandleState == Values.CmHandleState.ADVISED - assert result.newValues.cmHandleState == Values.CmHandleState.READY + assert result.oldValues.cmHandleState == LCM_READY + assert result.newValues.cmHandleState == LCM_ADVISED } def 'Create payload when public properties change.'() { given: 'current and target cm handles with different properties' - def currentCmHandle = new NcmpServiceCmHandle( - compositeState: new CompositeState(dataSyncEnabled: true, cmHandleState: CmHandleState.READY), - publicProperties: ['prop1': 'old value', 'prop2': 'to be deleted', 'prop4': 'unchanged'] - ) - def targetCmHandle = new NcmpServiceCmHandle( - compositeState: new CompositeState(dataSyncEnabled: true, cmHandleState: CmHandleState.READY), - publicProperties: ['prop1': 'new value', 'prop3': 'new', 'prop4': 'unchanged'] - ) + def currentCmHandle = new NcmpServiceCmHandle(publicProperties: [prop1: 'old value', prop2: 'to be deleted', prop4: 'unchanged'], compositeState: defaultState) + def targetCmHandle = new NcmpServiceCmHandle(publicProperties: [prop1: 'new value', prop3: 'new', prop4: 'unchanged'], compositeState: defaultState) when: 'payload is created' - def result = PayloadFactory.createPayloadV1(LcmEventType.UPDATE,currentCmHandle, targetCmHandle) + def result = PayloadFactory.createPayloadV1(UPDATE,currentCmHandle, targetCmHandle) then: 'property changes are detected' - assert result.oldValues.cmHandleProperties[0]['prop1'] == 'old value' - assert result.oldValues.cmHandleProperties[0]['prop2'] == 'to be deleted' - assert result.newValues.cmHandleProperties[0]['prop1'] == 'new value' - assert result.newValues.cmHandleProperties[0]['prop3'] == 'new' - and: 'unchanged property is not included in the result' - assert !result.oldValues.cmHandleProperties[0].containsKey('prop4') - assert !result.newValues.cmHandleProperties[0].containsKey('prop4') + assert result.oldValues.cmHandleProperties[0].prop1 == 'old value' + assert result.oldValues.cmHandleProperties[0].prop2 == 'to be deleted' + assert result.newValues.cmHandleProperties[0].prop1 == 'new value' + assert result.newValues.cmHandleProperties[0].prop3 == 'new' + and: 'unchanged property is still included in the result' + assert result.oldValues.cmHandleProperties[0].prop4 == 'unchanged' + assert result.newValues.cmHandleProperties[0].prop4 == 'unchanged' } def 'Create payload when multiple changes occur.'() { given: 'current and target cm handles with multiple differences' - def currentCmHandle = new NcmpServiceCmHandle( - compositeState: new CompositeState(dataSyncEnabled: false, cmHandleState: CmHandleState.ADVISED), - publicProperties: ['prop1': 'value1'] - ) - def targetCmHandle = new NcmpServiceCmHandle( - compositeState: new CompositeState(dataSyncEnabled: true, cmHandleState: CmHandleState.READY), - publicProperties: ['prop1': 'newValue1'] - ) + def currentCmHandle = new NcmpServiceCmHandle(compositeState: new CompositeState(dataSyncEnabled: false, cmHandleState: ADVISED), publicProperties: [prop1: 'value1']) + def targetCmHandle = new NcmpServiceCmHandle(compositeState: defaultState, publicProperties: [prop1: 'newValue1']) when: 'payload is created' - def result = PayloadFactory.createPayloadV1(LcmEventType.UPDATE,currentCmHandle, targetCmHandle) + def result = PayloadFactory.createPayloadV1(UPDATE,currentCmHandle, targetCmHandle) then: 'all changes are detected' assert result.oldValues.dataSyncEnabled == false assert result.newValues.dataSyncEnabled == true - assert result.oldValues.cmHandleState == Values.CmHandleState.ADVISED - assert result.newValues.cmHandleState == Values.CmHandleState.READY - assert result.oldValues.cmHandleProperties[0]['prop1'] == 'value1' - assert result.newValues.cmHandleProperties[0]['prop1'] == 'newValue1' + assert result.oldValues.cmHandleState == LCM_ADVISED + assert result.newValues.cmHandleState == LCM_READY + assert result.oldValues.cmHandleProperties[0].prop1 == 'value1' + assert result.newValues.cmHandleProperties[0].prop1 == 'newValue1' } def 'Create payload for delete operation.'() { given: 'a cm handle being deleted' - def currentCmHandle = new NcmpServiceCmHandle( - compositeState: new CompositeState(dataSyncEnabled: true, cmHandleState: CmHandleState.READY), - publicProperties: ['prop1': 'value1'] - ) - def targetCmHandle = new NcmpServiceCmHandle(cmHandleId: 'ch', - compositeState: new CompositeState(dataSyncEnabled: false, cmHandleState: CmHandleState.DELETED), - publicProperties: ['prop1': 'value1'] - ) + def currentCmHandle = new NcmpServiceCmHandle(cmHandleId: 'ch1', compositeState: defaultState, publicProperties: [prop1: 'value1']) + def targetCmHandle = new NcmpServiceCmHandle(cmHandleId: 'ch1', compositeState: new CompositeState(dataSyncEnabled: false, cmHandleState: DELETED), publicProperties: [prop1: 'value1']) when: 'payload is created for delete' - def result = PayloadFactory.createPayloadV1(LcmEventType.DELETE, currentCmHandle, targetCmHandle) + def result = PayloadFactory.createPayloadV1(DELETE, currentCmHandle, targetCmHandle) then: 'cmHandleId is populated' - assert result.cmHandleId == 'ch' + assert result.cmHandleId == 'ch1' and: 'no values are populated' assert result.oldValues == null assert result.newValues == null } + + def 'Create V2 payload when #scenario changes.'() { + given: 'current and target cm handles' + def currentCmHandle = new NcmpServiceCmHandle(compositeState: defaultState, publicProperties: [:],(propertyName):currentValue) + def targetCmHandle = new NcmpServiceCmHandle(compositeState: defaultState, publicProperties: [:],(propertyName):targetValue) + when: 'V2 payload is created' + def result = PayloadFactory.createPayloadV2(UPDATE, currentCmHandle, targetCmHandle) + then: 'changes are detected in V2 payload' + assert result.oldValues[propertyName] == currentValue + assert result.newValues[propertyName] == targetValue + where: + scenario | propertyName | currentValue | targetValue + 'alternateId' | 'alternateId' | 'old-alt-id' | 'new-alt-id' + 'moduleSetTag' | 'moduleSetTag' | 'old-tag' | 'new-tag' + 'dataProducerIdentifier' | 'dataProducerIdentifier' | 'old-dpi' | 'new-dpi' + } + + def 'Create V2 payload when public properties change.'() { + given: 'current and target cm handles with different properties' + def currentCmHandle = new NcmpServiceCmHandle(compositeState: defaultState, publicProperties: [oldProp:'oldValue']) + def targetCmHandle = new NcmpServiceCmHandle(compositeState: defaultState, publicProperties: [newProp:'newValue']) + when: 'V2 payload is created' + def result = PayloadFactory.createPayloadV2(UPDATE, currentCmHandle, targetCmHandle) + then: 'property changes are detected in V2 payload as "chHandleProperties"' + assert result.oldValues['cmHandleProperties'] == [oldProp:'oldValue'] + assert result.newValues['cmHandleProperties'] == [newProp:'newValue'] + } + + def 'Create V2 payload when cm handle state changes and dataSyncEnabled #dataSyncScenario.'() { + given: 'current and target cm handles with different states' + def currentCmHandle = new NcmpServiceCmHandle(compositeState: defaultState) + def targetCmHandle = new NcmpServiceCmHandle(compositeState: new CompositeState(dataSyncEnabled: targetDataSync, cmHandleState: ADVISED)) + when: 'V2 payload is created' + def result = PayloadFactory.createPayloadV2(UPDATE, currentCmHandle, targetCmHandle) + then: 'state change is detected in V2 payload' + assert result.oldValues['cmHandleState'] == 'READY' + assert result.newValues['cmHandleState'] == 'ADVISED' + and: 'dataSyncEnabled is handled correctly' + assert result.oldValues['dataSyncEnabled'] == expectedOldDataSync + assert result.newValues['dataSyncEnabled'] == expectedNewDataSync + where: + dataSyncScenario | targetDataSync | expectedOldDataSync | expectedNewDataSync + 'changes' | false | true | false + 'does not change'| true | null | null + } } diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/inventory/CmHandleCreateSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/inventory/CmHandleCreateSpec.groovy index 15f3a487b4..8f84c5ff2d 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/inventory/CmHandleCreateSpec.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/inventory/CmHandleCreateSpec.groovy @@ -31,7 +31,11 @@ import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistration import org.onap.cps.ncmp.api.inventory.models.LockReasonCategory import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle import org.onap.cps.ncmp.events.lcm.LcmEventV1 +import org.onap.cps.ncmp.events.lcm.LcmEventV2 import org.onap.cps.ncmp.impl.NetworkCmProxyInventoryFacadeImpl +import org.onap.cps.ncmp.impl.inventory.sync.lcm.LcmEventProducer +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.test.util.ReflectionTestUtils import spock.util.concurrent.PollingConditions import java.time.Duration @@ -43,6 +47,9 @@ class CmHandleCreateSpec extends CpsIntegrationSpecBase { KafkaConsumer kafkaConsumer + @Autowired + LcmEventProducer lcmEventProducer + def setup() { objectUnderTest = networkCmProxyInventoryFacade subscribeAndClearPreviousMessages('test-group', 'ncmp-events') @@ -99,7 +106,7 @@ class CmHandleCreateSpec extends CpsIntegrationSpecBase { assert oldValues == null assert newValues.cmHandleState.value() == 'ADVISED' assert newValues.dataSyncEnabled == null - assert newValues.cmHandleProperties[0] == [color:'green'] + assert newValues.cmHandleProperties == [[color:'green']] } and: 'the next event is about update to READY state (new value), the old value for state is ADVISED' assert messages[1].event.oldValues.cmHandleState.value() == 'ADVISED' @@ -124,6 +131,70 @@ class CmHandleCreateSpec extends CpsIntegrationSpecBase { } } + def 'CM Handle registration using V2 events.'() { + given: 'event schema version is set to v2' + def originalEventSchemaVersion = ReflectionTestUtils.getField(lcmEventProducer, 'eventSchemaVersion') + ReflectionTestUtils.setField(lcmEventProducer, 'eventSchemaVersion', 'v2') + and: 'DMI will return modules when requested' + def uniqueIdV2 = 'my-new-cm-handle-v2' + dmiDispatcher1.moduleNamesPerCmHandleId[uniqueIdV2] = ['M1', 'M2'] + when: 'a CM-handle is registered for creation' + def cmHandleToCreate = new NcmpServiceCmHandle(cmHandleId: uniqueIdV2, + alternateId: 'fdn1', + moduleSetTag: 'tag1', + dataProducerIdentifier: 'prod1', + publicProperties: [color:'green']) + def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: DMI1_URL, createdCmHandles: [cmHandleToCreate]) + def dmiPluginRegistrationResponse = objectUnderTest.updateDmiRegistration(dmiPluginRegistration) + then: 'registration gives successful response' + assert dmiPluginRegistrationResponse.createdCmHandles == [CmHandleRegistrationResponse.createSuccessResponse(uniqueIdV2)] + and: 'CM-handle is initially in ADVISED state' + assert CmHandleState.ADVISED == objectUnderTest.getCmHandleCompositeState(uniqueIdV2).cmHandleState + then: 'the module sync watchdog is triggered' + moduleSyncWatchdog.moduleSyncAdvisedCmHandles() + then: 'CM-handle goes to READY state after module sync' + assert CmHandleState.READY == objectUnderTest.getCmHandleCompositeState(uniqueIdV2).cmHandleState + and: 'the CM-handle has expected modules' + assert ['M1', 'M2'] == objectUnderTest.getYangResourcesModuleReferences(uniqueIdV2).moduleName.sort() + then: 'get the last 2 messages' + def consumerRecords = getLatestConsumerRecordsWithMaxPollOf1Second(kafkaConsumer, 2) + def messages = [] + consumerRecords.each { consumerRecord -> + messages.add(jsonObjectMapper.convertJsonString(consumerRecord.value().toString(), LcmEventV2)) + } + and: 'both messages have the correct cmHandleId' + assert messages.event.every { it.cmHandleId == uniqueIdV2 } + and: 'the first lcm event has no old values and the initial attributes as new values state ADVISED' + with(messages[0].event) { + assert oldValues == null + assert newValues['cmHandleState'] == 'ADVISED' + assert newValues['dataSyncEnabled'] == null + assert newValues['cmHandleProperties'] == [color:'green'] + assert newValues['alternateId'] == 'fdn1' + assert newValues['moduleSetTag'] == 'tag1' + assert newValues['dataProducerIdentifier'] == 'prod1' + } + and: 'the next event is about update to READY state (new value), the old value for state is ADVISED' + assert messages[1].event.oldValues['cmHandleState'] == 'ADVISED' + assert messages[1].event.newValues['cmHandleState'] == 'READY' + and: 'the cm handle (public) properties have not changed and are therefore null for old and new values' + assert messages[1].event.oldValues['cmHandleProperties'] == null + assert messages[1].event.newValues['cmHandleProperties'] == null + and: 'the data sync flag goes from undefined to false' + assert messages[1].event.oldValues['dataSyncEnabled'] == null + assert messages[1].event.newValues['dataSyncEnabled'] == false + and: 'alternateId, moduleSetTag, dataProducerIdentifier have not changed and are therefore null for old and new values' + assert messages[1].event.oldValues['alternateId'] == null + assert messages[1].event.newValues['alternateId'] == null + assert messages[1].event.oldValues['moduleSetTag'] == null + assert messages[1].event.newValues['moduleSetTag'] == null + assert messages[1].event.oldValues['dataProducerIdentifier'] == null + assert messages[1].event.newValues['dataProducerIdentifier'] == null + cleanup: 'restore original event schema version and deregister CM handle' + ReflectionTestUtils.setField(lcmEventProducer, 'eventSchemaVersion', originalEventSchemaVersion) + deregisterCmHandle(DMI1_URL, uniqueIdV2) + } + def 'CM Handle registration with DMI error during module sync.'() { given: 'DMI is not available to handle requests' dmiDispatcher1.isAvailable = false diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/inventory/CmHandleUpdateSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/inventory/CmHandleUpdateSpec.groovy index ae302e8df3..a86bfa35c2 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/inventory/CmHandleUpdateSpec.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/inventory/CmHandleUpdateSpec.groovy @@ -29,7 +29,11 @@ import org.onap.cps.ncmp.api.inventory.models.CmHandleRegistrationResponse import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistration import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle import org.onap.cps.ncmp.events.lcm.LcmEventV1 +import org.onap.cps.ncmp.events.lcm.LcmEventV2 import org.onap.cps.ncmp.impl.NetworkCmProxyInventoryFacadeImpl +import org.onap.cps.ncmp.impl.inventory.sync.lcm.LcmEventProducer +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.test.util.ReflectionTestUtils import java.time.Duration @@ -39,6 +43,8 @@ class CmHandleUpdateSpec extends CpsIntegrationSpecBase { KafkaConsumer kafkaConsumer + @Autowired + LcmEventProducer lcmEventProducer def setup() { objectUnderTest = networkCmProxyInventoryFacade @@ -125,6 +131,43 @@ class CmHandleUpdateSpec extends CpsIntegrationSpecBase { deregisterCmHandle(DMI1_URL, cmHandleId) } + def 'CM Handle registration to verify changes in data producer identifier using V2 events'() { + given: 'event schema version is set to v2' + def originalEventSchemaVersion = ReflectionTestUtils.getField(lcmEventProducer, 'eventSchemaVersion') + ReflectionTestUtils.setField(lcmEventProducer, 'eventSchemaVersion', 'v2') + and: 'DMI will return modules when requested' + def cmHandleId = 'ch-id-for-update-v2' + dmiDispatcher1.moduleNamesPerCmHandleId[cmHandleId] = ['M1', 'M2'] + when: 'a CM-handle is registered for creation' + def cmHandleToCreate = new NcmpServiceCmHandle(cmHandleId: cmHandleId) + def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: DMI1_URL, createdCmHandles: [cmHandleToCreate]) + def dmiPluginRegistrationResponse = objectUnderTest.updateDmiRegistration(dmiPluginRegistration) + then: 'registration gives successful response' + assert dmiPluginRegistrationResponse.createdCmHandles == [CmHandleRegistrationResponse.createSuccessResponse(cmHandleId)] + then: 'the module sync watchdog is triggered' + moduleSyncWatchdog.moduleSyncAdvisedCmHandles() + and: 'flush and check there are 2 cm handle registration events (state transition from NONE to ADVISED and ADVISED to READY)' + assert getLatestConsumerRecordsWithMaxPollOf1Second(kafkaConsumer, 2).size() == 2 + and: 'cm handle updated with the data producer identifier' + def cmHandleToUpdate = new NcmpServiceCmHandle(cmHandleId: cmHandleId, dataProducerIdentifier: 'my-data-producer-id') + def dmiPluginRegistrationForUpdate = new DmiPluginRegistration(dmiPlugin: DMI1_URL, updatedCmHandles: [cmHandleToUpdate]) + def dmiPluginRegistrationResponseForUpdate = objectUnderTest.updateDmiRegistration(dmiPluginRegistrationForUpdate) + then: 'registration gives successful response' + assert dmiPluginRegistrationResponseForUpdate.updatedCmHandles == [CmHandleRegistrationResponse.createSuccessResponse(cmHandleId)] + and: 'get the latest message' + def consumerRecords = getLatestConsumerRecordsWithMaxPollOf1Second(kafkaConsumer, 1) + and: 'the V2 message has the updated data producer identifier in newValues' + def notificationMessages = [] + for (def consumerRecord : consumerRecords) { + notificationMessages.add(jsonObjectMapper.convertJsonString(consumerRecord.value().toString(), LcmEventV2)) + } + assert notificationMessages[0].event.cmHandleId.contains(cmHandleId) + assert notificationMessages[0].event.newValues['dataProducerIdentifier'] == 'my-data-producer-id' + cleanup: 'restore original event schema version and deregister CM handle' + ReflectionTestUtils.setField(lcmEventProducer, 'eventSchemaVersion', originalEventSchemaVersion) + deregisterCmHandle(DMI1_URL, cmHandleId) + } + def subscribeAndClearPreviousMessages(consumerGroupId, topicName) { kafkaConsumer = KafkaTestContainer.getLegacyEventConsumer(consumerGroupId) kafkaConsumer.subscribe([topicName])