From f174640d9aebe8b962de651d954243f434cc5eab Mon Sep 17 00:00:00 2001 From: mpriyank Date: Fri, 10 Jun 2022 12:09:20 +0100 Subject: [PATCH] NcmpEvent creation and Mapping - Mapping class to create header and event payload based on type of operation i.e CREATE, UPDATE and DELETE. - Service class to get CmHandle public properties, create event and delegate request to event publisher. - Modification in NcmpEvent schema json to mark field as String instead of URI - Test scenarios - UPCOMING: Call the service method from relevant code to actually publish the event. Issue-ID: CPS-1037 Change-Id: I6bb7de4b27e602c4d8ee6a5528a866e5f7e8799a Signed-off-by: mpriyank --- .../resources/schemas/ncmp-event-schema-v1.json | 6 +- .../cps/ncmp/api/impl/event/NcmpEventsCreator.java | 90 ++++++++++++++++++++++ .../cps/ncmp/api/impl/event/NcmpEventsService.java | 65 ++++++++++++++++ .../api/impl/event/NcmpEventsCreatorSpec.groovy | 57 ++++++++++++++ .../api/impl/event/NcmpEventsServiceSpec.groovy | 64 +++++++++++++++ 5 files changed, 278 insertions(+), 4 deletions(-) create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/NcmpEventsCreator.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/NcmpEventsService.java create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/NcmpEventsCreatorSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/NcmpEventsServiceSpec.groovy diff --git a/cps-ncmp-events/src/main/resources/schemas/ncmp-event-schema-v1.json b/cps-ncmp-events/src/main/resources/schemas/ncmp-event-schema-v1.json index 84fc12edb..4ddffea56 100644 --- a/cps-ncmp-events/src/main/resources/schemas/ncmp-event-schema-v1.json +++ b/cps-ncmp-events/src/main/resources/schemas/ncmp-event-schema-v1.json @@ -26,8 +26,7 @@ }, "eventSource": { "description": "The source of the event.", - "type": "string", - "format": "uri" + "type": "string" }, "eventType": { "description": "The type of the event.", @@ -35,8 +34,7 @@ }, "eventSchema": { "description": "The schema, including its version, that this event adheres to.", - "type": "string", - "format": "uri" + "type": "string" }, "event": { "$ref": "#/definitions/Event" diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/NcmpEventsCreator.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/NcmpEventsCreator.java new file mode 100644 index 000000000..609306f08 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/NcmpEventsCreator.java @@ -0,0 +1,90 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation + * ================================================================================ + * 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.ncmp.api.impl.event; + +import static org.onap.ncmp.cmhandle.lcm.event.Event.CmhandleState.READY; +import static org.onap.ncmp.cmhandle.lcm.event.Event.Operation.DELETE; + +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.UUID; +import lombok.extern.slf4j.Slf4j; +import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle; +import org.onap.ncmp.cmhandle.lcm.event.Event; +import org.onap.ncmp.cmhandle.lcm.event.Event.Operation; +import org.onap.ncmp.cmhandle.lcm.event.NcmpEvent; +import org.springframework.stereotype.Component; + + +/** + * NcmpEventsCreator to create NcmpEvent based on relevant operation. + */ +@Slf4j +@Component +public class NcmpEventsCreator { + + + /** + * Populate NcmpEvent. + * + * @param cmHandleId Cm Handle Identifier + * @param operation Relevant Operation + * @param ncmpServiceCmHandle Ncmp CmHandle Data + * @return Populated NcmpEvent + */ + public NcmpEvent populateNcmpEvent(final String cmHandleId, final Operation operation, + final NcmpServiceCmHandle ncmpServiceCmHandle) { + return createNcmpEvent(cmHandleId, operation, ncmpServiceCmHandle); + } + + private NcmpEvent createNcmpEvent(final String cmHandleId, final Operation operation, + final NcmpServiceCmHandle ncmpServiceCmHandle) { + final NcmpEvent ncmpEvent = ncmpEventHeader(cmHandleId); + ncmpEvent.setEvent(ncmpEventPayload(cmHandleId, operation, ncmpServiceCmHandle)); + return ncmpEvent; + } + + private Event ncmpEventPayload(final String eventCorrelationId, final Operation operation, + final NcmpServiceCmHandle ncmpServiceCmHandle) { + final Event event = new Event(); + event.setOperation(operation); + event.setCmHandleId(eventCorrelationId); + + if (!DELETE.equals(operation)) { + event.setCmhandleState(READY); + event.setCmhandleProperties(List.of(ncmpServiceCmHandle.getPublicProperties())); + } + return event; + } + + private NcmpEvent ncmpEventHeader(final String eventCorrelationId) { + final NcmpEvent ncmpEvent = new NcmpEvent(); + ncmpEvent.setEventId(UUID.randomUUID().toString()); + ncmpEvent.setEventCorrelationId(eventCorrelationId); + ncmpEvent.setEventTime(ZonedDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ"))); + ncmpEvent.setEventSource("org.onap.ncmp"); + ncmpEvent.setEventType("org.onap.ncmp.cmhandle-lcm-event"); + ncmpEvent.setEventSchema("org.onap.ncmp:cmhandle-lcm-event:v1"); + return ncmpEvent; + } + +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/NcmpEventsService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/NcmpEventsService.java new file mode 100644 index 000000000..045a67a10 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/NcmpEventsService.java @@ -0,0 +1,65 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation + * ================================================================================ + * 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.ncmp.api.impl.event; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.onap.cps.ncmp.api.impl.utils.YangDataConverter; +import org.onap.cps.ncmp.api.inventory.InventoryPersistence; +import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle; +import org.onap.ncmp.cmhandle.lcm.event.Event.Operation; +import org.onap.ncmp.cmhandle.lcm.event.NcmpEvent; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +/** + * NcmpEventService to map the event correctly and publish to the public topic. + */ + +@Slf4j +@Service +@RequiredArgsConstructor +public class NcmpEventsService { + + private final InventoryPersistence inventoryPersistence; + + private final NcmpEventsPublisher ncmpEventsPublisher; + + private final NcmpEventsCreator ncmpEventsCreator; + + @Value("${app.ncmp.events.topic:ncmp-events}") + private String topicName; + + /** + * Publish the NcmpEvent to the public topic. + * + * @param cmHandleId Cm Handle Id + * @param operation Relevant operation(CREATE,UPDATE or DELETE) + */ + public void publishNcmpEvent(final String cmHandleId, final Operation operation) { + + final NcmpServiceCmHandle ncmpServiceCmHandle = YangDataConverter.convertYangModelCmHandleToNcmpServiceCmHandle( + inventoryPersistence.getYangModelCmHandle(cmHandleId)); + final NcmpEvent ncmpEvent = ncmpEventsCreator.populateNcmpEvent(cmHandleId, operation, ncmpServiceCmHandle); + ncmpEventsPublisher.publishEvent(topicName, cmHandleId, ncmpEvent); + + } +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/NcmpEventsCreatorSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/NcmpEventsCreatorSpec.groovy new file mode 100644 index 000000000..04eb0bf2b --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/NcmpEventsCreatorSpec.groovy @@ -0,0 +1,57 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation + * ================================================================================ + * 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.ncmp.api.impl.event + +import org.onap.cps.ncmp.api.inventory.CmHandleState +import org.onap.cps.ncmp.api.inventory.CompositeStateBuilder +import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle +import spock.lang.Specification + +import static org.onap.ncmp.cmhandle.lcm.event.Event.Operation.CREATE +import static org.onap.ncmp.cmhandle.lcm.event.Event.Operation.DELETE +import static org.onap.ncmp.cmhandle.lcm.event.Event.Operation.UPDATE + +class NcmpEventsCreatorSpec extends Specification { + + def objectUnderTest = new NcmpEventsCreator() + def cmHandleId = 'test-cm-handle' + + def 'Map the NcmpEvent for operation #operation'() { + given: 'NCMP cm handle details' + def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, compositeState: new CompositeStateBuilder().withCmHandleState(CmHandleState.READY).build(), + publicProperties: ['publicProperty1': 'value1', 'publicProperty2': 'value2']) + when: 'the event is populated' + def result = objectUnderTest.populateNcmpEvent(cmHandleId, operation, ncmpServiceCmHandle) + then: 'event header is mapped correctly' + assert result.eventSource == 'org.onap.ncmp' + assert result.eventCorrelationId == cmHandleId + and: 'event payload is mapped correctly' + assert result.event.operation == operation + assert result.event.cmhandleProperties.size() == cmHandlePropertiesListSize + assert result.event.cmhandleProperties[0] == cmHandleProperties + where: 'the following operations are used' + operation | cmHandlePropertiesListSize | cmHandleProperties + CREATE | 1 | ['publicProperty1': 'value1', 'publicProperty2': 'value2'] + UPDATE | 1 | ['publicProperty1': 'value1', 'publicProperty2': 'value2'] + DELETE | 0 | null + + } +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/NcmpEventsServiceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/NcmpEventsServiceSpec.groovy new file mode 100644 index 000000000..977423556 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/NcmpEventsServiceSpec.groovy @@ -0,0 +1,64 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation + * ================================================================================ + * 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.ncmp.api.impl.event + +import org.onap.cps.ncmp.api.impl.utils.YangDataConverter +import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle +import org.onap.cps.ncmp.api.inventory.InventoryPersistence +import org.onap.ncmp.cmhandle.lcm.event.NcmpEvent +import spock.lang.Specification + +import static org.onap.ncmp.cmhandle.lcm.event.Event.Operation.CREATE +import static org.onap.ncmp.cmhandle.lcm.event.Event.Operation.DELETE +import static org.onap.ncmp.cmhandle.lcm.event.Event.Operation.UPDATE + +class NcmpEventsServiceSpec extends Specification { + + def mockInventoryPersistence = Mock(InventoryPersistence) + def mockNcmpEventsPublisher = Mock(NcmpEventsPublisher) + def mockNcmpEventsMapper = Mock(NcmpEventsCreator) + + def objectUnderTest = new NcmpEventsService(mockInventoryPersistence, mockNcmpEventsPublisher, mockNcmpEventsMapper) + + def 'Create and Publish event for #operation'() { + given: 'a cm handle id and operation and responses are mocked' + mockResponses('test-cm-handle-id', operation, 'test-topic') + when: 'service is called to publish ncmp event' + objectUnderTest.publishNcmpEvent('test-cm-handle-id', operation) + then: 'no exception is thrown' + noExceptionThrown() + where: 'for following operations' + operation << [CREATE, UPDATE, DELETE] + } + + def mockResponses(cmHandleId, operation, topicName) { + + def yangModelCmHandle = new YangModelCmHandle(id: cmHandleId, publicProperties: [new YangModelCmHandle.Property('publicProperty1', 'value1')], dmiProperties: []) + def ncmpEvent = new NcmpEvent(eventId: UUID.randomUUID().toString(), eventCorrelationId: cmHandleId) + def ncmpServiceCmhandle = YangDataConverter.convertYangModelCmHandleToNcmpServiceCmHandle(yangModelCmHandle) + + mockInventoryPersistence.getYangModelCmHandle(cmHandleId) >> yangModelCmHandle + mockNcmpEventsMapper.populateNcmpEvent(cmHandleId, operation, ncmpServiceCmhandle) >> ncmpEvent + mockNcmpEventsPublisher.publishEvent(topicName, cmHandleId, ncmpEvent) >> {} + } + + +} -- 2.16.6