StndDefined event routing 33/110433/16
authorBogumil Zebek <bogumil.zebek@nokia.com>
Wed, 22 Jul 2020 06:19:51 +0000 (08:19 +0200)
committerBartosz Gardziejewski <bartosz.gardziejewski@nokia.com>
Thu, 6 Aug 2020 06:07:39 +0000 (08:07 +0200)
Route stndDefined events to streams defined in namespace event field.

Change-Id: I3963e220095665f8ca3fd1b21c5c20b44057cf76
Issue-ID: DCAEGEN2-1771
Signed-off-by: Zebek Bogumil <bogumil.zebek@nokia.com>
31 files changed:
Changelog.md
etc/DmaapConfig.json
etc/collector.properties
pom.xml
src/main/java/org/onap/dcae/ApplicationSettings.java
src/main/java/org/onap/dcae/JSonSchemasSupplier.java
src/main/java/org/onap/dcae/VesApplication.java
src/main/java/org/onap/dcae/common/EventSender.java
src/main/java/org/onap/dcae/common/EventUpdater.java
src/main/java/org/onap/dcae/common/model/StndDefinedNamespaceParameterHasEmptyValueException.java [new file with mode: 0644]
src/main/java/org/onap/dcae/common/model/StndDefinedNamespaceParameterNotDefinedException.java [new file with mode: 0644]
src/main/java/org/onap/dcae/common/model/VesEvent.java [new file with mode: 0644]
src/main/java/org/onap/dcae/restapi/ApiException.java
src/main/java/org/onap/dcae/restapi/EventValidator.java
src/main/java/org/onap/dcae/restapi/EventValidatorException.java [new file with mode: 0644]
src/main/java/org/onap/dcae/restapi/VesRestController.java
src/test/java/org/onap/dcae/ApplicationSettingsTest.java
src/test/java/org/onap/dcae/common/EventSenderTest.java
src/test/java/org/onap/dcae/common/JsonDataLoader.java [new file with mode: 0644]
src/test/java/org/onap/dcae/common/model/VesEventTest.java [new file with mode: 0644]
src/test/java/org/onap/dcae/restapi/EventValidatorTest.java
src/test/java/org/onap/dcae/restapi/VesRestControllerTest.java
src/test/resources/eventsAfterTransformation/ves7_valid_event.json [new file with mode: 0644]
src/test/resources/eventsAfterTransformation/ves_stdnDefined_empty_namespace_invalid.json [new file with mode: 0644]
src/test/resources/eventsAfterTransformation/ves_stdnDefined_missing_namespace_invalid.json [new file with mode: 0644]
src/test/resources/eventsAfterTransformation/ves_stdnDefined_valid.json [new file with mode: 0644]
src/test/resources/ves_stdnDefined_empty_namespace_invalid.json [new file with mode: 0644]
src/test/resources/ves_stdnDefined_missing_namespace_invalid.json [new file with mode: 0644]
src/test/resources/ves_stdnDefined_valid.json [new file with mode: 0644]
src/test/resources/ves_stdnDefined_valid_unknown_topic.json [new file with mode: 0644]
version.properties

index 4b1918d..216e1ce 100644 (file)
@@ -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.
index 2732821..2ef77dc 100644 (file)
       "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
+}
index 3684f5e..0d408cc 100755 (executable)
@@ -50,8 +50,8 @@ collector.truststore.passwordfile=etc/trustpasswordfile
 collector.schema.checkflag=1\r
 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\"}\r
 \r
-## List all streamid per domain to be supported. The streamid should match to channel name on dmaapfile  \r
-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\r
+## List all streamid per domain to be supported. The streamid should match to channel name on dmaapfile\r
+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\r
 collector.dmaapfile=./etc/DmaapConfig.json\r
 \r
 ## Event transformation Flag - when set expects configurable transformation\r
diff --git a/pom.xml b/pom.xml
index dcf2628..1154b34 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -24,7 +24,7 @@
   </parent>\r
   <groupId>org.onap.dcaegen2.collectors.ves</groupId>\r
   <artifactId>VESCollector</artifactId>\r
-  <version>1.7.1-SNAPSHOT</version>\r
+  <version>1.7.2-SNAPSHOT</version>\r
   <name>dcaegen2-collectors-ves</name>\r
   <description>VESCollector</description>\r
   <properties>\r
index 8458df8..33ad5bc 100644 (file)
@@ -161,7 +161,7 @@ public class ApplicationSettings {
         return properties.getString("auth.method", AuthMethodType.NO_AUTH.value());
     }
 
-    public Map<String, String[]> dMaaPStreamsMapping() {
+    public Map<String, String[]> getDmaapStreamIds() {
         String streamIdsProperty = properties.getString("collector.dmaap.streamid", null);
         if (streamIdsProperty == null) {
             return HashMap.empty();
index d7cd566..10e74ee 100644 (file)
@@ -3,7 +3,7 @@
  * PROJECT\r
  * ================================================================================\r
  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.\r
- * Copyright (C) 2019 Nokia. All rights reserved.s\r
+ * Copyright (C) 2020 Nokia. All rights reserved.s\r
  * ================================================================================\r
  * Licensed under the Apache License, Version 2.0 (the "License");\r
  * you may not use this file except in compliance with the License.\r
@@ -33,7 +33,7 @@ import java.nio.file.Paths;
 import static io.vavr.API.Tuple;\r
 import static java.nio.file.Files.readAllBytes;\r
 \r
-class JSonSchemasSupplier {\r
+public class JSonSchemasSupplier {\r
 \r
     public Map<String, JsonSchema> loadJsonSchemas(String collectorSchemaFile) {\r
         JSONObject jsonObject = new JSONObject(collectorSchemaFile);\r
index bc5b1a8..9f628b5 100644 (file)
@@ -133,7 +133,7 @@ public class VesApplication {
     @Bean
     @Qualifier("eventSender")
     public EventSender eventSender() {
-        return new EventSender(eventPublisher, applicationSettings);
+        return new EventSender(eventPublisher, applicationSettings.getDmaapStreamIds());
     }
 
 }
index c1002af..63be910 100644 (file)
@@ -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<String, String[]> streamidHash;
+  private Map<String, String[]> 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<String, String[]> 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<VesEvent> 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());
   }
 }
index 1469d47..954e4b6 100644 (file)
 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<VesEvent> 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<VesEvent> convertEvents(VesEvent vesEvent, String uuid, String version) {
+    List<VesEvent> 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<VesEvent> 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 (file)
index 0000000..22ec23a
--- /dev/null
@@ -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 (file)
index 0000000..69ee68f
--- /dev/null
@@ -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 (file)
index 0000000..ce709d1
--- /dev/null
@@ -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);
+    }
+}
index 5867e52..255999a 100644 (file)
@@ -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;
index 3261c3b..0eb0967 100644 (file)
  */
 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<ResponseEntity<String>> 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<ResponseEntity<String>> 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 (file)
index 0000000..65ad457
--- /dev/null
@@ -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;
+    }
+}
index b07b58d..f6dde6d 100644 (file)
@@ -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.
 
 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<String> process(String events, String version, HttpServletRequest request, String type) {
+    private ResponseEntity<String> 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<ResponseEntity<String>> 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<String> handleEvent(VesEvent vesEvent, String version, String type, CustomHeaderUtils headerUtils, String requestURI) {
+        try {
+            eventValidator.validate(vesEvent, type, version);
+            List<VesEvent> 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<VesEvent> 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
+}
index 3d8a1a1..6560b1c 100644 (file)
@@ -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<String, String[]> 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<String, String[]> 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<String, String[]> dmaapStreamID = fromTemporaryConfiguration().dMaaPStreamsMapping();
+        Map<String, String[]> 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
index f49d3cd..e20fa99 100644 (file)
@@ -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.
  */
 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<VesEvent> 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<VesEvent> 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<VesEvent> eventToSend = createEventToSend("/eventsAfterTransformation/ves_stdnDefined_valid.json");
+
+    // when
+    eventSender.send(eventToSend);
+
+    // then
+    verifyThatEventWasSendAtStream("ves-3gpp-fault-supervision");
   }
 
   @Test
-  public void shouldSendEvent() {
-    Map<String, String[]> 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<VesEvent> 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<VesEvent> eventToSend = createEventToSend(
+            "/eventsAfterTransformation/ves_stdnDefined_missing_namespace_invalid.json"
+    );
+
+    // when
+    assertThatExceptionOfType(StndDefinedNamespaceParameterNotDefinedException.class)
+            .isThrownBy(() -> eventSender.send(eventToSend));
+
+    // then
+    verifyThatEventWasNotSendAtStream();
+  }
+
+  private List<VesEvent> createEventToSend(String path) throws IOException {
+    String event = JsonDataLoader.loadContent(path);
+    return givenEventToSend(event);
+  }
+
+  private EventSender givenConfiguredEventSender(io.vavr.collection.Map<String, String[]> streamIds) {
+    return new EventSender(eventPublisher, streamIds);
+  }
+
+  private List<VesEvent> 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 (file)
index 0000000..2ea59aa
--- /dev/null
@@ -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 (file)
index 0000000..c66e0a9
--- /dev/null
@@ -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));
+    }
+}
index 0d38fda..0ca5c42 100644 (file)
 
 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<ResponseEntity<String>> 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<ResponseEntity<String>> 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<ResponseEntity<String>> 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<ResponseEntity<String>> 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<ResponseEntity<String>> 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<ResponseEntity<String>> 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<ResponseEntity<String>> 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<ResponseEntity<String>> generateResponseOptional(ApiException schemaValidationFailed) {
-        return Optional.of(ResponseEntity.status(schemaValidationFailed.httpStatusCode)
-                .body(schemaValidationFailed.toJSON().toString()));
-    }
 }
index 6b89a35..e5e7239 100644 (file)
 
 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<String, String[]> 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<String> 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<String> 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<String> 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<String> 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<String> 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<String> response = vesRestController.event(validEvent, "v7", request);
+        final ResponseEntity<String> 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<String> 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<String, JsonSchema> 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<String> response, String messageId, String messageText) throws com.fasterxml.jackson.core.JsonProcessingException {
+        final Map<String, String> errorDetails = fetchErrorDetails(response);
+        assertThat(errorDetails).containsEntry("messageId", messageId);
+        assertThat(errorDetails).containsEntry("text", messageText);
+    }
+
+    private Map<String, String> fetchErrorDetails(ResponseEntity<String> response) throws com.fasterxml.jackson.core.JsonProcessingException {
+        final String body = response.getBody();
+        ObjectMapper mapper = new ObjectMapper();
+        Map<String, Map<String, Map<String,String>>> map = mapper.readValue(body, Map.class);
+        return map.get("requestError").get("ServiceException");
     }
 
     private void configureEventTransformations() throws IOException {
         final List<EventTransformation> 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<JSONArray> argument = ArgumentCaptor.forClass(JSONArray.class);
-        verify(eventSender).send(argument.capture());
+        ArgumentCaptor<JSONObject> argument = ArgumentCaptor.forClass(JSONObject.class);
+        ArgumentCaptor<String> 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 (file)
index 0000000..d397733
--- /dev/null
@@ -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 (file)
index 0000000..63d682f
--- /dev/null
@@ -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 (file)
index 0000000..b962892
--- /dev/null
@@ -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 (file)
index 0000000..dfae48f
--- /dev/null
@@ -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 (file)
index 0000000..bf5f095
--- /dev/null
@@ -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 (file)
index 0000000..230dc54
--- /dev/null
@@ -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 (file)
index 0000000..aa026e7
--- /dev/null
@@ -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 (file)
index 0000000..46195f7
--- /dev/null
@@ -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"
+    }
+  }
+}
index cedaba1..75acd49 100644 (file)
@@ -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