From f6260a26de44a9338ca998626a93c0d0fa56abc3 Mon Sep 17 00:00:00 2001 From: Bogumil Zebek Date: Wed, 22 Jul 2020 08:19:51 +0200 Subject: StndDefined event routing Route stndDefined events to streams defined in namespace event field. Change-Id: I3963e220095665f8ca3fd1b21c5c20b44057cf76 Issue-ID: DCAEGEN2-1771 Signed-off-by: Zebek Bogumil --- Changelog.md | 3 +- etc/DmaapConfig.json | 34 +++- etc/collector.properties | 4 +- pom.xml | 2 +- .../java/org/onap/dcae/ApplicationSettings.java | 2 +- .../java/org/onap/dcae/JSonSchemasSupplier.java | 4 +- src/main/java/org/onap/dcae/VesApplication.java | 2 +- .../java/org/onap/dcae/common/EventSender.java | 52 +++--- .../java/org/onap/dcae/common/EventUpdater.java | 22 ++- ...edNamespaceParameterHasEmptyValueException.java | 23 +++ ...finedNamespaceParameterNotDefinedException.java | 24 +++ .../java/org/onap/dcae/common/model/VesEvent.java | 120 ++++++++++++ .../java/org/onap/dcae/restapi/ApiException.java | 4 +- .../java/org/onap/dcae/restapi/EventValidator.java | 52 ++++-- .../onap/dcae/restapi/EventValidatorException.java | 32 ++++ .../org/onap/dcae/restapi/VesRestController.java | 97 ++++++---- .../org/onap/dcae/ApplicationSettingsTest.java | 19 +- .../java/org/onap/dcae/common/EventSenderTest.java | 130 +++++++++---- .../java/org/onap/dcae/common/JsonDataLoader.java | 49 +++++ .../org/onap/dcae/common/model/VesEventTest.java | 92 ++++++++++ .../org/onap/dcae/restapi/EventValidatorTest.java | 113 +++++++----- .../onap/dcae/restapi/VesRestControllerTest.java | 201 ++++++++++++++++++--- .../ves7_valid_event.json | 36 ++++ .../ves_stdnDefined_empty_namespace_invalid.json | 47 +++++ .../ves_stdnDefined_missing_namespace_invalid.json | 46 +++++ .../ves_stdnDefined_valid.json | 47 +++++ .../ves_stdnDefined_empty_namespace_invalid.json | 45 +++++ .../ves_stdnDefined_missing_namespace_invalid.json | 44 +++++ src/test/resources/ves_stdnDefined_valid.json | 45 +++++ .../ves_stdnDefined_valid_unknown_topic.json | 45 +++++ version.properties | 2 +- 31 files changed, 1223 insertions(+), 215 deletions(-) create mode 100644 src/main/java/org/onap/dcae/common/model/StndDefinedNamespaceParameterHasEmptyValueException.java create mode 100644 src/main/java/org/onap/dcae/common/model/StndDefinedNamespaceParameterNotDefinedException.java create mode 100644 src/main/java/org/onap/dcae/common/model/VesEvent.java create mode 100644 src/main/java/org/onap/dcae/restapi/EventValidatorException.java create mode 100644 src/test/java/org/onap/dcae/common/JsonDataLoader.java create mode 100644 src/test/java/org/onap/dcae/common/model/VesEventTest.java create mode 100644 src/test/resources/eventsAfterTransformation/ves7_valid_event.json create mode 100644 src/test/resources/eventsAfterTransformation/ves_stdnDefined_empty_namespace_invalid.json create mode 100644 src/test/resources/eventsAfterTransformation/ves_stdnDefined_missing_namespace_invalid.json create mode 100644 src/test/resources/eventsAfterTransformation/ves_stdnDefined_valid.json create mode 100644 src/test/resources/ves_stdnDefined_empty_namespace_invalid.json create mode 100644 src/test/resources/ves_stdnDefined_missing_namespace_invalid.json create mode 100644 src/test/resources/ves_stdnDefined_valid.json create mode 100644 src/test/resources/ves_stdnDefined_valid_unknown_topic.json diff --git a/Changelog.md b/Changelog.md index 4b1918d9..216e1ce9 100644 --- a/Changelog.md +++ b/Changelog.md @@ -19,4 +19,5 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [1.7.1] - 13/07/2020 - [DCAEGEN2-1484](https://jira.onap.org/browse/DCAEGEN2-1484) - VESCollector DMaap publish optimization - [DCAEGEN2-2254](https://jira.onap.org/browse/DCAEGEN2-2254) - Add new data-format for 30.2_ONAP schema version - \ No newline at end of file +## [1.7.2] - 04/08/2020 + - [DCAEGEN2-1771](https://jira.onap.org/browse/DCAEGEN2-1771) - Add StndDefined event routing to dmaap streams defined in namespace event field - no second stage event validation. diff --git a/etc/DmaapConfig.json b/etc/DmaapConfig.json index 27328216..2ef77dcd 100644 --- a/etc/DmaapConfig.json +++ b/etc/DmaapConfig.json @@ -47,6 +47,38 @@ "stripHpId": "true", "type": "out", "cambria.hosts": "onap-dmaap" + }, + { + "name": "ves-3gpp-fault-supervision", + "cambria.topic": "unauthenticated.SEC_3GPP_FAULTSUPERVISION_OUTPUT", + "class": "HpCambriaOutputStream", + "stripHpId": "true", + "type": "out", + "cambria.hosts": "onap-dmaap" + }, + { + "name": "ves-3gpp-provisioning", + "cambria.topic": "unauthenticated.SEC_3GPP_PROVISIONING_OUTPUT", + "class": "HpCambriaOutputStream", + "stripHpId": "true", + "type": "out", + "cambria.hosts": "onap-dmaap" + }, + { + "name": "ves-3gpp-heartbeat", + "cambria.topic": "unauthenticated.SEC_3GPP_HEARTBEAT_OUTPUT", + "class": "HpCambriaOutputStream", + "stripHpId": "true", + "type": "out", + "cambria.hosts": "onap-dmaap" + }, + { + "name": "ves-3gpp-performance-assurance", + "cambria.topic": "unauthenticated.unauthenticated.SEC_3GPP_PERFORMANCEASSURANCE_OUTPUT", + "class": "HpCambriaOutputStream", + "stripHpId": "true", + "type": "out", + "cambria.hosts": "onap-dmaap" } ] -} \ No newline at end of file +} diff --git a/etc/collector.properties b/etc/collector.properties index 3684f5e0..0d408cc4 100755 --- a/etc/collector.properties +++ b/etc/collector.properties @@ -50,8 +50,8 @@ collector.truststore.passwordfile=etc/trustpasswordfile collector.schema.checkflag=1 collector.schema.file={\"v1\":\"./etc/CommonEventFormat_27.2.json\",\"v2\":\"./etc/CommonEventFormat_27.2.json\",\"v3\":\"./etc/CommonEventFormat_27.2.json\",\"v4\":\"./etc/CommonEventFormat_27.2.json\",\"v5\":\"./etc/CommonEventFormat_28.4.1.json\",\"v7\":\"./etc/CommonEventFormat_30.2_ONAP.json\"} -## List all streamid per domain to be supported. The streamid should match to channel name on dmaapfile -collector.dmaap.streamid=fault=ves-fault|syslog=ves-syslog|heartbeat=ves-heartbeat|measurementsForVfScaling=ves-measurement|mobileFlow=ves-mobileflow|other=ves-other|stateChange=ves-statechange|thresholdCrossingAlert=ves-thresholdCrossingAlert|voiceQuality=ves-voicequality|sipSignaling=ves-sipsignaling|notification=ves-notification|pnfRegistration=ves-pnfRegistration|stndDefined=ves-other +## List all streamid per domain to be supported. The streamid should match to channel name on dmaapfile +collector.dmaap.streamid=fault=ves-fault|syslog=ves-syslog|heartbeat=ves-heartbeat|measurementsForVfScaling=ves-measurement|mobileFlow=ves-mobileflow|other=ves-other|stateChange=ves-statechange|thresholdCrossingAlert=ves-thresholdCrossingAlert|voiceQuality=ves-voicequality|sipSignaling=ves-sipsignaling|notification=ves-notification|pnfRegistration=ves-pnfRegistration|3GPP-FaultSupervision=ves-3gpp-fault-supervision|3GPP-Heartbeat=ves-3gpp-heartbeat|3GPP-Provisioning=ves-3gpp-provisioning|3GPP-PerformanceAssurance=ves-3gpp-performance-assurance collector.dmaapfile=./etc/DmaapConfig.json ## Event transformation Flag - when set expects configurable transformation diff --git a/pom.xml b/pom.xml index dcf26280..1154b34a 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ org.onap.dcaegen2.collectors.ves VESCollector - 1.7.1-SNAPSHOT + 1.7.2-SNAPSHOT dcaegen2-collectors-ves VESCollector diff --git a/src/main/java/org/onap/dcae/ApplicationSettings.java b/src/main/java/org/onap/dcae/ApplicationSettings.java index 8458df8d..33ad5bc7 100644 --- a/src/main/java/org/onap/dcae/ApplicationSettings.java +++ b/src/main/java/org/onap/dcae/ApplicationSettings.java @@ -161,7 +161,7 @@ public class ApplicationSettings { return properties.getString("auth.method", AuthMethodType.NO_AUTH.value()); } - public Map dMaaPStreamsMapping() { + public Map getDmaapStreamIds() { String streamIdsProperty = properties.getString("collector.dmaap.streamid", null); if (streamIdsProperty == null) { return HashMap.empty(); diff --git a/src/main/java/org/onap/dcae/JSonSchemasSupplier.java b/src/main/java/org/onap/dcae/JSonSchemasSupplier.java index d7cd5663..10e74ee5 100644 --- a/src/main/java/org/onap/dcae/JSonSchemasSupplier.java +++ b/src/main/java/org/onap/dcae/JSonSchemasSupplier.java @@ -3,7 +3,7 @@ * PROJECT * ================================================================================ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. - * Copyright (C) 2019 Nokia. All rights reserved.s + * Copyright (C) 2020 Nokia. All rights reserved.s * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,7 +33,7 @@ import java.nio.file.Paths; import static io.vavr.API.Tuple; import static java.nio.file.Files.readAllBytes; -class JSonSchemasSupplier { +public class JSonSchemasSupplier { public Map loadJsonSchemas(String collectorSchemaFile) { JSONObject jsonObject = new JSONObject(collectorSchemaFile); diff --git a/src/main/java/org/onap/dcae/VesApplication.java b/src/main/java/org/onap/dcae/VesApplication.java index bc5b1a8f..9f628b5c 100644 --- a/src/main/java/org/onap/dcae/VesApplication.java +++ b/src/main/java/org/onap/dcae/VesApplication.java @@ -133,7 +133,7 @@ public class VesApplication { @Bean @Qualifier("eventSender") public EventSender eventSender() { - return new EventSender(eventPublisher, applicationSettings); + return new EventSender(eventPublisher, applicationSettings.getDmaapStreamIds()); } } diff --git a/src/main/java/org/onap/dcae/common/EventSender.java b/src/main/java/org/onap/dcae/common/EventSender.java index c1002af6..63be9106 100644 --- a/src/main/java/org/onap/dcae/common/EventSender.java +++ b/src/main/java/org/onap/dcae/common/EventSender.java @@ -1,9 +1,9 @@ /* * ============LICENSE_START======================================================= - * PROJECT + * VES Collector * ================================================================================ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. - * Copyright (C) 2018 Nokia. All rights reserved.s + * Copyright (C) 2020 Nokia. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,56 +24,48 @@ import com.att.nsa.clock.SaClock; import com.att.nsa.logging.LoggingContext; import com.att.nsa.logging.log4j.EcompFields; import io.vavr.collection.Map; -import org.json.JSONArray; -import org.json.JSONObject; -import org.onap.dcae.ApplicationSettings; +import org.onap.dcae.common.model.VesEvent; import org.onap.dcae.common.publishing.EventPublisher; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.List; + public class EventSender { private static final Logger metriclog = LoggerFactory.getLogger("com.att.ecomp.metrics"); - private Map streamidHash; + private Map streamIdToDmaapIds; private EventPublisher eventPublisher; - private static final String VES_UNIQUE_ID = "VESuniqueId"; private static final Logger log = LoggerFactory.getLogger(EventSender.class); - private static final String EVENT_LITERAL = "event"; - private static final String COMMON_EVENT_HEADER = "commonEventHeader"; - public EventSender( EventPublisher eventPublisher, ApplicationSettings properties) { + public EventSender(EventPublisher eventPublisher, Map streamIdToDmaapIds) { this.eventPublisher = eventPublisher; - this.streamidHash = properties.dMaaPStreamsMapping(); + this.streamIdToDmaapIds = streamIdToDmaapIds; } - public void send(JSONArray arrayOfEvents) { - for (int i = 0; i < arrayOfEvents.length(); i++) { + public void send(List vesEvents) { + for (VesEvent vesEvent : vesEvents) { metriclog.info("EVENT_PUBLISH_START"); - JSONObject object = (JSONObject) arrayOfEvents.get(i); - setLoggingContext(object); - streamidHash.get(getDomain(object)) - .onEmpty(() -> log.error("No StreamID defined for publish - Message dropped" + object)) - .forEach(streamIds -> sendEventsToStreams(object, streamIds)); - log.debug("Message published" + object); + setLoggingContext(vesEvent); + streamIdToDmaapIds.get(vesEvent.getStreamId()) + .onEmpty(() -> log.error("No StreamID defined for publish - Message dropped" + vesEvent.asJsonObject())) + .forEach(streamIds -> sendEventsToStreams(vesEvent, streamIds)); + log.debug("Message published" + vesEvent.asJsonObject()); } log.debug("CommonStartup.handleEvents:EVENTS has been published successfully!"); metriclog.info("EVENT_PUBLISH_END"); } - private static String getDomain(JSONObject event) { - return event.getJSONObject(EVENT_LITERAL).getJSONObject(COMMON_EVENT_HEADER).getString("domain"); - } - - private void sendEventsToStreams(JSONObject event, String[] streamIdList) { - for (String aStreamIdList : streamIdList) { - log.info("Invoking publisher for streamId:" + aStreamIdList); - eventPublisher.sendEvent(event, aStreamIdList); + private void sendEventsToStreams(VesEvent vesEvent, String[] streamIdList) { + for (String streamId : streamIdList) { + log.info("Invoking publisher for streamId/domain:" + streamId); + eventPublisher.sendEvent(vesEvent.asJsonObject(), streamId); } } - private void setLoggingContext(JSONObject event) { - LoggingContext localLC = VESLogger.getLoggingContextForThread(event.get(VES_UNIQUE_ID).toString()); + private void setLoggingContext(VesEvent vesEvent) { + LoggingContext localLC = VESLogger.getLoggingContextForThread(vesEvent.getUniqueId().toString()); localLC.put(EcompFields.kBeginTimestampMs, SaClock.now()); - log.debug("event.VESuniqueId" + event.get(VES_UNIQUE_ID) + "event.commonEventHeader.domain:" + getDomain(event)); + log.debug("event.VESuniqueId" + vesEvent.getUniqueId() + "event.commonEventHeader.domain:" + vesEvent.getDomain()); } } diff --git a/src/main/java/org/onap/dcae/common/EventUpdater.java b/src/main/java/org/onap/dcae/common/EventUpdater.java index 1469d47e..954e4b6e 100644 --- a/src/main/java/org/onap/dcae/common/EventUpdater.java +++ b/src/main/java/org/onap/dcae/common/EventUpdater.java @@ -22,12 +22,14 @@ package org.onap.dcae.common; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.UUID; import org.json.JSONArray; import org.json.JSONObject; import org.onap.dcae.ApplicationSettings; +import org.onap.dcae.common.model.VesEvent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -47,33 +49,33 @@ public class EventUpdater { this.settings = settings; } - public JSONArray convert(JSONObject jsonObject, String version, UUID uuid, String type){ + public List convert(VesEvent vesEvent, String version, UUID uuid, String type){ if(type.equalsIgnoreCase(EVENT_LIST)){ - return convertEvents(jsonObject, uuid.toString(), version); + return convertEvents(vesEvent, uuid.toString(), version); } else { - return convertEvent(jsonObject, uuid.toString(), version); + return convertEvent(vesEvent, uuid.toString(), version); } } - private JSONArray convertEvents(JSONObject jsonObject, - String uuid, String version) { - JSONArray asArrayEvents = new JSONArray(); + private List convertEvents(VesEvent vesEvent, String uuid, String version) { + List asArrayEvents = new ArrayList<>(); - JSONArray events = jsonObject.getJSONArray(EVENT_LIST); + JSONArray events = vesEvent.asJsonObject().getJSONArray(EVENT_LIST); for (int i = 0; i < events.length(); i++) { JSONObject event = new JSONObject().put(EVENT, events.getJSONObject(i)); event.put(VES_UNIQUE_ID, uuid + "-" + i); event.put(VES_VERSION, version); - asArrayEvents.put(overrideEvent(event)); + asArrayEvents.add(new VesEvent(overrideEvent(event))); } return asArrayEvents; } - private JSONArray convertEvent(JSONObject jsonObject, String uuid, String version) { + private List convertEvent(VesEvent vesEvent, String uuid, String version) { + JSONObject jsonObject = vesEvent.asJsonObject(); jsonObject.put(VES_UNIQUE_ID, uuid); jsonObject.put(VES_VERSION, version); - return new JSONArray().put(overrideEvent(jsonObject)); + return List.of(new VesEvent(overrideEvent(jsonObject))); } private JSONObject overrideEvent(JSONObject event) { diff --git a/src/main/java/org/onap/dcae/common/model/StndDefinedNamespaceParameterHasEmptyValueException.java b/src/main/java/org/onap/dcae/common/model/StndDefinedNamespaceParameterHasEmptyValueException.java new file mode 100644 index 00000000..22ec23a3 --- /dev/null +++ b/src/main/java/org/onap/dcae/common/model/StndDefinedNamespaceParameterHasEmptyValueException.java @@ -0,0 +1,23 @@ +/* + * ============LICENSE_START======================================================= + * VES Collector + * ================================================================================ + * Copyright (C) 2020 Nokia. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.dcae.common.model; + +public class StndDefinedNamespaceParameterHasEmptyValueException extends RuntimeException{ +} diff --git a/src/main/java/org/onap/dcae/common/model/StndDefinedNamespaceParameterNotDefinedException.java b/src/main/java/org/onap/dcae/common/model/StndDefinedNamespaceParameterNotDefinedException.java new file mode 100644 index 00000000..69ee68fa --- /dev/null +++ b/src/main/java/org/onap/dcae/common/model/StndDefinedNamespaceParameterNotDefinedException.java @@ -0,0 +1,24 @@ +/* + * ============LICENSE_START======================================================= + * VES Collector + * ================================================================================ + * Copyright (C) 2020 Nokia. All rights reserved.s + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.dcae.common.model; + + +public class StndDefinedNamespaceParameterNotDefinedException extends RuntimeException { +} diff --git a/src/main/java/org/onap/dcae/common/model/VesEvent.java b/src/main/java/org/onap/dcae/common/model/VesEvent.java new file mode 100644 index 00000000..ce709d1c --- /dev/null +++ b/src/main/java/org/onap/dcae/common/model/VesEvent.java @@ -0,0 +1,120 @@ +/* + * ============LICENSE_START======================================================= + * VES Collector + * ================================================================================ + * Copyright (C) 2020 Nokia. All rights reserved.s + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.dcae.common.model; + +import org.json.JSONObject; + +/** + * This class is a wrapper for JSONObject, that represents VES event. + * It contains Strings that represents key, that can be found in VES event. + * + * @author Zebek + */ +public class VesEvent { + + private static final String EVENT_LITERAL = "event"; + private static final String COMMON_EVENT_HEADER = "commonEventHeader"; + private static final String VES_UNIQUE_ID = "VESuniqueId"; + private static final String DOMAIN = "domain"; + private static final String STND_DEFINED_NAMESPACE = "stndDefinedNamespace"; + private static final String STND_DEFINED_DOMAIN = "stndDefined"; + + private final JSONObject event; + + public VesEvent(JSONObject event) { + this.event = event; + } + + /** + * Returns stream ID from VES event. + * + * @return stream ID + */ + public String getStreamId() { + String retVal = getDomain(); + + if (isStdDefinedDomain(retVal)) { + retVal = resolveDomainForStndDefinedEvent(); + } + + return retVal; + } + + /** + * Returns Domain name from VES event. + * + * @return domain + */ + public String getDomain() { + return getEventHeader().getString(DOMAIN); + } + + private String resolveDomainForStndDefinedEvent() { + final JSONObject eventHeader = getEventHeader(); + if(eventHeader.has(STND_DEFINED_NAMESPACE)) { + final String domain = eventHeader + .getString(STND_DEFINED_NAMESPACE); + if(domain.isEmpty()) { + throw new StndDefinedNamespaceParameterHasEmptyValueException(); + } + return domain; + } else { + throw new StndDefinedNamespaceParameterNotDefinedException(); + } + } + + private JSONObject getEventHeader() { + return event + .getJSONObject(EVENT_LITERAL) + .getJSONObject(COMMON_EVENT_HEADER); + } + + private boolean isStdDefinedDomain(String domain) { + return domain.equals(STND_DEFINED_DOMAIN); + } + + /** + * Returns unique ID of VES event. + * + * @return unique ID + */ + public Object getUniqueId() { + return event.get(VES_UNIQUE_ID); + } + + /** + * Returns VES event in form of JSON object. + * + * @return event in form of json Object + */ + public JSONObject asJsonObject() { + return new JSONObject(event.toString()); + } + + /** + * Checks if type of event is same as given in paramaters. + * + * @param type name that will be compared with event type + * @return true or false depending if type given in parameter is same as VES event type + */ + public boolean hasType(String type) { + return this.event.has(type); + } +} diff --git a/src/main/java/org/onap/dcae/restapi/ApiException.java b/src/main/java/org/onap/dcae/restapi/ApiException.java index 5867e52b..255999a6 100644 --- a/src/main/java/org/onap/dcae/restapi/ApiException.java +++ b/src/main/java/org/onap/dcae/restapi/ApiException.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * org.onap.dcaegen2.collectors.ves * ================================================================================ - * Copyright (C) 2018 Nokia. All rights reserved. + * Copyright (C) 2020 Nokia. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,6 +32,8 @@ public enum ApiException { INVALID_CONTENT_TYPE(ExceptionType.SERVICE_EXCEPTION, "SVC0002", "Bad Parameter (Incorrect request Content-Type)", 400), UNAUTHORIZED_USER(ExceptionType.POLICY_EXCEPTION, "POL2000", "Unauthorized user", 401), INVALID_CUSTOM_HEADER(ExceptionType.SERVICE_EXCEPTION, "SVC0002", "Bad Parameter (Incorrect request api version)", 400), + MISSING_NAMESPACE_PARAMETER(ExceptionType.SERVICE_EXCEPTION, "SVC2006", "Mandatory input attribute event.commonEventHeader.stndDefinedNamespace is missing from request", 400), + EMPTY_NAMESPACE_PARAMETER(ExceptionType.SERVICE_EXCEPTION, "SVC2006", "Mandatory input attribute event.commonEventHeader.stndDefinedNamespace is empty in request", 400), NO_SERVER_RESOURCES(ExceptionType.SERVICE_EXCEPTION, "SVC1000", "No server resources (internal processing queue full)", 503); public final int httpStatusCode; diff --git a/src/main/java/org/onap/dcae/restapi/EventValidator.java b/src/main/java/org/onap/dcae/restapi/EventValidator.java index 3261c3b3..0eb0967a 100644 --- a/src/main/java/org/onap/dcae/restapi/EventValidator.java +++ b/src/main/java/org/onap/dcae/restapi/EventValidator.java @@ -20,34 +20,54 @@ */ package org.onap.dcae.restapi; -import java.util.Optional; -import org.json.JSONObject; +import com.networknt.schema.JsonSchema; import org.onap.dcae.ApplicationSettings; -import org.springframework.http.ResponseEntity; +import org.onap.dcae.common.model.VesEvent; + +/** + * This class is using ApplicationSetting and SchemaValidator to validate VES event. + * + * @author Zebek + */ public class EventValidator { - private final SchemaValidator schemaValidator = new SchemaValidator(); - private ApplicationSettings applicationSettings; + private final SchemaValidator schemaValidator; + private final ApplicationSettings applicationSettings; public EventValidator(ApplicationSettings applicationSettings) { + this(applicationSettings, new SchemaValidator()); + } + + EventValidator(ApplicationSettings applicationSettings, SchemaValidator schemaValidator) { this.applicationSettings = applicationSettings; + this.schemaValidator = schemaValidator; } - public Optional> validate(JSONObject jsonObject, String type, String version){ + /** + * This method is validating given event using schema adn throws exception if event is not valid + * + * @param vesEvent event that will be validate + * @param type expected type of event + * @param version json schema version that will be used + * @throws EventValidatorException when event is not valid or have wrong type + */ + public void validate(VesEvent vesEvent, String type, String version) throws EventValidatorException { if (applicationSettings.eventSchemaValidationEnabled()) { - if (jsonObject.has(type)) { - if (!schemaValidator.conformsToSchema(jsonObject, applicationSettings.jsonSchema(version))) { - return errorResponse(ApiException.SCHEMA_VALIDATION_FAILED); - } - } else { - return errorResponse(ApiException.INVALID_JSON_INPUT); + doValidation(vesEvent, type, version); + } + } + + private void doValidation(VesEvent vesEvent, String type, String version) throws EventValidatorException { + if (vesEvent.hasType(type)) { + if (!isEventMatchToSchema(vesEvent, applicationSettings.jsonSchema(version))) { + throw new EventValidatorException(ApiException.SCHEMA_VALIDATION_FAILED); } + } else { + throw new EventValidatorException(ApiException.INVALID_JSON_INPUT); } - return Optional.empty(); } - private Optional> errorResponse(ApiException noServerResources) { - return Optional.of(ResponseEntity.status(noServerResources.httpStatusCode) - .body(noServerResources.toJSON().toString())); + private boolean isEventMatchToSchema(VesEvent vesEvent, JsonSchema schema) { + return schemaValidator.conformsToSchema(vesEvent.asJsonObject(), schema); } } diff --git a/src/main/java/org/onap/dcae/restapi/EventValidatorException.java b/src/main/java/org/onap/dcae/restapi/EventValidatorException.java new file mode 100644 index 00000000..65ad457f --- /dev/null +++ b/src/main/java/org/onap/dcae/restapi/EventValidatorException.java @@ -0,0 +1,32 @@ +/* + * ============LICENSE_START======================================================= + * VES Collector + * ================================================================================ + * Copyright (C) 2020 Nokia. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.dcae.restapi; + +public class EventValidatorException extends Exception { + private final ApiException apiException; + + public EventValidatorException(ApiException apiException) { + this.apiException = apiException; + } + + public ApiException getApiException() { + return apiException; + } +} diff --git a/src/main/java/org/onap/dcae/restapi/VesRestController.java b/src/main/java/org/onap/dcae/restapi/VesRestController.java index b07b58df..f6dde6d2 100644 --- a/src/main/java/org/onap/dcae/restapi/VesRestController.java +++ b/src/main/java/org/onap/dcae/restapi/VesRestController.java @@ -1,9 +1,9 @@ /* * ============LICENSE_START======================================================= - * PROJECT + * VES Collector * ================================================================================ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. - * Copyright (C) 2018 Nokia. All rights reserved.s + * Copyright (C) 2020 Nokia. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,22 +21,18 @@ package org.onap.dcae.restapi; -import static org.springframework.http.ResponseEntity.accepted; -import static org.springframework.http.ResponseEntity.badRequest; - import com.att.nsa.clock.SaClock; import com.att.nsa.logging.LoggingContext; import com.att.nsa.logging.log4j.EcompFields; -import java.util.Optional; -import java.util.UUID; -import javax.servlet.http.HttpServletRequest; -import org.json.JSONArray; import org.json.JSONObject; import org.onap.dcae.ApplicationSettings; import org.onap.dcae.common.EventSender; -import org.onap.dcae.common.VESLogger; import org.onap.dcae.common.EventUpdater; import org.onap.dcae.common.HeaderUtils; +import org.onap.dcae.common.VESLogger; +import org.onap.dcae.common.model.StndDefinedNamespaceParameterHasEmptyValueException; +import org.onap.dcae.common.model.StndDefinedNamespaceParameterNotDefinedException; +import org.onap.dcae.common.model.VesEvent; import org.onap.dcaegen2.services.sdk.standardization.header.CustomHeaderUtils; import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; @@ -48,6 +44,13 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; +import javax.servlet.http.HttpServletRequest; +import java.util.List; +import java.util.UUID; + +import static org.springframework.http.ResponseEntity.accepted; +import static org.springframework.http.ResponseEntity.badRequest; + @RestController public class VesRestController { @@ -58,15 +61,19 @@ public class VesRestController { private final Logger requestLogger; private EventSender eventSender; private final HeaderUtils headerUtils; + private final EventValidator eventValidator; + private final EventUpdater eventUpdater; - @Autowired - VesRestController(ApplicationSettings settings, - @Qualifier("incomingRequestsLogger") Logger incomingRequestsLogger, - @Qualifier("eventSender") EventSender eventSender, HeaderUtils headerUtils) { + @Autowired + VesRestController(ApplicationSettings settings, + @Qualifier("incomingRequestsLogger") Logger incomingRequestsLogger, + @Qualifier("eventSender") EventSender eventSender, HeaderUtils headerUtils) { this.settings = settings; this.requestLogger = incomingRequestsLogger; this.eventSender = eventSender; this.headerUtils = headerUtils; + this.eventValidator = new EventValidator(settings); + this.eventUpdater = new EventUpdater(settings); } @PostMapping(value = {"/eventListener/{version}"}, consumes = "application/json") @@ -86,38 +93,54 @@ public class VesRestController { return badRequest().contentType(MediaType.APPLICATION_JSON).body(String.format("API version %s is not supported", version)); } - private ResponseEntity process(String events, String version, HttpServletRequest request, String type) { + private ResponseEntity process(String payload, String version, HttpServletRequest request, String type) { CustomHeaderUtils headerUtils = createHeaderUtils(version, request); - if(headerUtils.isOkCustomHeaders()){ - JSONObject jsonObject = new JSONObject(events); - - EventValidator eventValidator = new EventValidator(settings); - Optional> validationResult = eventValidator.validate(jsonObject, type, version); - - if (validationResult.isPresent()){ - return validationResult.get(); - } - JSONArray arrayOfEvents = new EventUpdater(settings).convert(jsonObject,version, generateUUID(version, request.getRequestURI(), jsonObject), type); - eventSender.send(arrayOfEvents); - // TODO call service and return status, replace CambriaClient, split event to single object and list of them - return accepted().headers(this.headerUtils.fillHeaders(headerUtils.getRspCustomHeader())) - .contentType(MediaType.APPLICATION_JSON).body("Accepted"); + if (headerUtils.isOkCustomHeaders()) { + final VesEvent vesEvent = new VesEvent(new JSONObject(payload)); + final String requestURI = request.getRequestURI(); + return handleEvent(vesEvent, version, type, headerUtils, requestURI); } return badRequest().body(String.format(ApiException.INVALID_CUSTOM_HEADER.toString())); } - private CustomHeaderUtils createHeaderUtils(String version, HttpServletRequest request){ - return new CustomHeaderUtils(version.toLowerCase().replace("v", ""), - headerUtils.extractHeaders(request), - headerUtils.getApiVerFilePath("api_version_config.json"), - headerUtils.getRestApiIdentify(request.getRequestURI())); + private ResponseEntity handleEvent(VesEvent vesEvent, String version, String type, CustomHeaderUtils headerUtils, String requestURI) { + try { + eventValidator.validate(vesEvent, type, version); + List vesEvents = transformEvent(vesEvent, type, version, requestURI); + eventSender.send(vesEvents); + } catch (EventValidatorException e) { + return ResponseEntity.status(e.getApiException().httpStatusCode) + .body(e.getApiException().toJSON().toString()); + } catch (StndDefinedNamespaceParameterNotDefinedException e) { + return ResponseEntity.status(ApiException.MISSING_NAMESPACE_PARAMETER.httpStatusCode) + .body(ApiException.MISSING_NAMESPACE_PARAMETER.toJSON().toString()); + } catch (StndDefinedNamespaceParameterHasEmptyValueException e) { + return ResponseEntity.status(ApiException.MISSING_NAMESPACE_PARAMETER.httpStatusCode) + .body(ApiException.EMPTY_NAMESPACE_PARAMETER.toJSON().toString()); + } + + // TODO call service and return status, replace CambriaClient, split event to single object and list of them + return accepted().headers(this.headerUtils.fillHeaders(headerUtils.getRspCustomHeader())) + .contentType(MediaType.APPLICATION_JSON).body("Accepted"); + } + + private CustomHeaderUtils createHeaderUtils(String version, HttpServletRequest request) { + return new CustomHeaderUtils(version.toLowerCase().replace("v", ""), + headerUtils.extractHeaders(request), + headerUtils.getApiVerFilePath("api_version_config.json"), + headerUtils.getRestApiIdentify(request.getRequestURI())); + + } + private List transformEvent(VesEvent vesEvent, String type, String version, String requestURI) { + return this.eventUpdater.convert( + vesEvent, version, generateUUID(vesEvent, version, requestURI), type); } - private UUID generateUUID(String version, String uri, JSONObject jsonObject) { + private UUID generateUUID(VesEvent vesEvent, String version, String uri) { UUID uuid = UUID.randomUUID(); setUpECOMPLoggingForRequest(uuid); - requestLogger.info(String.format(VES_EVENT_MESSAGE, jsonObject, uuid, version, uri)); + requestLogger.info(String.format(VES_EVENT_MESSAGE, vesEvent.asJsonObject(), uuid, version, uri)); return uuid; } @@ -125,4 +148,4 @@ public class VesRestController { LoggingContext localLC = VESLogger.getLoggingContextForThread(uuid); localLC.put(EcompFields.kBeginTimestampMs, SaClock.now()); } -} \ No newline at end of file +} diff --git a/src/test/java/org/onap/dcae/ApplicationSettingsTest.java b/src/test/java/org/onap/dcae/ApplicationSettingsTest.java index 3d8a1a1e..6560b1ce 100644 --- a/src/test/java/org/onap/dcae/ApplicationSettingsTest.java +++ b/src/test/java/org/onap/dcae/ApplicationSettingsTest.java @@ -288,7 +288,6 @@ public class ApplicationSettingsTest { // then JsonNode correctTestObject = new ObjectMapper().readTree("{ \"state\": \"hi\" }"); - ; assertTrue(schema.validate(correctTestObject).isEmpty()); } @@ -316,25 +315,25 @@ public class ApplicationSettingsTest { public void shouldReturnDMAAPStreamId() throws IOException { // given Map expected = HashMap.of( - "s", new String[]{"something", "something2"}, - "s2", new String[]{"something3"} + "log", new String[]{"ves-syslog", "ves-auditlog"}, + "fault", new String[]{"ves-fault"} ); // when Map dmaapStreamID = fromTemporaryConfiguration( - "collector.dmaap.streamid=s=something,something2|s2=something3") - .dMaaPStreamsMapping(); + "collector.dmaap.streamid=fault=ves-fault|log=ves-syslog,ves-auditlog") + .getDmaapStreamIds(); // then - assertArrayEquals(expected.get("s").get(), Objects.requireNonNull(dmaapStreamID).get("s").get()); - assertArrayEquals(expected.get("s2").get(), Objects.requireNonNull(dmaapStreamID).get("s2").get()); + assertArrayEquals(expected.get("log").get(), Objects.requireNonNull(dmaapStreamID).get("log").get()); + assertArrayEquals(expected.get("fault").get(), Objects.requireNonNull(dmaapStreamID).get("fault").get()); assertEquals(expected.keySet(), dmaapStreamID.keySet()); } @Test public void shouldReturnDefaultDMAAPStreamId() throws IOException { // when - Map dmaapStreamID = fromTemporaryConfiguration().dMaaPStreamsMapping(); + Map dmaapStreamID = fromTemporaryConfiguration().getDmaapStreamIds(); // then assertEquals(dmaapStreamID, HashMap.empty()); @@ -357,8 +356,8 @@ public class ApplicationSettingsTest { ).validAuthorizationCredentials(); // then - assertEquals(allowedUsers.get("pasza").get(), "c2ltcGxlcGFzc3dvcmQNCg=="); - assertEquals(allowedUsers.get("someoneelse").get(), "c2ltcGxlcGFzc3dvcmQNCg=="); + assertEquals( "c2ltcGxlcGFzc3dvcmQNCg==", allowedUsers.get("pasza").get()); + assertEquals("c2ltcGxlcGFzc3dvcmQNCg==", allowedUsers.get("someoneelse").get()); } @Test diff --git a/src/test/java/org/onap/dcae/common/EventSenderTest.java b/src/test/java/org/onap/dcae/common/EventSenderTest.java index f49d3cd8..e20fa993 100644 --- a/src/test/java/org/onap/dcae/common/EventSenderTest.java +++ b/src/test/java/org/onap/dcae/common/EventSenderTest.java @@ -3,7 +3,7 @@ * PROJECT * ================================================================================ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. - * Copyright (C) 2018 Nokia. All rights reserved.s + * Copyright (C) 2020 Nokia. All rights reserved.s * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,56 +20,122 @@ */ package org.onap.dcae.common; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - import io.vavr.collection.HashMap; -import io.vavr.collection.Map; -import org.json.JSONArray; import org.json.JSONObject; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; -import org.onap.dcae.ApplicationSettings; +import org.onap.dcae.common.model.StndDefinedNamespaceParameterNotDefinedException; +import org.onap.dcae.common.model.VesEvent; import org.onap.dcae.common.publishing.EventPublisher; +import java.io.IOException; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + @RunWith(MockitoJUnitRunner.Silent.class) public class EventSenderTest { - private String event = "{\"VESversion\":\"v7\",\"VESuniqueId\":\"fd69d432-5cd5-4c15-9d34-407c81c61c6a-0\",\"event\":{\"commonEventHeader\":{\"startEpochMicrosec\":1544016106000000,\"eventId\":\"fault33\",\"timeZoneOffset\":\"UTC+00.00\",\"priority\":\"Normal\",\"version\":\"4.0.1\",\"nfVendorName\":\"Ericsson\",\"reportingEntityName\":\"1\",\"sequence\":1,\"domain\":\"fault\",\"lastEpochMicrosec\":1544016106000000,\"eventName\":\"Fault_KeyFileFault\",\"vesEventListenerVersion\":\"7.0.1\",\"sourceName\":\"1\"},\"faultFields\":{\"eventSeverity\":\"CRITICAL\",\"alarmCondition\":\"KeyFileFault\",\"faultFieldsVersion\":\"4.0\",\"eventCategory\":\"PROCESSINGERRORALARM\",\"specificProblem\":\"License Key File Fault_1\",\"alarmAdditionalInformation\":{\"probableCause\":\"ConfigurationOrCustomizationError\",\"additionalText\":\"test_1\",\"source\":\"ManagedElement=1,SystemFunctions=1,Lm=1\"},\"eventSourceType\":\"Lm\",\"vfStatus\":\"Active\"}}}\n"; - @Mock private EventPublisher eventPublisher; - @Mock - private ApplicationSettings settings; - private EventSender eventSender; + @Test + public void shouldNotSendEventWhenStreamIdIsNotDefined() throws IOException { + // given + EventSender eventSender = givenConfiguredEventSender(HashMap.empty()); + List eventToSend = createEventToSend("/eventsAfterTransformation/ves7_valid_event.json"); + + // when + eventSender.send(eventToSend); + + // then + verifyThatEventWasNotSendAtStream(); + } @Test - public void shouldntSendEventWhenStreamIdsIsEmpty() { - when(settings.dMaaPStreamsMapping()).thenReturn(HashMap.empty()); - eventSender = new EventSender(eventPublisher, settings ); - JSONObject jsonObject = new JSONObject(event); - JSONArray jsonArray = new JSONArray(); - jsonArray.put(jsonObject); - eventSender.send(jsonArray); - verify(eventPublisher,never()).sendEvent(any(),any()); + public void shouldSendEventAtStreamsAssignedToEventDomain() throws IOException { + // given + EventSender eventSender = givenConfiguredEventSender(HashMap.of("fault", new String[]{"ves-fault", "fault-ves"})); + List eventToSend = createEventToSend("/eventsAfterTransformation/ves7_valid_event.json"); + + // when + eventSender.send(eventToSend); + + //then + verifyThatEventWasSendAtStream("ves-fault"); + verifyThatEventWasSendAtStream("fault-ves"); + } + + @Test + public void shouldSendStdDefinedEventAtStreamAssignedToEventDomain() throws IOException { + // given + EventSender eventSender = givenConfiguredEventSender( + HashMap.of("3GPP-FaultSupervision", new String[]{"ves-3gpp-fault-supervision"}) + ); + List eventToSend = createEventToSend("/eventsAfterTransformation/ves_stdnDefined_valid.json"); + + // when + eventSender.send(eventToSend); + + // then + verifyThatEventWasSendAtStream("ves-3gpp-fault-supervision"); } @Test - public void shouldSendEvent() { - Map streams = HashMap.of("fault", new String[]{"ves-fault", "fault-ves"}); - when(settings.dMaaPStreamsMapping()).thenReturn(streams); - eventSender = new EventSender(eventPublisher, settings ); + public void shouldNotSendStndEventWhenStreamIsNotDefined() throws IOException { + // given + EventSender eventSender = givenConfiguredEventSender(HashMap.empty()); + List eventToSend = createEventToSend("/eventsAfterTransformation/ves_stdnDefined_valid.json"); + + // when + eventSender.send(eventToSend); + + // then + verifyThatEventWasNotSendAtStream(); + } + + @Test + public void shouldReportThatNoStndDefinedNamespaceParameterIsDefinedInEvent() throws IOException { + // given + EventSender eventSender = givenConfiguredEventSender(HashMap.empty()); + List eventToSend = createEventToSend( + "/eventsAfterTransformation/ves_stdnDefined_missing_namespace_invalid.json" + ); + + // when + assertThatExceptionOfType(StndDefinedNamespaceParameterNotDefinedException.class) + .isThrownBy(() -> eventSender.send(eventToSend)); + + // then + verifyThatEventWasNotSendAtStream(); + } + + private List createEventToSend(String path) throws IOException { + String event = JsonDataLoader.loadContent(path); + return givenEventToSend(event); + } + + private EventSender givenConfiguredEventSender(io.vavr.collection.Map streamIds) { + return new EventSender(eventPublisher, streamIds); + } + + private List givenEventToSend(String event) { JSONObject jsonObject = new JSONObject(event); - JSONArray jsonArray = new JSONArray(); - jsonArray.put(jsonObject); - eventSender.send(jsonArray); - verify(eventPublisher, times(2)).sendEvent(any(),any()); + return List.of(new VesEvent(jsonObject)); + } + + private void verifyThatEventWasNotSendAtStream() { + verify(eventPublisher,never()).sendEvent(any(),any()); + } + + private void verifyThatEventWasSendAtStream(String s) { + verify(eventPublisher).sendEvent(any(), eq(s)); } -} \ No newline at end of file +} diff --git a/src/test/java/org/onap/dcae/common/JsonDataLoader.java b/src/test/java/org/onap/dcae/common/JsonDataLoader.java new file mode 100644 index 00000000..2ea59aa0 --- /dev/null +++ b/src/test/java/org/onap/dcae/common/JsonDataLoader.java @@ -0,0 +1,49 @@ +/* + * ============LICENSE_START======================================================= + * VES Collector + * ================================================================================ + * Copyright (C) 2020 Nokia. All rights reserved.s + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.dcae.common; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; + +/** + * This class is static and does not have public constructor. + * It is responsible for data loading fot test cases. + * + * @author Zebek + */ +public final class JsonDataLoader { + + private JsonDataLoader() { + } + + /** + * This method is validating given event using schema adn throws exception if event is not valid + * + * @param path to file that will be loaded + * @return contend of the file located under path, given in parameters, as string + * @throws IOException when file under given path was not found + */ + public static String loadContent(String path) throws IOException { + return new String( + Files.readAllBytes(Paths.get(JsonDataLoader.class.getResource(path).getPath())) + ); + } +} diff --git a/src/test/java/org/onap/dcae/common/model/VesEventTest.java b/src/test/java/org/onap/dcae/common/model/VesEventTest.java new file mode 100644 index 00000000..c66e0a9b --- /dev/null +++ b/src/test/java/org/onap/dcae/common/model/VesEventTest.java @@ -0,0 +1,92 @@ +/* + * ============LICENSE_START======================================================= + * VES Collector + * ================================================================================ + * Copyright (C) 2020 Nokia. All rights reserved.s + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.dcae.common.model; + +import org.assertj.core.api.Assertions; +import org.json.JSONObject; +import org.junit.Test; +import org.onap.dcae.common.JsonDataLoader; + +import java.io.IOException; + +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; + +public class VesEventTest { + + private static final String FAULT_DOMAIN = "fault"; + private static final String FAULT_STREAM_ID = "fault"; + private static final String STND_DEFINED_DOMAIN = "stndDefined"; + private static final String STND_DEFINED_STREAM_ID = "3GPP-FaultSupervision"; + + @Test + public void shouldReturnsOriginalDomainForNonStdEvent() throws IOException { + // given + final VesEvent vesEvent = createVesEvent("/eventsAfterTransformation/ves7_valid_event.json"); + + // when/then + Assertions.assertThat(vesEvent.getDomain()).isEqualTo(FAULT_DOMAIN); + Assertions.assertThat(vesEvent.getStreamId()).isEqualTo(FAULT_STREAM_ID); + } + + @Test + public void shouldReturnsDomainStoredInStndDefinedNamespaceParameterForNonStdEvent() throws IOException { + // given + final VesEvent vesEvent = createVesEvent("/eventsAfterTransformation/ves_stdnDefined_valid.json"); + + // when/then + Assertions.assertThat(vesEvent.getDomain()).isEqualTo(STND_DEFINED_DOMAIN); + Assertions.assertThat(vesEvent.getStreamId()).isEqualTo(STND_DEFINED_STREAM_ID); + } + + + @Test + public void shouldReportThatStndDefinedNamespaceParameterIsNotDefinedInEvent() throws IOException { + // given + final VesEvent vesEvent = createVesEvent( + "/eventsAfterTransformation/ves_stdnDefined_missing_namespace_invalid.json" + ); + + // when/then + // when + assertThatExceptionOfType(StndDefinedNamespaceParameterNotDefinedException.class) + .isThrownBy(() -> { + vesEvent.getStreamId(); + }); + } + + @Test + public void shouldReportThatStndDefinedNamespaceParameterHasEmptyValue() throws IOException { + // given + final VesEvent vesEvent = createVesEvent( + "/eventsAfterTransformation/ves_stdnDefined_empty_namespace_invalid.json" + ); + + // when/then + assertThatExceptionOfType(StndDefinedNamespaceParameterHasEmptyValueException.class) + .isThrownBy(() -> { + vesEvent.getStreamId(); + }); + } + + private VesEvent createVesEvent(String path) throws IOException { + String event = JsonDataLoader.loadContent(path); + return new VesEvent(new JSONObject(event)); + } +} diff --git a/src/test/java/org/onap/dcae/restapi/EventValidatorTest.java b/src/test/java/org/onap/dcae/restapi/EventValidatorTest.java index 0d38fdac..0ca5c424 100644 --- a/src/test/java/org/onap/dcae/restapi/EventValidatorTest.java +++ b/src/test/java/org/onap/dcae/restapi/EventValidatorTest.java @@ -20,28 +20,29 @@ package org.onap.dcae.restapi; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; - import com.networknt.schema.JsonSchema; import com.networknt.schema.JsonSchemaFactory; - -import java.util.Optional; - import org.json.JSONObject; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.onap.dcae.ApplicationSettings; import org.onap.dcae.FileReader; -import org.springframework.http.ResponseEntity; +import org.onap.dcae.common.model.VesEvent; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) -public class EventValidatorTest { +class EventValidatorTest { private static final String DUMMY_SCHEMA_VERSION = "v5"; private static final String DUMMY_TYPE = "type"; private final String newSchemaV7 = FileReader.readFileAsString("etc/CommonEventFormat_30.2_ONAP.json"); @@ -51,10 +52,11 @@ public class EventValidatorTest { private static final String EVENT_TYPE = "event"; @Mock - private static ApplicationSettings settings; + private ApplicationSettings settings; + + private SchemaValidator schemaValidator = spy( new SchemaValidator()); - @InjectMocks - private static EventValidator sut; + private EventValidator sut; @BeforeAll @@ -62,57 +64,70 @@ public class EventValidatorTest { jsonObject = new JSONObject("{" + DUMMY_TYPE + ":dummy}"); } + @BeforeEach + public void setUp(){ + this.sut = new EventValidator(settings, schemaValidator); + } + @Test - public void shouldReturnEmptyOptionalOnJsonSchemaValidationDisabled() { + void shouldNotValidateEventWhenJsonSchemaValidationDisabled() throws EventValidatorException { //given when(settings.eventSchemaValidationEnabled()).thenReturn(false); //when - Optional> result = sut.validate(jsonObject, DUMMY_TYPE, DUMMY_SCHEMA_VERSION); + this.sut.validate(new VesEvent(jsonObject), DUMMY_TYPE, DUMMY_SCHEMA_VERSION); //then - assertEquals(Optional.empty(), result); + verify(schemaValidator, never()).conformsToSchema(any(), any()); } @Test - public void shouldReturnInvalidJsonErrorOnWrongType() { + void shouldReturnInvalidJsonErrorOnWrongType() { //given when(settings.eventSchemaValidationEnabled()).thenReturn(true); //when - Optional> result = sut.validate(jsonObject, "wrongType", DUMMY_SCHEMA_VERSION); + try { + sut.validate(new VesEvent(jsonObject), "wrongType", DUMMY_SCHEMA_VERSION); + } catch (EventValidatorException e) { + //then + assertEquals(ApiException.INVALID_JSON_INPUT, e.getApiException()); + } + - //then - assertEquals(generateResponseOptional(ApiException.INVALID_JSON_INPUT), result); } @Test - public void shouldReturnSchemaValidationFailedErrorOnInvalidJsonObjectSchema() { + void shouldReturnSchemaValidationFailedErrorOnInvalidJsonObjectSchema() { //given String schemaRejectingEverything = "{\"not\":{}}"; mockJsonSchema(schemaRejectingEverything); when(settings.eventSchemaValidationEnabled()).thenReturn(true); //when - Optional> result = sut.validate(jsonObject, DUMMY_TYPE, DUMMY_SCHEMA_VERSION); + try { + sut.validate(new VesEvent(jsonObject), DUMMY_TYPE, DUMMY_SCHEMA_VERSION); + } catch (EventValidatorException e) { + //then + assertEquals(ApiException.SCHEMA_VALIDATION_FAILED, e.getApiException()); + } - //then - assertEquals(generateResponseOptional(ApiException.SCHEMA_VALIDATION_FAILED), result); } @Test - public void shouldReturnEmptyOptionalOnValidJsonObjectSchema() { + void shouldReturnEmptyOptionalOnValidJsonObjectSchema() { //given String schemaAcceptingEverything = "{}"; mockJsonSchema(schemaAcceptingEverything); when(settings.eventSchemaValidationEnabled()).thenReturn(true); //when - Optional> result = sut.validate(jsonObject, DUMMY_TYPE, DUMMY_SCHEMA_VERSION); - - //then - assertEquals(Optional.empty(), result); + try { + sut.validate(new VesEvent(jsonObject), DUMMY_TYPE, DUMMY_SCHEMA_VERSION); + } catch (EventValidatorException e) { + failWithError(); + } } @Test @@ -124,14 +139,15 @@ public class EventValidatorTest { when(settings.eventSchemaValidationEnabled()).thenReturn(true); //when - Optional> result = sut.validate(sentEvent, EVENT_TYPE, V7_VERSION); - - //then - assertEquals(Optional.empty(), result); + try { + sut.validate(new VesEvent(sentEvent), EVENT_TYPE, V7_VERSION); + } catch (EventValidatorException e) { + failWithError(); + } } @Test - public void shouldReturnNoErrorsWhenValidatingValidEventWithStndDefinedFields() { + void shouldReturnNoErrorsWhenValidatingValidEventWithStndDefinedFields() { //given sentEvent = new JSONObject(FileReader.readFileAsString("src/test/resources/ves7_valid_eventWithStndDefinedFields.json")); @@ -139,14 +155,15 @@ public class EventValidatorTest { when(settings.eventSchemaValidationEnabled()).thenReturn(true); //when - Optional> result = sut.validate(sentEvent, EVENT_TYPE, V7_VERSION); - - //then - assertEquals(Optional.empty(), result); + try { + sut.validate(new VesEvent(sentEvent), EVENT_TYPE, V7_VERSION); + } catch (EventValidatorException e) { + failWithError(); + } } @Test - public void shouldReturnSchemaValidationFailedWhenValidating30_1_1InvalidEvent() { + void shouldReturnSchemaValidationFailedWhenValidating30_1_1InvalidEvent() { //given sentEvent = new JSONObject(FileReader.readFileAsString("src/test/resources/ves7_invalid_30_1_1_event.json")); @@ -154,12 +171,19 @@ public class EventValidatorTest { when(settings.eventSchemaValidationEnabled()).thenReturn(true); //when - Optional> result = sut.validate(this.sentEvent, EVENT_TYPE, V7_VERSION); + try { + sut.validate(new VesEvent(this.sentEvent), EVENT_TYPE, V7_VERSION); + } catch (EventValidatorException e) { + //then + assertEquals(ApiException.SCHEMA_VALIDATION_FAILED, e.getApiException()); + } + - //then - assertEquals(generateResponseOptional(ApiException.SCHEMA_VALIDATION_FAILED), result); } + private void failWithError() { + fail("Validation should not report any error!"); + } private void mockJsonSchema(String jsonSchemaContent) { JsonSchemaFactory factory = JsonSchemaFactory.getInstance(); @@ -167,9 +191,4 @@ public class EventValidatorTest { JsonSchema schema = factory.getSchema(jsonSchemaContent); when(settings.jsonSchema(any())).thenReturn(schema); } - - private Optional> generateResponseOptional(ApiException schemaValidationFailed) { - return Optional.of(ResponseEntity.status(schemaValidationFailed.httpStatusCode) - .body(schemaValidationFailed.toJSON().toString())); - } } diff --git a/src/test/java/org/onap/dcae/restapi/VesRestControllerTest.java b/src/test/java/org/onap/dcae/restapi/VesRestControllerTest.java index 6b89a356..e5e7239c 100644 --- a/src/test/java/org/onap/dcae/restapi/VesRestControllerTest.java +++ b/src/test/java/org/onap/dcae/restapi/VesRestControllerTest.java @@ -20,20 +20,27 @@ package org.onap.dcae.restapi; +import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.reflect.TypeToken; import com.google.gson.Gson; +import com.networknt.schema.JsonSchema; +import io.vavr.collection.HashMap; +import org.apache.http.HttpStatus; import org.jetbrains.annotations.NotNull; -import org.json.JSONArray; +import org.json.JSONObject; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; -import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import org.onap.dcae.ApplicationSettings; +import org.onap.dcae.JSonSchemasSupplier; import org.onap.dcae.common.EventSender; import org.onap.dcae.common.EventTransformation; import org.onap.dcae.common.HeaderUtils; +import org.onap.dcae.common.JsonDataLoader; +import org.onap.dcae.common.publishing.EventPublisher; import org.slf4j.Logger; import org.springframework.http.ResponseEntity; import org.springframework.mock.web.MockHttpServletRequest; @@ -43,14 +50,15 @@ import org.springframework.web.context.request.ServletRequestAttributes; import java.io.FileReader; import java.io.IOException; import java.lang.reflect.Type; -import java.nio.file.Files; -import java.nio.file.Paths; import java.util.List; +import java.util.Map; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -58,21 +66,36 @@ import static org.mockito.Mockito.when; public class VesRestControllerTest { private static final String EVENT_TRANSFORM_FILE_PATH = "/eventTransform.json"; + private static final String ACCEPTED = "Accepted"; + private static final String VERSION_V7 = "v7"; + public static final String VES_FAULT_TOPIC = "ves-fault"; + public static final String VES_3_GPP_FAULT_SUPERVISION_TOPIC = "ves-3gpp-fault-supervision"; - @InjectMocks - VesRestController vesRestController; + private VesRestController vesRestController; @Mock - ApplicationSettings applicationSettings; + private ApplicationSettings applicationSettings; @Mock - Logger logger; + private Logger logger; @Mock - EventSender eventSender; + private HeaderUtils headerUtils; @Mock - HeaderUtils headerUtils; + private EventPublisher eventPublisher; + + @Before + public void setUp(){ + + final HashMap streamIds = HashMap.of( + "fault", new String[]{VES_FAULT_TOPIC}, + "3GPP-FaultSupervision", new String[]{VES_3_GPP_FAULT_SUPERVISION_TOPIC} + ); + this.vesRestController = new VesRestController( + applicationSettings, logger, new EventSender(eventPublisher, streamIds),headerUtils + ); + } @Test public void shouldReportThatApiVersionIsNotSupported() { @@ -84,9 +107,9 @@ public class VesRestControllerTest { final ResponseEntity event = vesRestController.event("", "v20", request); // then - assertThat(event.getStatusCodeValue()).isEqualTo(400); + assertThat(event.getStatusCodeValue()).isEqualTo(HttpStatus.SC_BAD_REQUEST); assertThat(event.getBody()).isEqualTo("API version v20 is not supported"); - verify(eventSender, never()).send(any(JSONArray.class)); + verifyThatEventWasNotSend(); } @Test @@ -97,22 +120,153 @@ public class VesRestControllerTest { MockHttpServletRequest request = givenMockHttpServletRequest(); - String validEvent = new String( - Files.readAllBytes(Paths.get(this.getClass().getResource("/ves7_valid_30_1_1_event.json").getPath())) + String validEvent = JsonDataLoader.loadContent("/ves7_valid_30_1_1_event.json"); + + //when + final ResponseEntity response = vesRestController.event(validEvent, VERSION_V7, request); + + //then + assertThat(response.getStatusCodeValue()).isEqualTo(HttpStatus.SC_ACCEPTED); + assertThat(response.getBody()).isEqualTo(ACCEPTED); + verifyThatTransformedEventWasSend(eventPublisher, validEvent); + } + + + @Test + public void shouldSendBatchOfEvents() throws IOException { + //given + configureEventTransformations(); + configureHeadersForEventListener(); + + MockHttpServletRequest request = givenMockHttpServletRequest(); + + String validEvent = JsonDataLoader.loadContent("/ves7_batch_valid.json"); + + //when + final ResponseEntity response = vesRestController.events(validEvent, VERSION_V7, request); + + //then + assertThat(response.getStatusCodeValue()).isEqualTo(HttpStatus.SC_ACCEPTED); + assertThat(response.getBody()).isEqualTo(ACCEPTED); + verify(eventPublisher, times(2)).sendEvent(any(),any()); + } + + @Test + public void shouldSendStndDomainEventIntoDomainStream() throws IOException { + //given + configureEventTransformations(); + configureHeadersForEventListener(); + + MockHttpServletRequest request = givenMockHttpServletRequest(); + configureSchemasSupplierForStndDefineEvent(); + + String validEvent = JsonDataLoader.loadContent("/ves_stdnDefined_valid.json"); + + //when + final ResponseEntity response = vesRestController.event(validEvent, VERSION_V7, request); + + //then + assertThat(response.getStatusCodeValue()).isEqualTo(HttpStatus.SC_ACCEPTED); + assertThat(response.getBody()).isEqualTo(ACCEPTED); + verify(eventPublisher).sendEvent(any(),eq(VES_3_GPP_FAULT_SUPERVISION_TOPIC)); + } + + + @Test + public void shouldReportThatStndDomainEventHasntGotNamespaceParameter() throws IOException { + //given + configureEventTransformations(); + configureHeadersForEventListener(); + + MockHttpServletRequest request = givenMockHttpServletRequest(); + configureSchemasSupplierForStndDefineEvent(); + + String validEvent = JsonDataLoader.loadContent("/ves_stdnDefined_missing_namespace_invalid.json"); + + //when + final ResponseEntity response = vesRestController.event(validEvent, VERSION_V7, request); + + //then + assertThat(response.getStatusCodeValue()).isEqualTo(HttpStatus.SC_BAD_REQUEST); + verifyErrorResponse( + response, + "SVC2006", + "Mandatory input attribute event.commonEventHeader.stndDefinedNamespace is missing from request" ); + verifyThatEventWasNotSend(); + } + + @Test + public void shouldReportThatStndDomainEventNamespaceParameterIsEmpty() throws IOException { + //given + configureEventTransformations(); + configureHeadersForEventListener(); + + MockHttpServletRequest request = givenMockHttpServletRequest(); + configureSchemasSupplierForStndDefineEvent(); + + String validEvent = JsonDataLoader.loadContent("/ves_stdnDefined_empty_namespace_invalid.json"); //when - final ResponseEntity response = vesRestController.event(validEvent, "v7", request); + final ResponseEntity response = vesRestController.event(validEvent, VERSION_V7, request); //then - assertThat(response.getStatusCodeValue()).isEqualTo(202); - assertThat(response.getBody()).isEqualTo("Accepted"); - verifyThatTransformedEventWasSend(eventSender, validEvent); + assertThat(response.getStatusCodeValue()).isEqualTo(HttpStatus.SC_BAD_REQUEST); + verifyErrorResponse( + response, + "SVC2006", + "Mandatory input attribute event.commonEventHeader.stndDefinedNamespace is empty in request" + ); + verifyThatEventWasNotSend(); + } + + @Test + public void shouldNotSendStndDomainEventWhenTopicCannotBeFoundInConfiguration() throws IOException { + //given + configureEventTransformations(); + configureHeadersForEventListener(); + + MockHttpServletRequest request = givenMockHttpServletRequest(); + + String validEvent = JsonDataLoader.loadContent("/ves_stdnDefined_valid_unknown_topic.json"); + + //when + final ResponseEntity response = vesRestController.event(validEvent, VERSION_V7, request); + + //then + assertThat(response.getStatusCodeValue()).isEqualTo(HttpStatus.SC_ACCEPTED); + assertThat(response.getBody()).isEqualTo(ACCEPTED); + verifyThatEventWasNotSend(); + } + + private void verifyThatEventWasNotSend() { + verify(eventPublisher, never()).sendEvent(any(), any()); + } + + private void configureSchemasSupplierForStndDefineEvent() { + String collectorSchemaFile = "{\"v7\":\"./etc/CommonEventFormat_30.2_ONAP.json\"}"; + final io.vavr.collection.Map loadedJsonSchemas = new JSonSchemasSupplier().loadJsonSchemas(collectorSchemaFile); + + when(applicationSettings.eventSchemaValidationEnabled()).thenReturn(true); + when(applicationSettings.jsonSchema(eq(VERSION_V7))).thenReturn(loadedJsonSchemas.get(VERSION_V7).get()); + } + + private void verifyErrorResponse(ResponseEntity response, String messageId, String messageText) throws com.fasterxml.jackson.core.JsonProcessingException { + final Map errorDetails = fetchErrorDetails(response); + assertThat(errorDetails).containsEntry("messageId", messageId); + assertThat(errorDetails).containsEntry("text", messageText); + } + + private Map fetchErrorDetails(ResponseEntity response) throws com.fasterxml.jackson.core.JsonProcessingException { + final String body = response.getBody(); + ObjectMapper mapper = new ObjectMapper(); + Map>> map = mapper.readValue(body, Map.class); + return map.get("requestError").get("ServiceException"); } private void configureEventTransformations() throws IOException { final List eventTransformations = loadEventTransformations(); - when(applicationSettings.isVersionSupported("v7")).thenReturn(true); + when(applicationSettings.isVersionSupported(VERSION_V7)).thenReturn(true); when(applicationSettings.eventTransformingEnabled()).thenReturn(true); when(applicationSettings.getEventTransformations()).thenReturn(eventTransformations); } @@ -124,19 +278,22 @@ public class VesRestControllerTest { ); } - private void verifyThatTransformedEventWasSend(EventSender eventSender, String eventBeforeTransformation) { + private void verifyThatTransformedEventWasSend(EventPublisher eventPublisher, String eventBeforeTransformation) { // event before transformation assertThat(eventBeforeTransformation).contains("\"version\": \"4.0.1\""); assertThat(eventBeforeTransformation).contains("\"faultFieldsVersion\": \"4.0\""); - ArgumentCaptor argument = ArgumentCaptor.forClass(JSONArray.class); - verify(eventSender).send(argument.capture()); + ArgumentCaptor argument = ArgumentCaptor.forClass(JSONObject.class); + ArgumentCaptor domain = ArgumentCaptor.forClass(String.class); + verify(eventPublisher).sendEvent(argument.capture(), domain.capture()); final String transformedEvent = argument.getValue().toString(); + final String eventSentAtTopic = domain.getValue(); // event after transformation assertThat(transformedEvent).contains("\"priority\":\"High\",\"version\":3,"); assertThat(transformedEvent).contains(",\"faultFieldsVersion\":3,\"specificProblem"); + assertThat(eventSentAtTopic).isEqualTo(VES_FAULT_TOPIC); } @NotNull diff --git a/src/test/resources/eventsAfterTransformation/ves7_valid_event.json b/src/test/resources/eventsAfterTransformation/ves7_valid_event.json new file mode 100644 index 00000000..d3977336 --- /dev/null +++ b/src/test/resources/eventsAfterTransformation/ves7_valid_event.json @@ -0,0 +1,36 @@ +{ + "VESversion":"v7", + "VESuniqueId":"fd69d432-5cd5-4c15-9d34-407c81c61c6a-0", + "event": { + "commonEventHeader": { + "version": "4.0.1", + "vesEventListenerVersion": "7.0.1", + "domain": "fault", + "eventName": "Fault_Vscf:Acs-Ericcson_PilotNumberPoolExhaustion", + "eventId": "fault0000245", + "sequence": 1, + "priority": "High", + "reportingEntityId": "cc305d54-75b4-431b-adb2-eb6b9e541234", + "reportingEntityName": "ibcx0001vm002oam001", + "sourceId": "de305d54-75b4-431b-adb2-eb6b9e546014", + "sourceName": "scfx0001vm002cap001", + "nfVendorName": "Ericsson", + "nfNamingCode": "scfx", + "nfcNamingCode": "ssc", + "startEpochMicrosec": 1413378172000000, + "lastEpochMicrosec": 1413378172000000, + "timeZoneOffset": "UTC-05:30" + }, + "faultFields": { + "faultFieldsVersion": "4.0", + "alarmCondition": "PilotNumberPoolExhaustion", + "eventSourceType": "other", + "specificProblem": "Calls cannot complete - pilot numbers are unavailable", + "eventSeverity": "CRITICAL", + "vfStatus": "Active", + "alarmAdditionalInformation": { + "PilotNumberPoolSize": "1000" + } + } + } +} diff --git a/src/test/resources/eventsAfterTransformation/ves_stdnDefined_empty_namespace_invalid.json b/src/test/resources/eventsAfterTransformation/ves_stdnDefined_empty_namespace_invalid.json new file mode 100644 index 00000000..63d682fd --- /dev/null +++ b/src/test/resources/eventsAfterTransformation/ves_stdnDefined_empty_namespace_invalid.json @@ -0,0 +1,47 @@ +{ + "VESversion":"v7", + "VESuniqueId":"fd69d432-5cd5-4c15-9d34-407c81c61c6a-0", + "event": { + "commonEventHeader": { + "domain": "stndDefined", + "eventId": "stndDefined-gNB_Nokia000001", + "eventName": "stndDefined-gNB-Nokia-PowerLost", + "stndDefinedNamespace": "", + "lastEpochMicrosec": 1234567890, + "priority": "Normal", + "reportingEntityName": "Nokia123456", + "sequence": 0, + "sourceName": "Nokia123456", + "startEpochMicrosec": 1234567890, + "version": "4.1", + "vesEventListenerVersion": "7.2" + }, + "stndDefinedFields": { + "schemaReference": "https://www.3gpp.org/Rel-16/TS28532_generic_fault_supervision.json#definitions/schemas/notifyNewAlarm-NotifType", + "data": { + "uri": "xyz", + "notificationId": "xyz", + "notificationType": "notifyNewAlarm", + "eventTime": "xyz", + "systemDN": "xyz", + "probableCause": "xyz", + "perceivedSeverity": "Major", + "rootCauseIndicator": false, + "specificProblem": "xyz", + "correlatedNotifications": [], + "backedUpStatus": true, + "backUpObject": "xyz", + "trendIndication": "No change", + "thresholdInfo": {}, + "stateChangeDefinition": [], + "monitoredAttributes": [], + "proposedRepairActions": "xyz", + "additionalText": "xyz", + "additionalInformation": [], + "alarmId": "xyz", + "alarmType": "Environmental Alarm" + }, + "stndDefinedFieldsVersion": "1.0" + } + } +} diff --git a/src/test/resources/eventsAfterTransformation/ves_stdnDefined_missing_namespace_invalid.json b/src/test/resources/eventsAfterTransformation/ves_stdnDefined_missing_namespace_invalid.json new file mode 100644 index 00000000..b9628926 --- /dev/null +++ b/src/test/resources/eventsAfterTransformation/ves_stdnDefined_missing_namespace_invalid.json @@ -0,0 +1,46 @@ +{ + "VESversion":"v7", + "VESuniqueId":"fd69d432-5cd5-4c15-9d34-407c81c61c6a-0", + "event": { + "commonEventHeader": { + "domain": "stndDefined", + "eventId": "stndDefined-gNB_Nokia000001", + "eventName": "stndDefined-gNB-Nokia-PowerLost", + "lastEpochMicrosec": 1234567890, + "priority": "Normal", + "reportingEntityName": "Nokia123456", + "sequence": 0, + "sourceName": "Nokia123456", + "startEpochMicrosec": 1234567890, + "version": "4.1", + "vesEventListenerVersion": "7.2" + }, + "stndDefinedFields": { + "schemaReference": "https://www.3gpp.org/Rel-16/TS28532_generic_fault_supervision.json#definitions/schemas/notifyNewAlarm-NotifType", + "data": { + "uri": "xyz", + "notificationId": "xyz", + "notificationType": "notifyNewAlarm", + "eventTime": "xyz", + "systemDN": "xyz", + "probableCause": "xyz", + "perceivedSeverity": "Major", + "rootCauseIndicator": false, + "specificProblem": "xyz", + "correlatedNotifications": [], + "backedUpStatus": true, + "backUpObject": "xyz", + "trendIndication": "No change", + "thresholdInfo": {}, + "stateChangeDefinition": [], + "monitoredAttributes": [], + "proposedRepairActions": "xyz", + "additionalText": "xyz", + "additionalInformation": [], + "alarmId": "xyz", + "alarmType": "Environmental Alarm" + }, + "stndDefinedFieldsVersion": "1.0" + } + } +} diff --git a/src/test/resources/eventsAfterTransformation/ves_stdnDefined_valid.json b/src/test/resources/eventsAfterTransformation/ves_stdnDefined_valid.json new file mode 100644 index 00000000..dfae48fc --- /dev/null +++ b/src/test/resources/eventsAfterTransformation/ves_stdnDefined_valid.json @@ -0,0 +1,47 @@ +{ + "VESversion":"v7", + "VESuniqueId":"fd69d432-5cd5-4c15-9d34-407c81c61c6a-0", + "event": { + "commonEventHeader": { + "domain": "stndDefined", + "eventId": "stndDefined-gNB_Nokia000001", + "eventName": "stndDefined-gNB-Nokia-PowerLost", + "stndDefinedNamespace": "3GPP-FaultSupervision", + "lastEpochMicrosec": 1234567890, + "priority": "Normal", + "reportingEntityName": "Nokia123456", + "sequence": 0, + "sourceName": "Nokia123456", + "startEpochMicrosec": 1234567890, + "version": "4.1", + "vesEventListenerVersion": "7.2" + }, + "stndDefinedFields": { + "schemaReference": "https://www.3gpp.org/Rel-16/TS28532_generic_fault_supervision.json#definitions/schemas/notifyNewAlarm-NotifType", + "data": { + "uri": "xyz", + "notificationId": "xyz", + "notificationType": "notifyNewAlarm", + "eventTime": "xyz", + "systemDN": "xyz", + "probableCause": "xyz", + "perceivedSeverity": "Major", + "rootCauseIndicator": false, + "specificProblem": "xyz", + "correlatedNotifications": [], + "backedUpStatus": true, + "backUpObject": "xyz", + "trendIndication": "No change", + "thresholdInfo": {}, + "stateChangeDefinition": [], + "monitoredAttributes": [], + "proposedRepairActions": "xyz", + "additionalText": "xyz", + "additionalInformation": [], + "alarmId": "xyz", + "alarmType": "Environmental Alarm" + }, + "stndDefinedFieldsVersion": "1.0" + } + } +} diff --git a/src/test/resources/ves_stdnDefined_empty_namespace_invalid.json b/src/test/resources/ves_stdnDefined_empty_namespace_invalid.json new file mode 100644 index 00000000..bf5f0953 --- /dev/null +++ b/src/test/resources/ves_stdnDefined_empty_namespace_invalid.json @@ -0,0 +1,45 @@ +{ + "event": { + "commonEventHeader": { + "domain": "stndDefined", + "eventId": "stndDefined-gNB_Nokia000001", + "eventName": "stndDefined-gNB-Nokia-PowerLost", + "stndDefinedNamespace": "", + "lastEpochMicrosec": 1234567890, + "priority": "Normal", + "reportingEntityName": "Nokia123456", + "sequence": 0, + "sourceName": "Nokia123456", + "startEpochMicrosec": 1234567890, + "version": "4.1", + "vesEventListenerVersion": "7.2" + }, + "stndDefinedFields": { + "schemaReference": "https://www.3gpp.org/Rel-16/TS28532_generic_fault_supervision.json#definitions/schemas/notifyNewAlarm-NotifType", + "data": { + "uri": "xyz", + "notificationId": "xyz", + "notificationType": "notifyNewAlarm", + "eventTime": "xyz", + "systemDN": "xyz", + "probableCause": "xyz", + "perceivedSeverity": "Major", + "rootCauseIndicator": false, + "specificProblem": "xyz", + "correlatedNotifications": [], + "backedUpStatus": true, + "backUpObject": "xyz", + "trendIndication": "No change", + "thresholdInfo": {}, + "stateChangeDefinition": [], + "monitoredAttributes": [], + "proposedRepairActions": "xyz", + "additionalText": "xyz", + "additionalInformation": [], + "alarmId": "xyz", + "alarmType": "Environmental Alarm" + }, + "stndDefinedFieldsVersion": "1.0" + } + } +} diff --git a/src/test/resources/ves_stdnDefined_missing_namespace_invalid.json b/src/test/resources/ves_stdnDefined_missing_namespace_invalid.json new file mode 100644 index 00000000..230dc54e --- /dev/null +++ b/src/test/resources/ves_stdnDefined_missing_namespace_invalid.json @@ -0,0 +1,44 @@ +{ + "event": { + "commonEventHeader": { + "domain": "stndDefined", + "eventId": "stndDefined-gNB_Nokia000001", + "eventName": "stndDefined-gNB-Nokia-PowerLost", + "lastEpochMicrosec": 1234567890, + "priority": "Normal", + "reportingEntityName": "Nokia123456", + "sequence": 0, + "sourceName": "Nokia123456", + "startEpochMicrosec": 1234567890, + "version": "4.1", + "vesEventListenerVersion": "7.2" + }, + "stndDefinedFields": { + "schemaReference": "https://www.3gpp.org/Rel-16/TS28532_generic_fault_supervision.json#definitions/schemas/notifyNewAlarm-NotifType", + "data": { + "uri": "xyz", + "notificationId": "xyz", + "notificationType": "notifyNewAlarm", + "eventTime": "xyz", + "systemDN": "xyz", + "probableCause": "xyz", + "perceivedSeverity": "Major", + "rootCauseIndicator": false, + "specificProblem": "xyz", + "correlatedNotifications": [], + "backedUpStatus": true, + "backUpObject": "xyz", + "trendIndication": "No change", + "thresholdInfo": {}, + "stateChangeDefinition": [], + "monitoredAttributes": [], + "proposedRepairActions": "xyz", + "additionalText": "xyz", + "additionalInformation": [], + "alarmId": "xyz", + "alarmType": "Environmental Alarm" + }, + "stndDefinedFieldsVersion": "1.0" + } + } +} diff --git a/src/test/resources/ves_stdnDefined_valid.json b/src/test/resources/ves_stdnDefined_valid.json new file mode 100644 index 00000000..aa026e71 --- /dev/null +++ b/src/test/resources/ves_stdnDefined_valid.json @@ -0,0 +1,45 @@ +{ + "event": { + "commonEventHeader": { + "domain": "stndDefined", + "eventId": "stndDefined-gNB_Nokia000001", + "eventName": "stndDefined-gNB-Nokia-PowerLost", + "stndDefinedNamespace": "3GPP-FaultSupervision", + "lastEpochMicrosec": 1234567890, + "priority": "Normal", + "reportingEntityName": "Nokia123456", + "sequence": 0, + "sourceName": "Nokia123456", + "startEpochMicrosec": 1234567890, + "version": "4.1", + "vesEventListenerVersion": "7.2" + }, + "stndDefinedFields": { + "schemaReference": "https://www.3gpp.org/Rel-16/TS28532_generic_fault_supervision.json#definitions/schemas/notifyNewAlarm-NotifType", + "data": { + "uri": "xyz", + "notificationId": "xyz", + "notificationType": "notifyNewAlarm", + "eventTime": "xyz", + "systemDN": "xyz", + "probableCause": "xyz", + "perceivedSeverity": "Major", + "rootCauseIndicator": false, + "specificProblem": "xyz", + "correlatedNotifications": [], + "backedUpStatus": true, + "backUpObject": "xyz", + "trendIndication": "No change", + "thresholdInfo": {}, + "stateChangeDefinition": [], + "monitoredAttributes": [], + "proposedRepairActions": "xyz", + "additionalText": "xyz", + "additionalInformation": [], + "alarmId": "xyz", + "alarmType": "Environmental Alarm" + }, + "stndDefinedFieldsVersion": "1.0" + } + } +} diff --git a/src/test/resources/ves_stdnDefined_valid_unknown_topic.json b/src/test/resources/ves_stdnDefined_valid_unknown_topic.json new file mode 100644 index 00000000..46195f7c --- /dev/null +++ b/src/test/resources/ves_stdnDefined_valid_unknown_topic.json @@ -0,0 +1,45 @@ +{ + "event": { + "commonEventHeader": { + "domain": "stndDefined", + "eventId": "stndDefined-gNB_Nokia000001", + "eventName": "stndDefined-gNB-Nokia-PowerLost", + "stndDefinedNamespace": "3GPP-FaultSupervision-unknown", + "lastEpochMicrosec": 1234567890, + "priority": "Normal", + "reportingEntityName": "Nokia123456", + "sequence": 0, + "sourceName": "Nokia123456", + "startEpochMicrosec": 1234567890, + "version": "4.1", + "vesEventListenerVersion": "7.2" + }, + "stndDefinedFields": { + "schemaReference": "https://www.3gpp.org/Rel-16/TS28532_generic_fault_supervision.json#definitions/schemas/notifyNewAlarm-NotifType", + "data": { + "uri": "xyz", + "notificationId": "xyz", + "notificationType": "notifyNewAlarm", + "eventTime": "xyz", + "systemDN": "xyz", + "probableCause": "xyz", + "perceivedSeverity": "Major", + "rootCauseIndicator": false, + "specificProblem": "xyz", + "correlatedNotifications": [], + "backedUpStatus": true, + "backUpObject": "xyz", + "trendIndication": "No change", + "thresholdInfo": {}, + "stateChangeDefinition": [], + "monitoredAttributes": [], + "proposedRepairActions": "xyz", + "additionalText": "xyz", + "additionalInformation": [], + "alarmId": "xyz", + "alarmType": "Environmental Alarm" + }, + "stndDefinedFieldsVersion": "1.0" + } + } +} diff --git a/version.properties b/version.properties index cedaba1f..75acd492 100644 --- a/version.properties +++ b/version.properties @@ -1,6 +1,6 @@ major=1 minor=7 -patch=1 +patch=2 base_version=${major}.${minor}.${patch} release_version=${base_version} snapshot_version=${base_version}-SNAPSHOT -- cgit 1.2.3-korg