From a0ba464faeb2e979d20758bc1091143108355974 Mon Sep 17 00:00:00 2001 From: Michal Banka Date: Tue, 4 Aug 2020 14:58:25 +0200 Subject: Add implementation of stndDefined fields validation Added implementation of stndDefined fields from incoming events. Validation is performed using external-schema-manager tool from DCAE SDK. StndDefined fields schemas are stored in etc/externalRepo directory. Additional stndDefined related properties has been added to collector.properties. VES version has been set to 1.7.3. Issue-ID: DCAEGEN2-2254 Signed-off-by: Edyta Krukowska Signed-off-by: Michal Banka Change-Id: Iedaa3622b1d527f6794822c8867b9dfd1860bb8f --- .../java/org/onap/dcae/ApplicationSettings.java | 26 +- src/main/java/org/onap/dcae/VesApplication.java | 7 + .../org/onap/dcae/common/ConfigProcessors.java | 181 ++-- .../java/org/onap/dcae/common/model/VesEvent.java | 20 + .../common/validator/GeneralEventValidator.java | 75 ++ .../dcae/common/validator/SchemaValidator.java | 58 + .../common/validator/StndDefinedDataValidator.java | 83 ++ .../validator/StndDefinedValidatorResolver.java | 53 + .../java/org/onap/dcae/restapi/ApiException.java | 6 +- .../java/org/onap/dcae/restapi/EventValidator.java | 73 -- .../onap/dcae/restapi/EventValidatorException.java | 2 +- .../org/onap/dcae/restapi/SchemaValidator.java | 58 - .../org/onap/dcae/restapi/VesRestController.java | 33 +- .../org/onap/dcae/ApplicationSettingsTest.java | 121 ++- src/test/java/org/onap/dcae/TLSTest.java | 15 + .../validator/GeneralEventValidatorTest.java | 197 ++++ .../validator/StndDefinedDataValidatorTest.java | 149 +++ .../StndDefinedValidatorResolverTest.java | 65 ++ .../org/onap/dcae/restapi/EventValidatorTest.java | 194 ---- .../onap/dcae/restapi/VesRestControllerTest.java | 49 +- .../resources/stndDefined/OpenAPI_faultMnS.yaml | 1144 ++++++++++++++++++++ src/test/resources/stndDefined/schema-map.json | 6 + .../ves7_batch_with_stndDefined_valid.json | 109 ++ .../ves7_valid_eventWithStndDefinedFields.json | 49 - .../ves_stdnDefined_empty_namespace_invalid.json | 2 +- src/test/resources/ves_stdnDefined_invalid.json | 54 + ...stdnDefined_missing_local_schema_reference.json | 54 + .../ves_stdnDefined_missing_namespace_invalid.json | 2 +- src/test/resources/ves_stdnDefined_valid.json | 51 +- ...Defined_with_empty_stndDefined_fields_data.json | 24 + .../ves_stdnDefined_without_schema_reference.json | 22 + ..._stdnDefined_wrong_internal_file_reference.json | 54 + 32 files changed, 2509 insertions(+), 527 deletions(-) create mode 100644 src/main/java/org/onap/dcae/common/validator/GeneralEventValidator.java create mode 100644 src/main/java/org/onap/dcae/common/validator/SchemaValidator.java create mode 100644 src/main/java/org/onap/dcae/common/validator/StndDefinedDataValidator.java create mode 100644 src/main/java/org/onap/dcae/common/validator/StndDefinedValidatorResolver.java delete mode 100644 src/main/java/org/onap/dcae/restapi/EventValidator.java delete mode 100644 src/main/java/org/onap/dcae/restapi/SchemaValidator.java create mode 100644 src/test/java/org/onap/dcae/common/validator/GeneralEventValidatorTest.java create mode 100644 src/test/java/org/onap/dcae/common/validator/StndDefinedDataValidatorTest.java create mode 100644 src/test/java/org/onap/dcae/common/validator/StndDefinedValidatorResolverTest.java delete mode 100644 src/test/java/org/onap/dcae/restapi/EventValidatorTest.java create mode 100644 src/test/resources/stndDefined/OpenAPI_faultMnS.yaml create mode 100644 src/test/resources/stndDefined/schema-map.json create mode 100644 src/test/resources/ves7_batch_with_stndDefined_valid.json delete mode 100644 src/test/resources/ves7_valid_eventWithStndDefinedFields.json create mode 100644 src/test/resources/ves_stdnDefined_invalid.json create mode 100644 src/test/resources/ves_stdnDefined_missing_local_schema_reference.json create mode 100644 src/test/resources/ves_stdnDefined_with_empty_stndDefined_fields_data.json create mode 100644 src/test/resources/ves_stdnDefined_without_schema_reference.json create mode 100644 src/test/resources/ves_stdnDefined_wrong_internal_file_reference.json (limited to 'src') diff --git a/src/main/java/org/onap/dcae/ApplicationSettings.java b/src/main/java/org/onap/dcae/ApplicationSettings.java index 33ad5bc7..7d5c7db2 100644 --- a/src/main/java/org/onap/dcae/ApplicationSettings.java +++ b/src/main/java/org/onap/dcae/ApplicationSettings.java @@ -55,6 +55,8 @@ public class ApplicationSettings { private static final Logger log = LoggerFactory.getLogger(ApplicationSettings.class); private static final String FALLBACK_VES_VERSION = "v5"; + private static final int DISABLED = -1; + private static final int ENABLED = 1; private final String appInvocationDir; private final String configurationFileLocation; private final PropertiesConfiguration properties = new PropertiesConfiguration(); @@ -96,7 +98,7 @@ public class ApplicationSettings { } public boolean eventSchemaValidationEnabled() { - return properties.getInt("collector.schema.checkflag", -1) > 0; + return properties.getInt("collector.schema.checkflag", DISABLED) > 0; } public JsonSchema jsonSchema(String version) { @@ -126,7 +128,7 @@ public class ApplicationSettings { } public boolean eventTransformingEnabled() { - return properties.getInt("event.transform.flag", 1) > 0; + return properties.getInt("event.transform.flag", ENABLED) > 0; } public String keystorePasswordFileLocation() { @@ -170,6 +172,26 @@ public class ApplicationSettings { } } + public boolean getExternalSchemaValidationCheckflag() { + return properties.getInt("collector.externalSchema.checkflag", DISABLED) > 0; + } + + public String getExternalSchemaSchemasLocation() { + return properties.getString("collector.externalSchema.schemasLocation", "./etc/externalRepo"); + } + + public String getExternalSchemaMappingFileLocation() { + return properties.getString("collector.externalSchema.mappingFileLocation", "./etc/externalRepo/schema-map.json"); + } + + public String getExternalSchemaSchemaRefPath() { + return properties.getString("event.externalSchema.schemaRefPath", "/event/stndDefinedFields/schemaReference"); + } + + public String getExternalSchemaStndDefinedDataPath() { + return properties.getString("event.externalSchema.stndDefinedDataPath", "/event/stndDefinedFields/data"); + } + public List getEventTransformations() { return eventTransformations; } diff --git a/src/main/java/org/onap/dcae/VesApplication.java b/src/main/java/org/onap/dcae/VesApplication.java index 9f628b5c..bb785dbd 100644 --- a/src/main/java/org/onap/dcae/VesApplication.java +++ b/src/main/java/org/onap/dcae/VesApplication.java @@ -27,10 +27,12 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.onap.dcae.common.EventSender; +import org.onap.dcae.common.validator.StndDefinedValidatorResolver; import org.onap.dcae.common.publishing.DMaaPConfigurationParser; import org.onap.dcae.common.publishing.EventPublisher; import org.onap.dcae.common.publishing.PublisherConfig; import org.onap.dcae.controller.ConfigLoader; +import org.onap.dcaegen2.services.sdk.services.external.schema.manager.service.StndDefinedValidator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Qualifier; @@ -136,4 +138,9 @@ public class VesApplication { return new EventSender(eventPublisher, applicationSettings.getDmaapStreamIds()); } + @Bean + public StndDefinedValidator getStndDefinedValidator(StndDefinedValidatorResolver resolver) { + return resolver.resolve(); + } + } diff --git a/src/main/java/org/onap/dcae/common/ConfigProcessors.java b/src/main/java/org/onap/dcae/common/ConfigProcessors.java index c459bb1c..d1c5e5a0 100644 --- a/src/main/java/org/onap/dcae/common/ConfigProcessors.java +++ b/src/main/java/org/onap/dcae/common/ConfigProcessors.java @@ -54,8 +54,9 @@ public class ConfigProcessors { if (filter == null || isFilterMet(filter)) { getEventObjectVal(field); - } else + } else { log.info(FILTER_NOT_MET); + } } @@ -65,8 +66,9 @@ public class ConfigProcessors { final JSONObject filter = jsonObject.optJSONObject(FILTER); if (filter == null || isFilterMet(filter)) { setEventObjectVal(field, value); - } else + } else { log.info(FILTER_NOT_MET); + } } @@ -85,8 +87,9 @@ public class ConfigProcessors { if (filter == null || isFilterMet(filter)) { setEventObjectVal("suppressEvent", "true"); - } else + } else { log.info(FILTER_NOT_MET); + } } @@ -99,8 +102,9 @@ public class ConfigProcessors { if (filter == null || isFilterMet(filter)) { setEventObjectVal(field, value, fieldType); - } else + } else { log.info(FILTER_NOT_MET); + } } @@ -111,8 +115,9 @@ public class ConfigProcessors { final JSONObject filter = jsonObject.optJSONObject(FILTER); if (filter == null || isFilterMet(filter)) { setEventObjectVal(field, value); - } else + } else { log.info(FILTER_NOT_MET); + } } @@ -123,8 +128,9 @@ public class ConfigProcessors { if (filter == null || isFilterMet(filter)) { removeEventKey(field); - } else + } else { log.info(FILTER_NOT_MET); + } } @@ -152,8 +158,9 @@ public class ConfigProcessors { removeEventKey(oldfsplit[0]); setEventObjectVal(fsplit[0], ja); } - } else + } else { log.info(FILTER_NOT_MET); + } } private void renameObject(JSONObject jsonObject) // map @@ -170,29 +177,30 @@ public class ConfigProcessors { setEventObjectVal(field, oldValue); removeEventKey(oldField); } - } else + } else { log.info(FILTER_NOT_MET); + } } - + public void map(JSONObject jsonObject) { final String field = jsonObject.getString(FIELD); final String mapType = jsonObject.optString(MAP_TYPE, ""); if (field.contains("[]")) { - if (field.matches(".*\\[\\]\\..*\\[\\]")) + if (field.matches(".*\\[\\]\\..*\\[\\]")) { renameArrayInArray(jsonObject); - else + } else { mapToJArray(jsonObject); + } + } else if ("hashmapToNameValueArray".equals(mapType)) { + mapHashmapToNameValueArray(jsonObject); + } else if ("nameValueArrayToHashmap".equals(mapType)) { + mapNameValueArrayToHashmap(jsonObject); + } else if ("renameObject".equals(mapType)) { + renameObject(jsonObject); + } else { + mapAttribute(jsonObject); } - else if (mapType.equals("hashmapToNameValueArray")) - mapHashmapToNameValueArray(jsonObject); - else if (mapType.equals("nameValueArrayToHashmap")) - mapNameValueArrayToHashmap(jsonObject); - else if (mapType.equals("renameObject")) - renameObject(jsonObject); - - else - mapAttribute(jsonObject); } private String performOperation(String operation, String value) { @@ -216,15 +224,17 @@ public class ConfigProcessors { value = getEventObjectVal(oldField).toString(); if (!value.equals(OBJECT_NOT_FOUND)) { - if (operation != null && !operation.isEmpty()) + if (operation != null && !operation.isEmpty()) { value = performOperation(operation, value); + } setEventObjectVal(field, value); removeEventKey(oldField); } - } else + } else { log.info(FILTER_NOT_MET); + } } @@ -270,16 +280,21 @@ public class ConfigProcessors { setEventObjectVal(field, ja); } } else // if new array + { setEventObjectVal(field + "[0]", new JSONObject(value), "JArray"); + } } else // oldfield is jsonArray + { setEventObjectVal(field, new JSONArray(value)); + } removeEventKey(oldField); } - } else + } else { log.info(FILTER_NOT_MET); + } } - + // this method is to support the mapping 5.x to VES7.x format for additionalInformation field private void mapNameValueArrayToHashmap(JSONObject jsonObject) { log.info("mapNameValueArrayToHashmap"); @@ -288,17 +303,17 @@ public class ConfigProcessors { final JSONObject filter = jsonObject.optJSONObject(FILTER); if (filter == null || isFilterMet(filter)) { - JSONObject newHashMap = new JSONObject(); // this will hold the newly mapped hashmap elements + JSONObject newHashMap = new JSONObject(); // this will hold the newly mapped hashmap elements JSONArray arrayValue = (JSONArray) getEventObjectVal(oldField); // old Array structure value - JSONObject tempJObj = null; - String tempName = ""; - String tempValue = ""; + JSONObject tempJObj; + String tempName; + String tempValue; if (!arrayValue.toString().equals(OBJECT_NOT_FOUND)) { log.info("old value ==" + arrayValue.toString()); // Loop thru the JSONArray, get the name:value pair and write to new JSONObject as hashmap elements for (int i = 0; i < arrayValue.length(); i++) { - tempJObj = arrayValue.getJSONObject(i); + tempJObj = arrayValue.getJSONObject(i); if (tempJObj != null) { tempName = tempJObj.get("name").toString(); tempValue = tempJObj.get(VALUE).toString(); @@ -310,11 +325,12 @@ public class ConfigProcessors { //Add the new Hashmap setEventObjectVal(field, newHashMap); } - } else + } else { log.info(FILTER_NOT_MET); + } } - - // this method is to support the mapping 7.x to VES5.x format for additionalInformation field + + // this method is to support the mapping 7.x to VES5.x format for additionalInformation field private void mapHashmapToNameValueArray(JSONObject jsonObject) { log.info("mapHashmapToNameValueArray"); System.out.println("mapHashmapToNameValueArray"); @@ -323,29 +339,30 @@ public class ConfigProcessors { final JSONObject filter = jsonObject.optJSONObject(FILTER); if (filter == null || isFilterMet(filter)) { - JSONArray newArray = new JSONArray(); // this will hold the new name:value JSONObject - JSONObject nameValJObj; - System.out.println("object ==" + getEventObjectVal(oldField).toString()); - if (!getEventObjectVal(oldField).toString().equals(OBJECT_NOT_FOUND)) { - - JSONObject hashMap = (JSONObject) getEventObjectVal(oldField); // old hashmap structure value - if (hashMap != null) { - log.info("old value ==" + hashMap.toString()); - // Loop thru the hashMap JSONObject, get the hashmap elements add them as name:value JsonObject into the newArray - for (String key : hashMap.keySet()) { - nameValJObj = new JSONObject(); //create new object so not to overwrite in memory for Array insertion - nameValJObj.put("name", key); - nameValJObj.put("value", hashMap.get(key)); - newArray.put(nameValJObj); - } - // remove the old hashMap structure - removeEventKey(oldField); - //Add the newArray containing the name:value Object - setEventObjectVal(field, newArray); - } - } - } else + JSONArray newArray = new JSONArray(); // this will hold the new name:value JSONObject + JSONObject nameValJObj; + System.out.println("object ==" + getEventObjectVal(oldField).toString()); + if (!getEventObjectVal(oldField).toString().equals(OBJECT_NOT_FOUND)) { + + JSONObject hashMap = (JSONObject) getEventObjectVal(oldField); // old hashmap structure value + if (hashMap != null) { + log.info("old value ==" + hashMap.toString()); + // Loop thru the hashMap JSONObject, get the hashmap elements add them as name:value JsonObject into the newArray + for (String key : hashMap.keySet()) { + nameValJObj = new JSONObject(); //create new object so not to overwrite in memory for Array insertion + nameValJObj.put("name", key); + nameValJObj.put("value", hashMap.get(key)); + newArray.put(nameValJObj); + } + // remove the old hashMap structure + removeEventKey(oldField); + //Add the newArray containing the name:value Object + setEventObjectVal(field, newArray); + } + } + } else { log.info(FILTER_NOT_MET); + } } /** @@ -367,16 +384,18 @@ public class ConfigProcessors { String tempVal = evaluate(values.getString(i)); if (!tempVal.equals(OBJECT_NOT_FOUND)) { - if (i == 0) + if (i == 0) { value.append(tempVal); - else + } else { value.append(delimiter).append(tempVal); + } } } setEventObjectVal(field, value.toString()); - } else + } else { log.info(FILTER_NOT_MET); + } } public void subtractValue(JSONObject jsonObject) { @@ -391,16 +410,18 @@ public class ConfigProcessors { String tempVal = evaluate(values.getString(i)); log.info("tempVal==" + tempVal); if (!tempVal.equals(OBJECT_NOT_FOUND)) { - if (i == 0) - value = value + Float.valueOf(tempVal); - else - value = value - Float.valueOf(tempVal); + if (i == 0) { + value = value + Float.parseFloat(tempVal); + } else { + value = value - Float.parseFloat(tempVal); + } } } log.info("value ==" + value); setEventObjectVal(field, value, "number"); - } else + } else { log.info(FILTER_NOT_MET); + } } @@ -470,12 +491,14 @@ public class ConfigProcessors { if ("not".equals(key)) { JSONObject njo = jo.getJSONObject(key); for (String njoKey : njo.keySet()) { - if (!checkFilter(njo, njoKey, key)) + if (!checkFilter(njo, njoKey, key)) { return false; + } } } else { - if (!checkFilter(jo, key, key)) + if (!checkFilter(jo, key, key)) { return false; + } } } return true; @@ -491,8 +514,9 @@ public class ConfigProcessors { keySeriesStr = keySeriesStr.replaceAll("\\.\\.", "."); } - if (keySeriesStr.lastIndexOf(".") == keySeriesStr.length() - 1) + if (keySeriesStr.lastIndexOf(".") == keySeriesStr.length() - 1) { keySeriesStr = keySeriesStr.substring(0, keySeriesStr.length() - 1); + } String[] keySet = keySeriesStr.split("\\.", keySeriesStr.length()); Object keySeriesObj = event; for (String aKeySet : keySet) { @@ -512,8 +536,9 @@ public class ConfigProcessors { } } - if (keySeriesObj == null) + if (keySeriesObj == null) { return OBJECT_NOT_FOUND; + } return keySeriesObj; } @@ -532,8 +557,9 @@ public class ConfigProcessors { } log.info("fieldType==" + fieldType); - if (keySeriesStr.lastIndexOf(".") == keySeriesStr.length() - 1) + if (keySeriesStr.lastIndexOf(".") == keySeriesStr.length() - 1) { keySeriesStr = keySeriesStr.substring(0, keySeriesStr.length() - 1); + } String[] keySet = keySeriesStr.split("\\.", keySeriesStr.length()); Object keySeriesObj = event; for (int i = 0; i < (keySet.length - 1); i++) { @@ -552,9 +578,11 @@ public class ConfigProcessors { { log.info("Object is null, must add it"); if (keySet[i + 1].matches("[0-9]*")) // if index then array + { ((JSONArray) keySeriesObj).put(Integer.parseInt(keySet[i]), new JSONArray()); - else + } else { ((JSONArray) keySeriesObj).put(Integer.parseInt(keySet[i]), new JSONObject()); + } } keySeriesObj = ((JSONArray) keySeriesObj).optJSONObject(Integer.parseInt(keySet[i])); @@ -570,9 +598,11 @@ public class ConfigProcessors { // it { if (keySet[i + 1].matches("[0-9]*")) // if index then array + { ((JSONObject) keySeriesObj).put(keySet[i], new JSONArray()); - else + } else { ((JSONObject) keySeriesObj).put(keySet[i], new JSONObject()); + } log.info("Object is null, must add it"); } keySeriesObj = ((JSONObject) keySeriesObj).opt(keySet[i]); @@ -582,17 +612,20 @@ public class ConfigProcessors { } if ("number".equals(fieldType)) { DecimalFormat df = new DecimalFormat("#.0"); - if (value instanceof String) + if (value instanceof String) { ((JSONObject) keySeriesObj).put(keySet[keySet.length - 1], Float.valueOf(df.format(Float.valueOf((String) value)))); - else + } else { ((JSONObject) keySeriesObj).put(keySet[keySet.length - 1], Float.valueOf(df.format(value))); - } else if ("integer".equals(fieldType) && value instanceof String) + } + } else if ("integer".equals(fieldType) && value instanceof String) { ((JSONObject) keySeriesObj).put(keySet[keySet.length - 1], Integer.valueOf((String) value)); - else if ("JArray".equals(fieldType)) + } else if ("JArray".equals(fieldType)) { + assert keySeriesObj instanceof JSONArray; ((JSONArray) keySeriesObj).put(value); - else + } else { ((JSONObject) keySeriesObj).put(keySet[keySet.length - 1], value); + } } } diff --git a/src/main/java/org/onap/dcae/common/model/VesEvent.java b/src/main/java/org/onap/dcae/common/model/VesEvent.java index ce709d1c..6c9a8ee2 100644 --- a/src/main/java/org/onap/dcae/common/model/VesEvent.java +++ b/src/main/java/org/onap/dcae/common/model/VesEvent.java @@ -19,6 +19,9 @@ */ package org.onap.dcae.common.model; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import org.json.JSONObject; /** @@ -35,6 +38,8 @@ public class VesEvent { private static final String DOMAIN = "domain"; private static final String STND_DEFINED_NAMESPACE = "stndDefinedNamespace"; private static final String STND_DEFINED_DOMAIN = "stndDefined"; + private static final String STND_DEFINED_FIELDS = "stndDefinedFields"; + private static final String SCHEMA_REFERENCE = "schemaReference"; private final JSONObject event; @@ -66,6 +71,16 @@ public class VesEvent { return getEventHeader().getString(DOMAIN); } + public String getSchemaReference() { + return getStndDefinedFields().getString(SCHEMA_REFERENCE); + } + + private JSONObject getStndDefinedFields() { + return event + .getJSONObject(EVENT_LITERAL) + .getJSONObject(STND_DEFINED_FIELDS); + } + private String resolveDomainForStndDefinedEvent() { final JSONObject eventHeader = getEventHeader(); if(eventHeader.has(STND_DEFINED_NAMESPACE)) { @@ -108,6 +123,11 @@ public class VesEvent { return new JSONObject(event.toString()); } + public JsonNode asJsonNode() throws JsonProcessingException { + ObjectMapper objectMapper = new ObjectMapper(); + return objectMapper.readTree(event.toString()); + } + /** * Checks if type of event is same as given in paramaters. * diff --git a/src/main/java/org/onap/dcae/common/validator/GeneralEventValidator.java b/src/main/java/org/onap/dcae/common/validator/GeneralEventValidator.java new file mode 100644 index 00000000..5cd5dc25 --- /dev/null +++ b/src/main/java/org/onap/dcae/common/validator/GeneralEventValidator.java @@ -0,0 +1,75 @@ +/* + * ============LICENSE_START======================================================= + * PROJECT + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. 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. + * 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.validator; + +import com.networknt.schema.JsonSchema; +import org.onap.dcae.ApplicationSettings; +import org.onap.dcae.common.model.VesEvent; +import org.onap.dcae.restapi.ApiException; +import org.onap.dcae.restapi.EventValidatorException; + +/** + * This class is using ApplicationSetting and SchemaValidator to validate VES event. + * + * @author Zebek + */ +public class GeneralEventValidator { + + private final SchemaValidator schemaValidator; + private final ApplicationSettings applicationSettings; + + public GeneralEventValidator(ApplicationSettings applicationSettings) { + this(applicationSettings, new SchemaValidator()); + } + + GeneralEventValidator(ApplicationSettings applicationSettings, SchemaValidator schemaValidator) { + this.applicationSettings = applicationSettings; + this.schemaValidator = schemaValidator; + } + + /** + * 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()) { + 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); + } + } + + private boolean isEventMatchToSchema(VesEvent vesEvent, JsonSchema schema) { + return schemaValidator.conformsToSchema(vesEvent.asJsonObject(), schema); + } +} diff --git a/src/main/java/org/onap/dcae/common/validator/SchemaValidator.java b/src/main/java/org/onap/dcae/common/validator/SchemaValidator.java new file mode 100644 index 00000000..80c8f6e7 --- /dev/null +++ b/src/main/java/org/onap/dcae/common/validator/SchemaValidator.java @@ -0,0 +1,58 @@ +/* + * ============LICENSE_START======================================================= + * PROJECT + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2019 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.validator; + + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.networknt.schema.JsonSchema; +import com.networknt.schema.ValidationMessage; +import org.json.JSONObject; +import org.onap.dcae.ApplicationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Set; + +class SchemaValidator { + public static final Logger log = LoggerFactory.getLogger(SchemaValidator.class); + + public boolean conformsToSchema(JSONObject payload, JsonSchema schema) { + try { + ObjectMapper mapper = new ObjectMapper(); + + String content = payload.toString(); + JsonNode node = mapper.readTree(content); + Set messageSet = schema.validate(node); + + if (messageSet.isEmpty()) { + return true; + } + + log.warn("Schema validation failed for event: {}", payload); + messageSet.forEach(it->log.warn(it.getMessage()) ); + + return false; + } catch (Exception e) { + throw new ApplicationException("Unable to validate against schema", e); + } + } +} diff --git a/src/main/java/org/onap/dcae/common/validator/StndDefinedDataValidator.java b/src/main/java/org/onap/dcae/common/validator/StndDefinedDataValidator.java new file mode 100644 index 00000000..d936f272 --- /dev/null +++ b/src/main/java/org/onap/dcae/common/validator/StndDefinedDataValidator.java @@ -0,0 +1,83 @@ +/* + * ============LICENSE_START======================================================= + * VES + * ================================================================================ + * 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.validator; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import org.json.JSONException; +import org.onap.dcae.common.model.VesEvent; +import org.onap.dcae.restapi.ApiException; +import org.onap.dcae.restapi.EventValidatorException; +import org.onap.dcaegen2.services.sdk.services.external.schema.manager.exception.IncorrectInternalFileReferenceException; +import org.onap.dcaegen2.services.sdk.services.external.schema.manager.exception.NoLocalReferenceException; +import org.onap.dcaegen2.services.sdk.services.external.schema.manager.service.StndDefinedValidator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class StndDefinedDataValidator { + + private static final String STND_DEFINED_DOMAIN = "stndDefined"; + + private final StndDefinedValidator stndDefinedValidator; + + @Autowired + public StndDefinedDataValidator(StndDefinedValidator validator) { + this.stndDefinedValidator = validator; + } + + /** + * Validates incoming event + * + * @param event as JsonNode + * @throws EventValidatorException exceptions related to failing StndDefined validation + */ + public void validate(VesEvent event) throws EventValidatorException { + try { + if (shouldBeValidated(event) && !doValidation(event.asJsonNode())) { + throw new EventValidatorException(ApiException.STND_DEFINED_VALIDATION_FAILED); + } + } catch (JsonProcessingException ex) { + throw new EventValidatorException(ApiException.INVALID_JSON_INPUT); + } + } + + private boolean doValidation(JsonNode event) throws EventValidatorException { + try { + return stndDefinedValidator.validate(event); + } catch (NoLocalReferenceException e) { + throw new EventValidatorException(ApiException.NO_LOCAL_SCHEMA_REFERENCE); + } catch (IncorrectInternalFileReferenceException e) { + throw new EventValidatorException(ApiException.INCORRECT_INTERNAL_FILE_REFERENCE); + } + } + + private boolean shouldBeValidated(VesEvent event) { + boolean shouldBeValidated; + try { + shouldBeValidated = STND_DEFINED_DOMAIN.equals(event.getDomain()) + && !event.getSchemaReference().isEmpty(); + } catch (JSONException e) { + shouldBeValidated = false; + } + return shouldBeValidated; + } +} diff --git a/src/main/java/org/onap/dcae/common/validator/StndDefinedValidatorResolver.java b/src/main/java/org/onap/dcae/common/validator/StndDefinedValidatorResolver.java new file mode 100644 index 00000000..3f06d0ae --- /dev/null +++ b/src/main/java/org/onap/dcae/common/validator/StndDefinedValidatorResolver.java @@ -0,0 +1,53 @@ +/* + * ============LICENSE_START======================================================= + * VES + * ================================================================================ + * 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.validator; + +import org.onap.dcae.ApplicationSettings; +import org.onap.dcaegen2.services.sdk.services.external.schema.manager.service.StndDefinedValidator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class StndDefinedValidatorResolver { + + private final ApplicationSettings settings; + + @Autowired + public StndDefinedValidatorResolver(ApplicationSettings settings) { + this.settings = settings; + } + + /** + * Creates StndDefinedValidator using settings defined in collector.properties + * + * @return StndDefinedValidator object for validation of configured fields of event + */ + public StndDefinedValidator resolve() { + return new StndDefinedValidator.ValidatorBuilder() + .mappingFilePath(settings.getExternalSchemaMappingFileLocation()) + .schemaRefPath(settings.getExternalSchemaSchemaRefPath()) + .schemasPath(settings.getExternalSchemaSchemasLocation()) + .stndDefinedDataPath(settings.getExternalSchemaStndDefinedDataPath()) + .build(); + } +} + + diff --git a/src/main/java/org/onap/dcae/restapi/ApiException.java b/src/main/java/org/onap/dcae/restapi/ApiException.java index 9ea02076..dbd41a4d 100644 --- a/src/main/java/org/onap/dcae/restapi/ApiException.java +++ b/src/main/java/org/onap/dcae/restapi/ApiException.java @@ -37,7 +37,11 @@ public enum ApiException { INVALID_CUSTOM_HEADER(ExceptionType.SERVICE_EXCEPTION, "SVC0002", "Bad Parameter (Incorrect request api version)", 400), MISSING_NAMESPACE_PARAMETER(ExceptionType.SERVICE_EXCEPTION, "SVC2006", "Mandatory input %1 %2 is missing from request", List.of("attribute", "event.commonEventHeader.stndDefinedNamespace"), 400), EMPTY_NAMESPACE_PARAMETER(ExceptionType.SERVICE_EXCEPTION, "SVC2006", "Mandatory input %1 %2 is empty in request", List.of("attribute", "event.commonEventHeader.stndDefinedNamespace"), 400), - NO_SERVER_RESOURCES(ExceptionType.SERVICE_EXCEPTION, "SVC1000", "No server resources (internal processing queue full)", 503); + NO_SERVER_RESOURCES(ExceptionType.SERVICE_EXCEPTION, "SVC1000", "No server resources (internal processing queue full)", 503), + STND_DEFINED_VALIDATION_FAILED(ExceptionType.SERVICE_EXCEPTION, "SVC2000", "The following service error occurred: %1. Error code is %2", List.of("event.stndDefinedFields.data invalid against event.stndDefinedFields.schemaReference", "400"), 400), + NO_LOCAL_SCHEMA_REFERENCE(ExceptionType.SERVICE_EXCEPTION, "SVC2004", "Invalid input value for %1 %2: %3", List.of("attribute", "event.stndDefinedFields.schemaReference", "Referred external schema not present in schema repository"), 400), + INCORRECT_INTERNAL_FILE_REFERENCE(ExceptionType.SERVICE_EXCEPTION, "SVC2000", "The following service error occurred: %1. Error code is %2", List.of("event.stndDefinedFields.schemaReference value does not correspond to any external event schema file in externalSchema repo", "400"), 400); + public final int httpStatusCode; private final ExceptionType type; diff --git a/src/main/java/org/onap/dcae/restapi/EventValidator.java b/src/main/java/org/onap/dcae/restapi/EventValidator.java deleted file mode 100644 index 0eb0967a..00000000 --- a/src/main/java/org/onap/dcae/restapi/EventValidator.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * PROJECT - * ================================================================================ - * Copyright (C) 2017 AT&T Intellectual Property. 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. - * 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; - -import com.networknt.schema.JsonSchema; -import org.onap.dcae.ApplicationSettings; -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; - private final ApplicationSettings applicationSettings; - - public EventValidator(ApplicationSettings applicationSettings) { - this(applicationSettings, new SchemaValidator()); - } - - EventValidator(ApplicationSettings applicationSettings, SchemaValidator schemaValidator) { - this.applicationSettings = applicationSettings; - this.schemaValidator = schemaValidator; - } - - /** - * 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()) { - 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); - } - } - - 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 index 65ad457f..380694d1 100644 --- a/src/main/java/org/onap/dcae/restapi/EventValidatorException.java +++ b/src/main/java/org/onap/dcae/restapi/EventValidatorException.java @@ -19,7 +19,7 @@ */ package org.onap.dcae.restapi; -public class EventValidatorException extends Exception { +public class EventValidatorException extends RuntimeException { private final ApiException apiException; public EventValidatorException(ApiException apiException) { diff --git a/src/main/java/org/onap/dcae/restapi/SchemaValidator.java b/src/main/java/org/onap/dcae/restapi/SchemaValidator.java deleted file mode 100644 index 94638071..00000000 --- a/src/main/java/org/onap/dcae/restapi/SchemaValidator.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * PROJECT - * ================================================================================ - * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. - * Copyright (C) 2019 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.restapi; - - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.networknt.schema.JsonSchema; -import com.networknt.schema.ValidationMessage; -import org.json.JSONObject; -import org.onap.dcae.ApplicationException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Set; - -class SchemaValidator { - public static final Logger log = LoggerFactory.getLogger(SchemaValidator.class); - - public boolean conformsToSchema(JSONObject payload, JsonSchema schema) { - try { - ObjectMapper mapper = new ObjectMapper(); - - String content = payload.toString(); - JsonNode node = mapper.readTree(content); - Set messageSet = schema.validate(node); - - if (messageSet.isEmpty()) { - return true; - } - - log.warn("Schema validation failed for event: " + payload); - messageSet.stream().forEach(it->log.warn(it.getMessage()) ); - - return false; - } catch (Exception e) { - throw new ApplicationException("Unable to validate against schema", e); - } - } -} diff --git a/src/main/java/org/onap/dcae/restapi/VesRestController.java b/src/main/java/org/onap/dcae/restapi/VesRestController.java index f6dde6d2..de0392e6 100644 --- a/src/main/java/org/onap/dcae/restapi/VesRestController.java +++ b/src/main/java/org/onap/dcae/restapi/VesRestController.java @@ -29,6 +29,8 @@ import org.onap.dcae.ApplicationSettings; import org.onap.dcae.common.EventSender; import org.onap.dcae.common.EventUpdater; import org.onap.dcae.common.HeaderUtils; +import org.onap.dcae.common.validator.GeneralEventValidator; +import org.onap.dcae.common.validator.StndDefinedDataValidator; import org.onap.dcae.common.VESLogger; import org.onap.dcae.common.model.StndDefinedNamespaceParameterHasEmptyValueException; import org.onap.dcae.common.model.StndDefinedNamespaceParameterNotDefinedException; @@ -61,18 +63,20 @@ public class VesRestController { private final Logger requestLogger; private EventSender eventSender; private final HeaderUtils headerUtils; - private final EventValidator eventValidator; + private final GeneralEventValidator generalEventValidator; private final EventUpdater eventUpdater; + private final StndDefinedDataValidator stndDefinedValidator; - @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, + StndDefinedDataValidator stndDefinedDataValidator) { this.settings = settings; this.requestLogger = incomingRequestsLogger; this.eventSender = eventSender; this.headerUtils = headerUtils; - this.eventValidator = new EventValidator(settings); + this.stndDefinedValidator = stndDefinedDataValidator; + this.generalEventValidator = new GeneralEventValidator(settings); this.eventUpdater = new EventUpdater(settings); } @@ -84,7 +88,6 @@ public class VesRestController { return badRequest().contentType(MediaType.APPLICATION_JSON).body(String.format("API version %s is not supported", version)); } - @PostMapping(value = {"/eventListener/{version}/eventBatch"}, consumes = "application/json") ResponseEntity events(@RequestBody String events, @PathVariable String version, HttpServletRequest request) { if (settings.isVersionSupported(version)) { @@ -100,13 +103,14 @@ public class VesRestController { final String requestURI = request.getRequestURI(); return handleEvent(vesEvent, version, type, headerUtils, requestURI); } - return badRequest().body(String.format(ApiException.INVALID_CUSTOM_HEADER.toString())); + return badRequest().body(ApiException.INVALID_CUSTOM_HEADER.toString()); } private ResponseEntity handleEvent(VesEvent vesEvent, String version, String type, CustomHeaderUtils headerUtils, String requestURI) { try { - eventValidator.validate(vesEvent, type, version); + generalEventValidator.validate(vesEvent, type, version); List vesEvents = transformEvent(vesEvent, type, version, requestURI); + executeStndDefinedValidation(vesEvents); eventSender.send(vesEvents); } catch (EventValidatorException e) { return ResponseEntity.status(e.getApiException().httpStatusCode) @@ -124,6 +128,12 @@ public class VesRestController { .contentType(MediaType.APPLICATION_JSON).body("Accepted"); } + private void executeStndDefinedValidation(List vesEvents) { + if (settings.getExternalSchemaValidationCheckflag()) { + vesEvents.forEach(stndDefinedValidator::validate); + } + } + private CustomHeaderUtils createHeaderUtils(String version, HttpServletRequest request) { return new CustomHeaderUtils(version.toLowerCase().replace("v", ""), headerUtils.extractHeaders(request), @@ -133,8 +143,7 @@ public class VesRestController { } private List transformEvent(VesEvent vesEvent, String type, String version, String requestURI) { - return this.eventUpdater.convert( - vesEvent, version, generateUUID(vesEvent, version, requestURI), type); + return this.eventUpdater.convert(vesEvent, version, generateUUID(vesEvent, version, requestURI), type); } private UUID generateUUID(VesEvent vesEvent, String version, String uri) { @@ -148,4 +157,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 6560b1ce..6ea94ab5 100644 --- a/src/test/java/org/onap/dcae/ApplicationSettingsTest.java +++ b/src/test/java/org/onap/dcae/ApplicationSettingsTest.java @@ -21,20 +21,13 @@ package org.onap.dcae; -import static java.util.Collections.singletonList; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.onap.dcae.CLIUtils.processCmdLine; -import static org.onap.dcae.TestingUtilities.createTemporaryFile; - import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.networknt.schema.JsonSchema; import io.vavr.collection.HashMap; import io.vavr.collection.Map; +import org.junit.Test; + import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -42,7 +35,15 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; import java.util.Objects; -import org.junit.Test; + +import static java.util.Collections.singletonList; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.onap.dcae.CLIUtils.processCmdLine; +import static org.onap.dcae.TestingUtilities.createTemporaryFile; public class ApplicationSettingsTest { @@ -70,7 +71,7 @@ public class ApplicationSettingsTest { @Test public void shouldMakeApplicationSettingsOutOfCLIArgumentsAndAConfigurationFile() - throws IOException { + throws IOException { // given File tempConfFile = File.createTempFile("doesNotMatter", "doesNotMatter"); Files.write(tempConfFile.toPath(), Arrays.asList("section.subSection1=abc", "section.subSection2=zxc")); @@ -111,7 +112,7 @@ public class ApplicationSettingsTest { public void shouldReturnHTTPPort() throws IOException { // when int applicationPort = fromTemporaryConfiguration("collector.service.port=8090") - .httpPort(); + .httpPort(); // then assertEquals(8090, applicationPort); @@ -130,7 +131,7 @@ public class ApplicationSettingsTest { public void shouldReturnIfHTTPSIsEnabled() throws IOException { // when boolean httpsEnabled = fromTemporaryConfiguration("collector.service.secure.port=8443") - .httpsEnabled(); + .httpsEnabled(); // then assertTrue(httpsEnabled); @@ -157,7 +158,7 @@ public class ApplicationSettingsTest { public void shouldReturnHTTPSPort() throws IOException { // when int httpsPort = fromTemporaryConfiguration("collector.service.secure.port=8443") - .httpsPort(); + .httpsPort(); // then assertEquals(8443, httpsPort); @@ -167,7 +168,7 @@ public class ApplicationSettingsTest { public void shouldReturnConfigurationUpdateInterval() throws IOException { // when int updateFrequency = fromTemporaryConfiguration("collector.dynamic.config.update.frequency=10") - .configurationUpdateFrequency(); + .configurationUpdateFrequency(); // then assertEquals(10, updateFrequency); @@ -177,7 +178,7 @@ public class ApplicationSettingsTest { public void shouldReturnDefaultConfigurationUpdateInterval() throws IOException { // when int updateFrequency = fromTemporaryConfiguration() - .configurationUpdateFrequency(); + .configurationUpdateFrequency(); // then assertEquals(5, updateFrequency); @@ -187,7 +188,7 @@ public class ApplicationSettingsTest { public void shouldReturnLocationOfThePasswordFile() throws IOException { // when String passwordFileLocation = fromTemporaryConfiguration("collector.keystore.passwordfile=/somewhere/password") - .keystorePasswordFileLocation(); + .keystorePasswordFileLocation(); // then assertEquals(sanitizePath("/somewhere/password"), passwordFileLocation); @@ -206,7 +207,7 @@ public class ApplicationSettingsTest { public void shouldReturnLocationOfTheKeystoreFile() throws IOException { // when String keystoreFileLocation = fromTemporaryConfiguration("collector.keystore.file.location=/somewhere/keystore") - .keystoreFileLocation(); + .keystoreFileLocation(); // then assertEquals(sanitizePath("/somewhere/keystore"), keystoreFileLocation); @@ -225,7 +226,7 @@ public class ApplicationSettingsTest { public void shouldReturnDMAAPConfigFileLocation() throws IOException { // when String dmaapConfigFileLocation = fromTemporaryConfiguration("collector.dmaapfile=/somewhere/dmaapFile") - .dMaaPConfigurationFileLocation(); + .dMaaPConfigurationFileLocation(); // then assertEquals(sanitizePath("/somewhere/dmaapFile"), dmaapConfigFileLocation); @@ -244,7 +245,7 @@ public class ApplicationSettingsTest { public void shouldTellIfSchemaValidationIsEnabled() throws IOException { // when boolean jsonSchemaValidationEnabled = fromTemporaryConfiguration("collector.schema.checkflag=1") - .eventSchemaValidationEnabled(); + .eventSchemaValidationEnabled(); // then assertTrue(jsonSchemaValidationEnabled); @@ -266,8 +267,8 @@ public class ApplicationSettingsTest { // when JsonSchema schema = fromTemporaryConfiguration( - String.format("collector.schema.file={\"v1\": \"%s\"}", temporarySchemaFile)) - .jsonSchema("v1"); + String.format("collector.schema.file={\"v1\": \"%s\"}", temporarySchemaFile)) + .jsonSchema("v1"); // then JsonNode incorrectTestObject = new ObjectMapper().readTree("{ \"state\": 1 }"); @@ -295,7 +296,7 @@ public class ApplicationSettingsTest { public void shouldReturnExceptionConfigFileLocation() throws IOException { // when String exceptionConfigFileLocation = fromTemporaryConfiguration("exceptionConfig=/somewhere/exceptionFile") - .exceptionConfigFileLocation(); + .exceptionConfigFileLocation(); // then assertEquals("/somewhere/exceptionFile", exceptionConfigFileLocation); @@ -315,14 +316,14 @@ public class ApplicationSettingsTest { public void shouldReturnDMAAPStreamId() throws IOException { // given Map expected = HashMap.of( - "log", new String[]{"ves-syslog", "ves-auditlog"}, - "fault", new String[]{"ves-fault"} + "log", new String[]{"ves-syslog", "ves-auditlog"}, + "fault", new String[]{"ves-fault"} ); // when Map dmaapStreamID = fromTemporaryConfiguration( - "collector.dmaap.streamid=fault=ves-fault|log=ves-syslog,ves-auditlog") - .getDmaapStreamIds(); + "collector.dmaap.streamid=fault=ves-fault|log=ves-syslog,ves-auditlog") + .getDmaapStreamIds(); // then assertArrayEquals(expected.get("log").get(), Objects.requireNonNull(dmaapStreamID).get("log").get()); @@ -352,11 +353,11 @@ public class ApplicationSettingsTest { public void shouldReturnValidCredentials() throws IOException { // when Map allowedUsers = fromTemporaryConfiguration( - "header.authlist=pasza,c2ltcGxlcGFzc3dvcmQNCg==|someoneelse,c2ltcGxlcGFzc3dvcmQNCg==" + "header.authlist=pasza,c2ltcGxlcGFzc3dvcmQNCg==|someoneelse,c2ltcGxlcGFzc3dvcmQNCg==" ).validAuthorizationCredentials(); // then - assertEquals( "c2ltcGxlcGFzc3dvcmQNCg==", allowedUsers.get("pasza").get()); + assertEquals("c2ltcGxlcGFzc3dvcmQNCg==", allowedUsers.get("pasza").get()); assertEquals("c2ltcGxlcGFzc3dvcmQNCg==", allowedUsers.get("someoneelse").get()); } @@ -364,7 +365,7 @@ public class ApplicationSettingsTest { public void shouldbyDefaultThereShouldBeNoValidCredentials() throws IOException { // when Map userToBase64PasswordDelimitedByCommaSeparatedByPipes = fromTemporaryConfiguration(). - validAuthorizationCredentials(); + validAuthorizationCredentials(); // then assertTrue(userToBase64PasswordDelimitedByCommaSeparatedByPipes.isEmpty()); @@ -374,7 +375,7 @@ public class ApplicationSettingsTest { public void shouldReturnIfEventTransformingIsEnabled() throws IOException { // when boolean isEventTransformingEnabled = fromTemporaryConfiguration("event.transform.flag=0") - .eventTransformingEnabled(); + .eventTransformingEnabled(); // then assertFalse(isEventTransformingEnabled); @@ -393,8 +394,8 @@ public class ApplicationSettingsTest { public void shouldReturnCambriaConfigurationFileLocation() throws IOException { // when String cambriaConfigurationFileLocation = fromTemporaryConfiguration( - "collector.dmaapfile=/somewhere/dmaapConfig") - .dMaaPConfigurationFileLocation(); + "collector.dmaapfile=/somewhere/dmaapConfig") + .dMaaPConfigurationFileLocation(); // then assertEquals(sanitizePath("/somewhere/dmaapConfig"), cambriaConfigurationFileLocation); @@ -404,14 +405,64 @@ public class ApplicationSettingsTest { public void shouldReturnDefaultCambriaConfigurationFileLocation() throws IOException { // when String cambriaConfigurationFileLocation = fromTemporaryConfiguration() - .dMaaPConfigurationFileLocation(); + .dMaaPConfigurationFileLocation(); // then assertEquals(sanitizePath("etc/DmaapConfig.json"), cambriaConfigurationFileLocation); } + @Test + public void shouldReturnDefaultExternalSchemaSchemasLocation() throws IOException { + //when + String externalSchemaSchemasLocation = fromTemporaryConfiguration() + .getExternalSchemaSchemasLocation(); + + //then + assertEquals(sanitizePath("./etc/externalRepo"), externalSchemaSchemasLocation); + } + + @Test + public void shouldReturnDefaultExternalSchemaMappingFileLocation() throws IOException { + //when + String externalSchemaMappingFileLocation = fromTemporaryConfiguration() + .getExternalSchemaMappingFileLocation(); + + //then + assertEquals(sanitizePath("./etc/externalRepo/schema-map.json"), externalSchemaMappingFileLocation); + } + + @Test + public void shouldReturnDefaultExternalSchemaSchemaRefPath() throws IOException { + //when + String externalSchemaSchemaRefPath = fromTemporaryConfiguration() + .getExternalSchemaSchemaRefPath(); + + //then + assertEquals(sanitizePath("/event/stndDefinedFields/schemaReference"), externalSchemaSchemaRefPath); + } + + @Test + public void shouldReturnDefaultExternalSchemaStndDefinedDataPath() throws IOException { + //when + String externalSchemaStndDefinedDataPath = fromTemporaryConfiguration() + .getExternalSchemaStndDefinedDataPath(); + + //then + assertEquals(sanitizePath("/event/stndDefinedFields/data"), externalSchemaStndDefinedDataPath); + } + + @Test + public void shouldReturnEnabledExternalSchema2ndStageValidation() throws IOException { + //when + boolean externalSchema2ndStageValidation = fromTemporaryConfiguration("collector.externalSchema.2ndStageValidation=-1") + .getExternalSchemaValidationCheckflag(); + + //then + assertFalse(externalSchema2ndStageValidation); + } + private static ApplicationSettings fromTemporaryConfiguration(String... fileLines) - throws IOException { + throws IOException { File tempConfFile = File.createTempFile("doesNotMatter", "doesNotMatter"); Files.write(tempConfFile.toPath(), Arrays.asList(fileLines)); tempConfFile.deleteOnExit(); diff --git a/src/test/java/org/onap/dcae/TLSTest.java b/src/test/java/org/onap/dcae/TLSTest.java index e55b6052..424ddf8b 100644 --- a/src/test/java/org/onap/dcae/TLSTest.java +++ b/src/test/java/org/onap/dcae/TLSTest.java @@ -37,6 +37,11 @@ import static org.onap.dcae.TLSTest.HttpsConfigurationWithTLSAuthenticationAndBa public class TLSTest extends TLSTestBase { + private static final String MAPPING_FILE_LOCATION = "./etc/externalRepo/schema-map.json"; + private static final String SCHEMA_FILES_LOCATION = "./etc/externalRepo"; + private static final String STND_DEFINED_DATA_PATH = "/event/stndDefinedFields/data"; + private static final String SCHEMA_REF_PATH = "/event/stndDefinedFields/schemaReference"; + @Nested @Import(HttpConfiguration.class) class HttpTest extends TestClassBase { @@ -69,10 +74,16 @@ public class TLSTest extends TLSTestBase { // ApplicationSettings configurations static class HttpConfiguration extends TLSTestBase.ConfigurationBase { + @Override protected void configureSettings(ApplicationSettings settings) { when(settings.authMethod()).thenReturn(AuthMethodType.NO_AUTH.value()); when(settings.httpPort()).thenReturn(1111); + when(settings.getExternalSchemaMappingFileLocation()).thenReturn(MAPPING_FILE_LOCATION); + when(settings.getExternalSchemaSchemasLocation()).thenReturn(SCHEMA_FILES_LOCATION); + when(settings.getExternalSchemaSchemaRefPath()).thenReturn(SCHEMA_REF_PATH); + when(settings.getExternalSchemaStndDefinedDataPath()).thenReturn(STND_DEFINED_DATA_PATH); + } } @@ -89,6 +100,10 @@ public class TLSTest extends TLSTestBase { when(settings.truststorePasswordFileLocation()).thenReturn(TRUSTSTORE_PASSWORD_FILE.toString()); when(settings.certSubjectMatcher()).thenReturn(CERT_SUBJECT_MATCHER.toString()); when(settings.httpPort()).thenReturn(1111); + when(settings.getExternalSchemaMappingFileLocation()).thenReturn(MAPPING_FILE_LOCATION); + when(settings.getExternalSchemaSchemasLocation()).thenReturn(SCHEMA_FILES_LOCATION); + when(settings.getExternalSchemaSchemaRefPath()).thenReturn(SCHEMA_REF_PATH); + when(settings.getExternalSchemaStndDefinedDataPath()).thenReturn(STND_DEFINED_DATA_PATH); } } } \ No newline at end of file diff --git a/src/test/java/org/onap/dcae/common/validator/GeneralEventValidatorTest.java b/src/test/java/org/onap/dcae/common/validator/GeneralEventValidatorTest.java new file mode 100644 index 00000000..e5e21177 --- /dev/null +++ b/src/test/java/org/onap/dcae/common/validator/GeneralEventValidatorTest.java @@ -0,0 +1,197 @@ +/*- + * ============LICENSE_START======================================================= + * org.onap.dcaegen2.collectors.ves + * ================================================================================ + * 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.validator; + +import com.networknt.schema.JsonSchema; +import com.networknt.schema.JsonSchemaFactory; +import org.json.JSONObject; +import org.junit.jupiter.api.Assertions; +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.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.onap.dcae.ApplicationSettings; +import org.onap.dcae.FileReader; +import org.onap.dcae.common.model.VesEvent; +import org.onap.dcae.restapi.ApiException; +import org.onap.dcae.restapi.EventValidatorException; + +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.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class GeneralEventValidatorTest { + 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"); + private JSONObject sentEvent; + private static final String V7_VERSION = "v7"; + private static JSONObject jsonObject; + private static final String EVENT_TYPE = "event"; + + @Mock + private ApplicationSettings settings; + + private SchemaValidator schemaValidator = Mockito.spy( new SchemaValidator()); + + private GeneralEventValidator sut; + + + @BeforeAll + static void setupTests() { + jsonObject = new JSONObject("{" + DUMMY_TYPE + ":dummy}"); + } + + @BeforeEach + public void setUp(){ + this.sut = new GeneralEventValidator(settings, schemaValidator); + } + + @Test + void shouldNotValidateEventWhenJsonSchemaValidationDisabled() throws EventValidatorException { + //given + when(settings.eventSchemaValidationEnabled()).thenReturn(false); + + //when + this.sut.validate(new VesEvent(jsonObject), DUMMY_TYPE, DUMMY_SCHEMA_VERSION); + + //then + verify(schemaValidator, never()).conformsToSchema(any(), any()); + + } + + @Test + void shouldReturnInvalidJsonErrorOnWrongType() { + //given + when(settings.eventSchemaValidationEnabled()).thenReturn(true); + + //when + try { + sut.validate(new VesEvent(jsonObject), "wrongType", DUMMY_SCHEMA_VERSION); + } catch (EventValidatorException e) { + //then + Assertions.assertEquals(ApiException.INVALID_JSON_INPUT, e.getApiException()); + } + + + } + + @Test + void shouldReturnSchemaValidationFailedErrorOnInvalidJsonObjectSchema() { + //given + String schemaRejectingEverything = "{\"not\":{}}"; + mockJsonSchema(schemaRejectingEverything); + when(settings.eventSchemaValidationEnabled()).thenReturn(true); + + //when + try { + sut.validate(new VesEvent(jsonObject), DUMMY_TYPE, DUMMY_SCHEMA_VERSION); + } catch (EventValidatorException e) { + //then + assertEquals(ApiException.SCHEMA_VALIDATION_FAILED, e.getApiException()); + } + + } + + @Test + void shouldReturnEmptyOptionalOnValidJsonObjectSchema() { + //given + String schemaAcceptingEverything = "{}"; + mockJsonSchema(schemaAcceptingEverything); + when(settings.eventSchemaValidationEnabled()).thenReturn(true); + + //when + try { + sut.validate(new VesEvent(jsonObject), DUMMY_TYPE, DUMMY_SCHEMA_VERSION); + } catch (EventValidatorException e) { + failWithError(); + } + } + + @Test + public void shouldReturnNoErrorsWhenValidating30_1_1ValidEvent() { + //given + sentEvent = new JSONObject(FileReader.readFileAsString("src/test/resources/ves7_valid_30_1_1_event.json")); + + mockJsonSchema(newSchemaV7); + when(settings.eventSchemaValidationEnabled()).thenReturn(true); + + //when + try { + sut.validate(new VesEvent(sentEvent), EVENT_TYPE, V7_VERSION); + } catch (EventValidatorException e) { + failWithError(); + } + } + + @Test + void shouldReturnNoErrorsWhenValidatingValidEventWithStndDefinedFields() { + //given + sentEvent = new JSONObject(FileReader.readFileAsString("src/test/resources/ves_stdnDefined_valid.json")); + + mockJsonSchema(newSchemaV7); + when(settings.eventSchemaValidationEnabled()).thenReturn(true); + + //when + try { + sut.validate(new VesEvent(sentEvent), EVENT_TYPE, V7_VERSION); + } catch (EventValidatorException e) { + failWithError(); + } + } + + @Test + void shouldReturnSchemaValidationFailedWhenValidating30_1_1InvalidEvent() { + //given + sentEvent = new JSONObject(FileReader.readFileAsString("src/test/resources/ves7_invalid_30_1_1_event.json")); + + mockJsonSchema(newSchemaV7); + when(settings.eventSchemaValidationEnabled()).thenReturn(true); + + //when + try { + sut.validate(new VesEvent(this.sentEvent), EVENT_TYPE, V7_VERSION); + } catch (EventValidatorException e) { + //then + assertEquals(ApiException.SCHEMA_VALIDATION_FAILED, e.getApiException()); + } + + + } + + private void failWithError() { + fail("Validation should not report any error!"); + } + + private void mockJsonSchema(String jsonSchemaContent) { + JsonSchemaFactory factory = JsonSchemaFactory.getInstance(); + + JsonSchema schema = factory.getSchema(jsonSchemaContent); + when(settings.jsonSchema(any())).thenReturn(schema); + } +} \ No newline at end of file diff --git a/src/test/java/org/onap/dcae/common/validator/StndDefinedDataValidatorTest.java b/src/test/java/org/onap/dcae/common/validator/StndDefinedDataValidatorTest.java new file mode 100644 index 00000000..1058b21f --- /dev/null +++ b/src/test/java/org/onap/dcae/common/validator/StndDefinedDataValidatorTest.java @@ -0,0 +1,149 @@ +/*- + * ============LICENSE_START======================================================= + * org.onap.dcaegen2.collectors.ves + * ================================================================================ + * 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.validator; + +import org.jetbrains.annotations.NotNull; +import org.json.JSONObject; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.onap.dcae.ApplicationSettings; +import org.onap.dcae.FileReader; +import org.onap.dcae.common.model.VesEvent; +import org.onap.dcae.restapi.ApiException; +import org.onap.dcae.restapi.EventValidatorException; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +public class StndDefinedDataValidatorTest { + + @Mock + private ApplicationSettings settings; + private StndDefinedDataValidator stndDefinedDataValidator; + + private static final String MAPPING_FILE_LOCATION = "./src/test/resources/stndDefined/schema-map.json"; + private static final String SCHEMA_FILES_LOCATION = "./src/test/resources/stndDefined"; + private static final String STND_DEFINED_DATA_PATH = "/event/stndDefinedFields/data"; + private static final String SCHEMA_REF_PATH = "/event/stndDefinedFields/schemaReference"; + + @BeforeEach + public void setUp() { + mockStndDefinedValidationProps(); + StndDefinedValidatorResolver stndDefinedValidatorResolver = new StndDefinedValidatorResolver(settings); + stndDefinedDataValidator = new StndDefinedDataValidator(stndDefinedValidatorResolver.resolve()); + } + + @Test + public void shouldReturnTrueWhenEventIsValid() throws EventValidatorException { + //given + VesEvent event = getVesEvent("src/test/resources/ves_stdnDefined_valid.json"); + + //when + //then + assertDoesNotThrow(() -> stndDefinedDataValidator.validate(event)); + } + + @Test + public void shouldReturnFalseWhenEventIsInvalid() throws EventValidatorException { + //given + VesEvent event = getVesEvent("src/test/resources/ves_stdnDefined_invalid.json"); + + try { + //when + stndDefinedDataValidator.validate(event); + } catch (EventValidatorException e) { + //then + assertEquals(ApiException.STND_DEFINED_VALIDATION_FAILED, e.getApiException()); + } + } + + @Test + void shouldReturnErrorWhenMissingLocalSchemaReferenceInMappingFile() { + //given + VesEvent event = getVesEvent("src/test/resources/ves_stdnDefined_missing_local_schema_reference.json"); + try { + //when + stndDefinedDataValidator.validate(event); + } catch (EventValidatorException e) { + //then + assertEquals(ApiException.NO_LOCAL_SCHEMA_REFERENCE, e.getApiException()); + } + } + + @Test + void shouldReturnErrorWhenIncorrectInternalFileReference() { + //given + VesEvent event = getVesEvent("src/test/resources/ves_stdnDefined_wrong_internal_file_reference.json"); + try { + //when + stndDefinedDataValidator.validate(event); + } catch (EventValidatorException e) { + //then + assertEquals(ApiException.INCORRECT_INTERNAL_FILE_REFERENCE, e.getApiException()); + } + } + + @Test + void shouldReturnErrorWhenStndDefinedFieldsDataIsEmpty() { + //given + VesEvent event = getVesEvent("src/test/resources/ves_stdnDefined_with_empty_stndDefined_fields_data.json"); + try { + //when + stndDefinedDataValidator.validate(event); + } catch (EventValidatorException e) { + //then + assertEquals(ApiException.STND_DEFINED_VALIDATION_FAILED, e.getApiException()); + } + } + + @Test + void shouldNotReturnErrorWhenValidatingInvalidEventAndStndDefinedReferenceMissing() { + //given + VesEvent event = getVesEvent("src/test/resources/ves_stdnDefined_without_schema_reference.json"); + + //when + //then + assertDoesNotThrow(() -> stndDefinedDataValidator.validate(event)); + } + + @NotNull + private VesEvent getVesEvent(String filename) { + JSONObject jsonObjectEvent = getJsonObjectEvent(filename); + return new VesEvent(jsonObjectEvent); + } + + private JSONObject getJsonObjectEvent(String fileName) { + String eventContent = FileReader.readFileAsString(fileName); + return new JSONObject(eventContent); + } + + private void mockStndDefinedValidationProps() { + when(settings.getExternalSchemaMappingFileLocation()).thenReturn(MAPPING_FILE_LOCATION); + when(settings.getExternalSchemaSchemaRefPath()).thenReturn(SCHEMA_REF_PATH); + when(settings.getExternalSchemaSchemasLocation()).thenReturn(SCHEMA_FILES_LOCATION); + when(settings.getExternalSchemaStndDefinedDataPath()).thenReturn(STND_DEFINED_DATA_PATH); + } +} \ No newline at end of file diff --git a/src/test/java/org/onap/dcae/common/validator/StndDefinedValidatorResolverTest.java b/src/test/java/org/onap/dcae/common/validator/StndDefinedValidatorResolverTest.java new file mode 100644 index 00000000..9cdfdcbd --- /dev/null +++ b/src/test/java/org/onap/dcae/common/validator/StndDefinedValidatorResolverTest.java @@ -0,0 +1,65 @@ +/*- + * ============LICENSE_START======================================================= + * org.onap.dcaegen2.collectors.ves + * ================================================================================ + * 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.validator; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.onap.dcae.ApplicationSettings; + +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +public class StndDefinedValidatorResolverTest { + + @Mock + private ApplicationSettings settings; + + private static final String MAPPING_FILE_LOCATION = "./src/test/resources/stndDefined/schema-map.json"; + private static final String SCHEMA_FILES_LOCATION = "./src/test/resources/stndDefined"; + private static final String STND_DEFINED_DATA_PATH = "/event/stndDefinedFields/data"; + private static final String SCHEMA_REF_PATH = "/event/stndDefinedFields/schemaReference"; + StndDefinedValidatorResolver stndDefinedValidatorResolver; + + @BeforeEach + public void setUp() { + mockStndDefinedValidationProps(); + stndDefinedValidatorResolver = new StndDefinedValidatorResolver(settings); + } + + @Test + public void shouldReturnStndValidatorWithDefaultSchemaConfigurations() { + //then + Assertions.assertDoesNotThrow(() -> stndDefinedValidatorResolver.resolve()); + } + + private void mockStndDefinedValidationProps() { + when(settings.getExternalSchemaMappingFileLocation()).thenReturn(MAPPING_FILE_LOCATION); + when(settings.getExternalSchemaSchemaRefPath()).thenReturn(SCHEMA_REF_PATH); + when(settings.getExternalSchemaSchemasLocation()).thenReturn(SCHEMA_FILES_LOCATION); + when(settings.getExternalSchemaStndDefinedDataPath()).thenReturn(STND_DEFINED_DATA_PATH); + } + + +} \ No newline at end of file diff --git a/src/test/java/org/onap/dcae/restapi/EventValidatorTest.java b/src/test/java/org/onap/dcae/restapi/EventValidatorTest.java deleted file mode 100644 index 0ca5c424..00000000 --- a/src/test/java/org/onap/dcae/restapi/EventValidatorTest.java +++ /dev/null @@ -1,194 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * org.onap.dcaegen2.collectors.ves - * ================================================================================ - * 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; - -import com.networknt.schema.JsonSchema; -import com.networknt.schema.JsonSchemaFactory; -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.Mock; -import org.mockito.junit.jupiter.MockitoExtension; -import org.onap.dcae.ApplicationSettings; -import org.onap.dcae.FileReader; -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) -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"); - private JSONObject sentEvent; - private static final String V7_VERSION = "v7"; - private static JSONObject jsonObject; - private static final String EVENT_TYPE = "event"; - - @Mock - private ApplicationSettings settings; - - private SchemaValidator schemaValidator = spy( new SchemaValidator()); - - private EventValidator sut; - - - @BeforeAll - static void setupTests() { - jsonObject = new JSONObject("{" + DUMMY_TYPE + ":dummy}"); - } - - @BeforeEach - public void setUp(){ - this.sut = new EventValidator(settings, schemaValidator); - } - - @Test - void shouldNotValidateEventWhenJsonSchemaValidationDisabled() throws EventValidatorException { - //given - when(settings.eventSchemaValidationEnabled()).thenReturn(false); - - //when - this.sut.validate(new VesEvent(jsonObject), DUMMY_TYPE, DUMMY_SCHEMA_VERSION); - - //then - verify(schemaValidator, never()).conformsToSchema(any(), any()); - - } - - @Test - void shouldReturnInvalidJsonErrorOnWrongType() { - //given - when(settings.eventSchemaValidationEnabled()).thenReturn(true); - - //when - try { - sut.validate(new VesEvent(jsonObject), "wrongType", DUMMY_SCHEMA_VERSION); - } catch (EventValidatorException e) { - //then - assertEquals(ApiException.INVALID_JSON_INPUT, e.getApiException()); - } - - - } - - @Test - void shouldReturnSchemaValidationFailedErrorOnInvalidJsonObjectSchema() { - //given - String schemaRejectingEverything = "{\"not\":{}}"; - mockJsonSchema(schemaRejectingEverything); - when(settings.eventSchemaValidationEnabled()).thenReturn(true); - - //when - try { - sut.validate(new VesEvent(jsonObject), DUMMY_TYPE, DUMMY_SCHEMA_VERSION); - } catch (EventValidatorException e) { - //then - assertEquals(ApiException.SCHEMA_VALIDATION_FAILED, e.getApiException()); - } - - } - - @Test - void shouldReturnEmptyOptionalOnValidJsonObjectSchema() { - //given - String schemaAcceptingEverything = "{}"; - mockJsonSchema(schemaAcceptingEverything); - when(settings.eventSchemaValidationEnabled()).thenReturn(true); - - //when - try { - sut.validate(new VesEvent(jsonObject), DUMMY_TYPE, DUMMY_SCHEMA_VERSION); - } catch (EventValidatorException e) { - failWithError(); - } - } - - @Test - public void shouldReturnNoErrorsWhenValidating30_1_1ValidEvent() { - //given - sentEvent = new JSONObject(FileReader.readFileAsString("src/test/resources/ves7_valid_30_1_1_event.json")); - - mockJsonSchema(newSchemaV7); - when(settings.eventSchemaValidationEnabled()).thenReturn(true); - - //when - try { - sut.validate(new VesEvent(sentEvent), EVENT_TYPE, V7_VERSION); - } catch (EventValidatorException e) { - failWithError(); - } - } - - @Test - void shouldReturnNoErrorsWhenValidatingValidEventWithStndDefinedFields() { - //given - sentEvent = new JSONObject(FileReader.readFileAsString("src/test/resources/ves7_valid_eventWithStndDefinedFields.json")); - - mockJsonSchema(newSchemaV7); - when(settings.eventSchemaValidationEnabled()).thenReturn(true); - - //when - try { - sut.validate(new VesEvent(sentEvent), EVENT_TYPE, V7_VERSION); - } catch (EventValidatorException e) { - failWithError(); - } - } - - @Test - void shouldReturnSchemaValidationFailedWhenValidating30_1_1InvalidEvent() { - //given - sentEvent = new JSONObject(FileReader.readFileAsString("src/test/resources/ves7_invalid_30_1_1_event.json")); - - mockJsonSchema(newSchemaV7); - when(settings.eventSchemaValidationEnabled()).thenReturn(true); - - //when - try { - sut.validate(new VesEvent(this.sentEvent), EVENT_TYPE, V7_VERSION); - } catch (EventValidatorException e) { - //then - assertEquals(ApiException.SCHEMA_VALIDATION_FAILED, e.getApiException()); - } - - - } - - private void failWithError() { - fail("Validation should not report any error!"); - } - - private void mockJsonSchema(String jsonSchemaContent) { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(); - - JsonSchema schema = factory.getSchema(jsonSchemaContent); - when(settings.jsonSchema(any())).thenReturn(schema); - } -} diff --git a/src/test/java/org/onap/dcae/restapi/VesRestControllerTest.java b/src/test/java/org/onap/dcae/restapi/VesRestControllerTest.java index 10423053..765f2b43 100644 --- a/src/test/java/org/onap/dcae/restapi/VesRestControllerTest.java +++ b/src/test/java/org/onap/dcae/restapi/VesRestControllerTest.java @@ -40,6 +40,7 @@ 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.validator.StndDefinedDataValidator; import org.onap.dcae.common.publishing.EventPublisher; import org.slf4j.Logger; import org.springframework.http.ResponseEntity; @@ -85,16 +86,17 @@ public class VesRestControllerTest { @Mock private EventPublisher eventPublisher; + @Mock + private StndDefinedDataValidator stndDefinedDataValidator; + @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 - ); + this.vesRestController = new VesRestController(applicationSettings, logger, + new EventSender(eventPublisher, streamIds), headerUtils, stndDefinedDataValidator); } @Test @@ -229,7 +231,6 @@ public class VesRestControllerTest { configureHeadersForEventListener(); MockHttpServletRequest request = givenMockHttpServletRequest(); - String validEvent = JsonDataLoader.loadContent("/ves_stdnDefined_valid_unknown_topic.json"); //when @@ -241,6 +242,44 @@ public class VesRestControllerTest { verifyThatEventWasNotSend(); } + @Test + public void shouldExecuteStndDefinedValidationWhenFlagIsOnTrue() throws IOException { + //given + configureEventTransformations(); + configureHeadersForEventListener(); + + MockHttpServletRequest request = givenMockHttpServletRequest(); + String validEvent = JsonDataLoader.loadContent("/ves7_batch_with_stndDefined_valid.json"); + when(applicationSettings.getExternalSchemaValidationCheckflag()).thenReturn(true); + + //when + final ResponseEntity response = vesRestController.events(validEvent, VERSION_V7, request); + + //then + assertThat(response.getStatusCodeValue()).isEqualTo(HttpStatus.SC_ACCEPTED); + assertThat(response.getBody()).isEqualTo(ACCEPTED); + verify(stndDefinedDataValidator, times(2)).validate(any()); + } + + @Test + public void shouldNotExecuteStndDefinedValidationWhenFlagIsOnFalse() throws IOException { + //given + configureEventTransformations(); + configureHeadersForEventListener(); + + MockHttpServletRequest request = givenMockHttpServletRequest(); + String validEvent = JsonDataLoader.loadContent("/ves7_batch_with_stndDefined_valid.json"); + when(applicationSettings.getExternalSchemaValidationCheckflag()).thenReturn(false); + + //when + final ResponseEntity response = vesRestController.events(validEvent, VERSION_V7, request); + + //then + assertThat(response.getStatusCodeValue()).isEqualTo(HttpStatus.SC_ACCEPTED); + assertThat(response.getBody()).isEqualTo(ACCEPTED); + verify(stndDefinedDataValidator, times(0)).validate(any()); + } + private void verifyThatEventWasNotSend() { verify(eventPublisher, never()).sendEvent(any(), any()); } diff --git a/src/test/resources/stndDefined/OpenAPI_faultMnS.yaml b/src/test/resources/stndDefined/OpenAPI_faultMnS.yaml new file mode 100644 index 00000000..499123b9 --- /dev/null +++ b/src/test/resources/stndDefined/OpenAPI_faultMnS.yaml @@ -0,0 +1,1144 @@ +openapi: 3.0.1 +info: + title: Fault Supervision MnS + version: 16.4.0 + description: >- + OAS 3.0.1 definition of the Fault Supervision MnS + © 2020, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TSDSI, TTA, TTC). + All rights reserved. +externalDocs: + description: 3GPP TS 28.532 V16.4.0; Generic management services + url: http://www.3gpp.org/ftp/Specs/archive/28_series/28.532/ +servers: + - url: '{MnSRoot}/FaultSupervisionMnS/{version}' + variables: + MnSRoot: + description: See subclause 4.4.3 of TS 32.158 + default: http://example.com/3GPPManagement + version: + description: Versi on number of the OpenAPI definition + default: XXX +paths: + /alarms: + get: + summary: Retrieve multiple alarms + description: >- + Retrieves the alarms identified by alarmAckState, baseObjectInstance + and filter. + parameters: + - name: alarmAckState + in: query + required: false + schema: + $ref: '#/components/schemas/AlarmAckState' + - name: baseObjectInstance + in: query + required: false + schema: + $ref: '#/components/schemas/Dn' + - name: filter + in: query + required: false + schema: + $ref: '#/components/schemas/Filter' + responses: + '200': + description: >- + Success case ("200 OK"). + Returns the alarms identified in the request. The alarmId is the key + of the map. + content: + application/json: + schema: + type: object + additionalProperties: + type: object + allOf: + - type: object + properties: + lastNotificationHeader: + $ref: '#/components/schemas/NotificationHeader' + - $ref: '#/components/schemas/AlarmRecord' + - type: object + properties: + comments: + $ref: '#/components/schemas/Comments' + default: + description: Response in case of error. + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + patch: + summary: 'Clear, acknowledge or unacknowledge multiple alarms' + description: >- + Clears, acknowledges or unacknowledges multiple alarms using patch. Depending + on which action is to be performed, different merge patch documents need + to be used. + requestBody: + description: >- + Patch documents for acknowledging and unacknowledging, or clearing multiple + alarms. The keys in the map are the alarmIds to be patched. + content: + application/merge-patch+json: + schema: + oneOf: + - type: object + additionalProperties: + $ref: '#/components/schemas/MergePatchAcknowledgeAlarm' + - type: object + additionalProperties: + $ref: '#/components/schemas/MergePatchClearAlarm' + responses: + '204': + description: >- + Success case ("204 No content"). + The response message body is empty. + default: + description: Response in case of error. + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/FailedAlarm' + /alarms/alarmCount: + get: + summary: Get the alarm count per perceived severity + parameters: + - name: alarmAckState + in: query + required: false + schema: + $ref: '#/components/schemas/AlarmAckState' + - name: filter + in: query + required: false + schema: + type: string + responses: + '200': + description: >- + Success case ("200 OK"). + The alarm count per perceived severity is returned. + content: + application/json: + schema: + $ref: '#/components/schemas/AlarmCount' + default: + description: Response in case of error. The error case needs rework. + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + /alarms/{alarmId}: + patch: + summary: 'Clear, acknowledge or unacknowledge a single alarm' + description: >- + Clears, acknowledges or uncknowldeges a single alarm by patching the alarm + information. A conditional acknowledge request based on the perceived + severity is not supported. + parameters: + - name: alarmId + in: path + description: Identifies the alarm to be patched. + required: true + schema: + type: string + requestBody: + required: true + content: + application/merge-patch+json: + schema: + oneOf: + - $ref: '#/components/schemas/MergePatchAcknowledgeAlarm' + - $ref: '#/components/schemas/MergePatchClearAlarm' + responses: + '204': + description: >- + Success case (204 No content). + The response message body is absent. + default: + description: Response in case of error. + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + /alarms/{alarmId}/comments: + post: + summary: Add a comment to a single alarm + description: >- + Adds a comment to an alarm identified by alarmId. The id of the new comment + is allocated by the producer. + parameters: + - name: alarmId + in: path + description: Identifies the alarm to which the comment shall be added. + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Comment' + responses: + '201': + description: >- + Success case (201 Created). + The representation of the newly created comment resource shall be returned. + content: + application/json: + schema: + $ref: '#/components/schemas/Comment' + headers: + Location: + description: URI of the newly created comment resource. + required: true + schema: + type: string + default: + description: Error case. + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /subscriptions: + post: + summary: Create a subscription + description: >- + To create a subscription the representation of the subscription is + POSTed on the /subscriptions collection resource. + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Subscription' + responses: + '201': + description: >- + Success case ("201 Created"). + The representation of the newly created subscription resource shall + be returned. + content: + application/json: + schema: + $ref: '#/components/schemas/Subscription' + headers: + Location: + description: URI of the newly created subscription resource + required: true + schema: + type: string + default: + description: Error case. + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + callbacks: + notifyNewAlarm: + '{request.body#/consumerReference}': + post: + requestBody: + required: true + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/NotifyNewAlarm' + - $ref: '#/components/schemas/NotifyNewSecAlarm' + responses: + '204': + description: >- + Success case ("204 No Content"). + The notification is successfully delivered. The response message + body is absent. + default: + description: Error case. + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + notifyClearedAlarm: + '{request.body#/consumerReference}': + post: + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/NotifyClearedAlarm' + responses: + '204': + description: >- + Success case ("204 No Content"). + The notification is successfully delivered. The response message + body is absent. + default: + description: Error case. + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + notifyChangedAlarm: + '{request.body#/consumerReference}': + post: + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/NotifyChangedAlarm' + responses: + '204': + description: >- + Success case ("204 No Content"). + The notification is successfully delivered. The response message + body is absent. + default: + description: Error case. + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + notifyChangedAlarmGeneral: + '{request.body#/consumerReference}': + post: + requestBody: + required: true + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/NotifyChangedAlarmGeneral' + - $ref: '#/components/schemas/NotifyChangedSecAlarmGeneral' + responses: + '204': + description: >- + Success case ("204 No Content"). + The notification is successfully delivered. The response message + body is absent. + default: + description: Error case. + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + notifyCorrelatedNotificationChanged: + '{request.body#/consumerReference}': + post: + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/NotifyCorrelatedNotificationChanged' + responses: + '204': + description: >- + Success case ("204 No Content"). + The notification is successfully delivered. The response message + body is absent. + default: + description: Error case. + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + notifyAckStateChanged: + '{request.body#/consumerReference}': + post: + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/NotifyAckStateChanged' + responses: + '204': + description: >- + Success case ("204 No Content"). + The notification is successfully delivered. The response message + body is absent. + default: + description: Error case. + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + notifyComments: + '{request.body#/consumerReference}': + post: + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/NotifyComments' + responses: + '204': + description: >- + Success case ("204 No Content"). + The notification is successfully delivered. The response message + body is absent. + default: + description: Error case. + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + notifyPotentialFaultyAlarmList: + '{request.body#/consumerReference}': + post: + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/NotifyPotentialFaultyAlarmList' + responses: + '204': + description: >- + Success case ("204 No Content"). + The notification is successfully delivered. The response message + body is absent. + default: + description: Error case. + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + notifyAlarmListRebuilt: + '{request.body#/consumerReference}': + post: + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/NotifyAlarmListRebuilt' + responses: + '204': + description: >- + Success case ("204 No Content"). + The notification is successfully delivered. The response message + body is absent. + default: + description: Error case. + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + /subscriptions/{subscriptionId}: + delete: + summary: Delete a subscription + description: >- + The subscription is deleted by deleting the corresponding subscription + resource. The resource to be deleted is identified with the path + component of the URI. + parameters: + - name: subscriptionId + in: path + description: Identifies the subscription to be deleted. + required: true + schema: + type: string + responses: + '204': + description: >- + Success case ("204 No Content"). + The subscription resource has been deleted. The response message body + is absent. + default: + description: Error case. + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + +components: + schemas: + + #---- Definitions to be moved to comDefs.yaml --------------------------------------# + + Long: + type: string + format: long + Float: + type: string + format: float + DateTime: + type: string + format: date-Time + + Dn: + type: string + Uri: + type: string + + AttributeNameValuePairSet: + type: object + minProperties: 1 + AttributeValueChangeSet: + description: >- + The key in this map is the attribute name. The value of each key is an array. + When only one item is present in the array, it carries the new attribute + value. If two items are present, then the first item carries the old value + and the second item the new value. The items can be of any type including null. + type: object + additionalProperties: + type: array + minItems: 1 + maxItems: 2 + items: + nullable: true + + Filter: + type: string + SystemDN: + type: string + + NotificationId: + type: integer + NotificationHeader: + description: >- + Header used for all notification types + type: object + required: + - href + - notificationId + - notificationType + - eventTime + - systemDN + properties: + uri: + $ref: '#/components/schemas/Uri' + notificationId: + $ref: '#/components/schemas/NotificationId' + notificationType: + oneOf: + - $ref: '#/components/schemas/AlarmNotificationTypes' + #- $ref: 'faultMnS.yaml#/components/schemas/AlarmNotificationTypes' + #- $ref: 'provMnS.yaml#/components/schemas/CmNotificationTypes' + # more to be added + eventTime: + $ref: '#/components/schemas/DateTime' + systemDN: + $ref: '#/components/schemas/SystemDN' + + ErrorResponse: + description: >- + Default schema for the response message body in case the request is not + successful. + type: object + properties: + error: + type: object + properties: + errorInfo: + type: string + + #---- End of definitions to be moved to comDefs.yaml -------------------------------# + + #---- Definition of AlarmRecord ----------------------------------------------------# + + AlarmId: + type: string + AlarmType: + type: string + enum: + - COMMUNICATIONS_ALARM + - QUALITY_OF_SERVICE_ALARM + - PROCESSING_ERROR_ALARM + - EQUIPMENT_ALARM + - ENVIRONMENTAL_ALARM + - INTEGRITY_VIOLATION + - OPERATIONAL_VIOLATION + - PHYSICAL_VIOLATION + - SECURITY_SERVICE_OR_MECHANISM_VIOLATION + - TIME_DOMAIN_VIOLATION + ProbableCause: + description: >- + The value of the probable cause may be a specific standardized string, or any + vendor provided string. Probable cause strings are not standardized in the + present document. They may be added in a future version. Up to then the + mapping of the generic probable cause strings "PROBABLE_CAUSE_001" to + "PROBABLE_CAUSE_005" is vendor specific. + The value of the probable cause may also be an integer. The mapping of integer + values to probable causes is vendor specific. + oneOf: + - anyOf: + - type: string + enum: + - PROBABLE_CAUSE_001 + - PROBABLE_CAUSE_002 + - PROBABLE_CAUSE_003 + - PROBABLE_CAUSE_004 + - PROBABLE_CAUSE_005 + - type: string + - type: integer + SpecificProblem: + oneOf: + - type: string + - type: integer + PerceivedSeverity: + type: string + enum: + - INDETERMINATE + - CRITICAL + - MAJOR + - MINOR + - WARNING + - CLEARED + TrendIndication: + type: string + enum: + - MORE_SEVERE + - NO_CHANGE + - LESS_SEVERE + ThresholdHysteresis: + type: object + required: + - high + properties: + high: + oneOf: + - type: integer + - $ref: '#/components/schemas/Float' + low: + $ref: '#/components/schemas/Float' + ThresholdLevelInd: + type: object + required: + - up + properties: + up: + $ref: '#/components/schemas/ThresholdHysteresis' + low: + $ref: '#/components/schemas/ThresholdHysteresis' + ThresholdInfo: + type: object + required: + - observedMeasurement + - observedValue + properties: + observedMeasurement: + type: string + observedValue: + oneOf: + - type: integer + - $ref: '#/components/schemas/Float' + thresholdLevelInd: + $ref: '#/components/schemas/ThresholdLevelInd' + armTime: + $ref: '#/components/schemas/DateTime' + CorrelatedNotification: + type: object + required: + - source + - notificationId + properties: + sourceObjectInstance: + $ref: '#/components/schemas/Dn' + notificationIds: + type: array + items: + $ref: '#/components/schemas/NotificationId' + CorrelatedNotifications: + type: array + items: + $ref: '#/components/schemas/CorrelatedNotification' + AckState: + type: string + enum: + - ACKNOWLEDGED + - UNACKNOWLEDGED + + AlarmRecord: + description: >- + The alarmId is not a property of an alarm record. It is used as key + in the map of alarm records instead. + type: object + properties: + # alarmId: + # $ref: '#/components/schemas/AlarmId' + objectInstance: + $ref: '#/components/schemas/Dn' + notificationId: + $ref: '#/components/schemas/NotificationId' + alarmRaisedTime: + $ref: '#/components/schemas/DateTime' + alarmChangedTime: + $ref: '#/components/schemas/DateTime' + alarmClearedTime: + $ref: '#/components/schemas/DateTime' + alarmType: + $ref: '#/components/schemas/AlarmType' + probableCause: + $ref: '#/components/schemas/ProbableCause' + specificProblem: + $ref: '#/components/schemas/SpecificProblem' + perceivedSeverity: + $ref: '#/components/schemas/PerceivedSeverity' + backedUpStatus: + type: boolean + backUpObject: + $ref: '#/components/schemas/Dn' + trendIndication: + $ref: '#/components/schemas/TrendIndication' + thresholdinfo: + $ref: '#/components/schemas/ThresholdInfo' + correlatedNotifications: + $ref: '#/components/schemas/CorrelatedNotifications' + stateChangeDefinition: + $ref: '#/components/schemas/AttributeValueChangeSet' + monitoredAttributes: + $ref: '#/components/schemas/AttributeNameValuePairSet' + proposedRepairActions: + type: string + additionalText: + type: string + additionalInformation: + $ref: '#/components/schemas/AttributeNameValuePairSet' + + rootCauseIndicator: + type: boolean + + ackTime: + $ref: '#/components/schemas/DateTime' + ackUserId: + type: string + ackSystemId: + type: string + ackState: + $ref: '#/components/schemas/AckState' + + clearUserId: + type: string + clearSystemId: + type: string + serviceUser: + type: string + serviceProvider: + type: string + securityAlarmDetector: + type: string + + #---- Definition of alarm notifications --------------------------------------------# + + AlarmNotificationTypes: + type: string + enum: + - notifyNewAlarm + - notifyChangedAlarm + - notifyChangedAlarmGeneral + - notifyAckStateChanged + - notifyCorrelatedNotificationChanged + - notifyComments + - notifyClearedAlarm + - notifyAlarmListRebuiltAlarm + - notifyPotentialFaultyAlarmList + AlarmListAlignmentRequirement: + type: string + enum: + - ALIGNMENT_REQUIRED + - ALIGNMENT_NOT_REQUIRED + + NotifyNewAlarm: + allOf: + - $ref: '#/components/schemas/NotificationHeader' + - type: object + required: + - alarmId + - alarmType + - probableCause + - perceivedSeverity + properties: + alarmId: + $ref: '#/components/schemas/AlarmId' + alarmType: + $ref: '#/components/schemas/AlarmType' + probableCause: + $ref: '#/components/schemas/ProbableCause' + specificProblem: + $ref: '#/components/schemas/SpecificProblem' + perceivedSeverity: + $ref: '#/components/schemas/PerceivedSeverity' + backedUpStatus: + type: boolean + backUpObject: + $ref: '#/components/schemas/Dn' + trendIndication: + $ref: '#/components/schemas/TrendIndication' + thresholdInfo: + $ref: '#/components/schemas/ThresholdInfo' + correlatedNotifications: + $ref: '#/components/schemas/CorrelatedNotifications' + stateChangeDefinition: + $ref: '#/components/schemas/AttributeValueChangeSet' + monitoredAttributes: + $ref: '#/components/schemas/AttributeNameValuePairSet' + proposedRepairActions: + type: string + additionalText: + type: string + additionalInformation: + $ref: '#/components/schemas/AttributeNameValuePairSet' + rootCauseIndicator: + type: boolean + NotifyNewSecAlarm: + allOf: + - $ref: '#/components/schemas/NotificationHeader' + - type: object + required: + - alarmId + - alarmType + - probableCause + - perceivedSeverity + - serviceUser + - serviceProvider + - securityAlarmDetector + properties: + alarmId: + $ref: '#/components/schemas/AlarmId' + alarmType: + $ref: '#/components/schemas/AlarmType' + probableCause: + $ref: '#/components/schemas/ProbableCause' + perceivedSeverity: + $ref: '#/components/schemas/PerceivedSeverity' + correlatedNotifications: + $ref: '#/components/schemas/CorrelatedNotifications' + additionalText: + type: string + additionalInformation: + $ref: '#/components/schemas/AttributeNameValuePairSet' + rootCauseIndicator: + type: boolean + serviceUser: + type: string + serviceProvider: + type: string + securityAlarmDetector: + type: string + NotifyClearedAlarm: + allOf: + - $ref: '#/components/schemas/NotificationHeader' + - type: object + required: + - alarmId + - alarmType + - probableCause + - perceivedSeverity + properties: + alarmId: + $ref: '#/components/schemas/AlarmId' + alarmType: + $ref: '#/components/schemas/AlarmType' + probableCause: + $ref: '#/components/schemas/ProbableCause' + perceivedSeverity: + $ref: '#/components/schemas/PerceivedSeverity' + correlatedNotifications: + $ref: '#/components/schemas/CorrelatedNotifications' + clearUserId: + type: string + clearSystemId: + type: string + NotifyChangedAlarm: + allOf: + - $ref: '#/components/schemas/NotificationHeader' + - type: object + required: + - alarmId + - alarmType + - probableCause + - perceivedSeverity + properties: + alarmId: + $ref: '#/components/schemas/AlarmId' + alarmType: + $ref: '#/components/schemas/AlarmType' + probableCause: + $ref: '#/components/schemas/ProbableCause' + perceivedSeverity: + $ref: '#/components/schemas/PerceivedSeverity' + NotifyChangedAlarmGeneral: + allOf: + - $ref: '#/components/schemas/NotificationHeader' + - type: object + required: + - alarmId + - alarmType + - probableCause + - perceivedSeverity + - changedAlarmAttributes + properties: + alarmId: + $ref: '#/components/schemas/AlarmId' + alarmType: + $ref: '#/components/schemas/AlarmType' + probableCause: + $ref: '#/components/schemas/ProbableCause' + specificProblem: + $ref: '#/components/schemas/SpecificProblem' + perceivedSeverity: + $ref: '#/components/schemas/PerceivedSeverity' + correlatedNotifications: + $ref: '#/components/schemas/CorrelatedNotifications' + backedUpStatus: + type: boolean + backUpObject: + $ref: '#/components/schemas/Dn' + trendIndication: + $ref: '#/components/schemas/TrendIndication' + thresholdInfo: + $ref: '#/components/schemas/ThresholdInfo' + stateChangeDefinition: + $ref: '#/components/schemas/AttributeValueChangeSet' + monitoredAttributes: + $ref: '#/components/schemas/AttributeNameValuePairSet' + proposedRepairActions: + type: string + additionalText: + type: string + additionalInformation: + $ref: '#/components/schemas/AttributeNameValuePairSet' + rootCauseIndicator: + type: boolean + changedAlarmAttributes: + $ref: '#/components/schemas/AttributeNameValuePairSet' + NotifyChangedSecAlarmGeneral: + allOf: + - $ref: '#/components/schemas/NotificationHeader' + - type: object + required: + - alarmId + - alarmType + - probableCause + - perceivedSeverity + - serviceUser + - serviceProvider + - securityAlarmDetector + - changedAlarmAttributes + properties: + alarmId: + $ref: '#/components/schemas/AlarmId' + alarmType: + $ref: '#/components/schemas/AlarmType' + probableCause: + $ref: '#/components/schemas/ProbableCause' + perceivedSeverity: + $ref: '#/components/schemas/PerceivedSeverity' + correlatedNotifications: + $ref: '#/components/schemas/CorrelatedNotifications' + additionalText: + type: string + additionalInformation: + $ref: '#/components/schemas/AttributeNameValuePairSet' + rootCauseIndicator: + type: boolean + serviceUser: + type: string + serviceProvider: + type: string + securityAlarmDetector: + type: string + changedAlarmAttributes: + $ref: '#/components/schemas/AttributeNameValuePairSet' + NotifyCorrelatedNotificationChanged: + allOf: + - $ref: '#/components/schemas/NotificationHeader' + - type: object + required: + - alarmId + - correlatedNotifications + properties: + alarmId: + $ref: '#/components/schemas/AlarmId' + correlatedNotifications: + $ref: '#/components/schemas/CorrelatedNotifications' + rootCauseIndicator: + type: boolean + NotifyAckStateChanged: + allOf: + - $ref: '#/components/schemas/NotificationHeader' + - type: object + required: + - alarmId + - alarmType + - probableCause + - perceivedSeverity + - ackState + - ackUserId + properties: + alarmId: + $ref: '#/components/schemas/AlarmId' + alarmType: + $ref: '#/components/schemas/AlarmType' + probableCause: + $ref: '#/components/schemas/ProbableCause' + perceivedSeverity: + $ref: '#/components/schemas/PerceivedSeverity' + ackState: + $ref: '#/components/schemas/AckState' + ackUserId: + type: string + ackSystemId: + type: string + NotifyComments: + allOf: + - $ref: '#/components/schemas/NotificationHeader' + - type: object + required: + - alarmId + - alarmType + - probableCause + - perceivedSeverity + - comments + properties: + alarmId: + $ref: '#/components/schemas/AlarmId' + alarmType: + $ref: '#/components/schemas/AlarmType' + probableCause: + $ref: '#/components/schemas/ProbableCause' + perceivedSeverity: + $ref: '#/components/schemas/PerceivedSeverity' + comments: + $ref: '#/components/schemas/Comments' + NotifyPotentialFaultyAlarmList: + allOf: + - $ref: '#/components/schemas/NotificationHeader' + - type: object + required: + - reason + properties: + reason: + type: string + NotifyAlarmListRebuilt: + allOf: + - $ref: '#/components/schemas/NotificationHeader' + - type: object + required: + - reason + properties: + reason: + type: string + alarmListAlignmentRequirement: + $ref: '#/components/schemas/AlarmListAlignmentRequirement' + + #---- Definition of query parameters -----------------------------------------------# + + AlarmAckState: + type: string + enum: + - ALL_ALARMS + - ALL_ACTIVE_ALARMS + - ALL_ACTIVE_AND_ACKNOWLEDGED_ALARMS + - ALL_ACTIVE_AND_UNACKNOWLEDGED_ALARMS + - ALL_CLEARED_AND_UNACKNOWLEDGED_ALARMS + - ALL_UNACKNOWLEDGED_ALARMS + + #---- Definition of patch documents ------------------------------------------------# + + MergePatchAcknowledgeAlarm: + description: >- + Patch document acknowledging or unacknowledging a single alarm. For + acknowleding an alarm the value of ackState is ACKNOWLEDGED, for unacknowleding + an alarm the value of ackState is UNACKNOWLEDGED. + type: object + required: + - ackUserId + - ackState + properties: + ackUserId: + type: string + ackSystemId: + type: string + ackState: + $ref: '#/components/schemas/AckState' + MergePatchClearAlarm: + description: Patch document for clearing a single alarm + type: object + required: + - clearUserId + - perceivedSeverity + properties: + clearUserId: + type: string + clearSystemId: + type: string + perceivedSeverity: + type: string + enum: + - CLEARED + + #---- Definition of method responses -----------------------------------------------# + + FailedAlarm: + type: object + required: + - alarmId + - failureReason + properties: + alarmId: + $ref: '#/components/schemas/AlarmId' + failureReason: + type: string + + #---- Definition of resources ------------------------------------------------------# + + AlarmCount: + type: object + required: + - criticalCount + - majorCount + - minorCount + - warningCount + - indeterminateCount + - clearedCount + properties: + criticalCount: + type: integer + majorCount: + type: integer + minorCount: + type: integer + warningCount: + type: integer + indeterminateCount: + type: integer + clearedCount: + type: integer + Comment: + type: object + properties: + commentTime: + $ref: '#/components/schemas/DateTime' + commentUserId: + type: string + commentSystemId: + type: string + commentText: + type: string + Comments: + description: >- + Collection of comments. The comment identifiers are allocated by the + MnS producer and used as key in the map. + type: object + additionalProperties: + $ref: '#/components/schemas/Comment' + Subscription: + type: object + properties: + consumerReference: + $ref: '#/components/schemas/Uri' + timeTick: + $ref: '#/components/schemas/Long' + filter: + $ref: '#/components/schemas/Filter' diff --git a/src/test/resources/stndDefined/schema-map.json b/src/test/resources/stndDefined/schema-map.json new file mode 100644 index 00000000..6d19037c --- /dev/null +++ b/src/test/resources/stndDefined/schema-map.json @@ -0,0 +1,6 @@ +[ + { + "publicURL": "https://forge.3gpp.org/rep/sa5/data-models/blob/REL-16/OpenAPI/faultMnS.yaml", + "localURL": "OpenAPI_faultMnS.yaml" + } +] \ No newline at end of file diff --git a/src/test/resources/ves7_batch_with_stndDefined_valid.json b/src/test/resources/ves7_batch_with_stndDefined_valid.json new file mode 100644 index 00000000..10ab4b49 --- /dev/null +++ b/src/test/resources/ves7_batch_with_stndDefined_valid.json @@ -0,0 +1,109 @@ +{ + "eventList": [ + { + "commonEventHeader": { + "version": "4.1", + "vesEventListenerVersion": "7.2", + "domain": "stndDefined", + "eventId": "stndDefined-gNB_Nokia000001", + "eventName": "stndDefined-gNB-Nokia-PowerLost", + "stndDefinedNamespace": "3GPP-FaultSupervision", + "startEpochMicrosec": 1413378172000000, + "lastEpochMicrosec": 1413378172000000, + "reportingEntityName": "ibcx0001vm002oam001", + "sourceName": "scfx0001vm002cap001", + "sequence": 1, + "priority": "High" + }, + "stndDefinedFields": { + "schemaReference": "https://forge.3gpp.org/rep/sa5/data-models/blob/REL-16/OpenAPI/faultMnS.yaml#components/schemas/NotifyNewAlarm", + "data": { + "href": 1, + "uri": "1", + "notificationId": 1, + "notificationType": "notifyNewAlarm", + "eventTime": "xyz", + "systemDN": "xyz", + "probableCause": 1, + "perceivedSeverity": "INDETERMINATE", + "rootCauseIndicator": false, + "specificProblem": "xyz", + "correlatedNotifications": [], + "backedUpStatus": true, + "backUpObject": "xyz", + "trendIndication": "MORE_SEVERE", + "thresholdInfo": { + "observedMeasurement": "new", + "observedValue": 123 + }, + "stateChangeDefinition": { + }, + "monitoredAttributes": { + "newAtt": "new" + }, + "proposedRepairActions": "xyz", + "additionalText": "xyz", + "additionalInformation": { + "addInfo": "new" + }, + "alarmId": "1", + "alarmType": "COMMUNICATIONS_ALARM" + }, + "stndDefinedFieldsVersion": "1.0" + } + }, + { + "commonEventHeader": { + "version": "4.1", + "vesEventListenerVersion": "7.2", + "domain": "stndDefined", + "eventId": "stndDefined-gNB_Nokia000001", + "eventName": "stndDefined-gNB-Nokia-PowerLost", + "stndDefinedNamespace": "3GPP-FaultSupervision", + "startEpochMicrosec": 1413378172000000, + "lastEpochMicrosec": 1413378172000000, + "reportingEntityName": "ibcx0001vm002oam001", + "sourceName": "scfx0001vm002cap001", + "sequence": 1, + "priority": "High" + }, + "stndDefinedFields": { + "schemaReference": "https://forge.3gpp.org/rep/sa5/data-models/blob/REL-16/OpenAPI/faultMnS.yaml#components/schemas/NotifyNewAlarm", + "data": { + "href": 1, + "uri": "1", + "notificationId": 1, + "notificationType": "notifyNewAlarm", + "eventTime": "xyz", + "systemDN": "xyz", + "probableCause": 1, + "perceivedSeverity": "INDETERMINATE", + "rootCauseIndicator": false, + "specificProblem": "xyz", + "correlatedNotifications": [], + "backedUpStatus": true, + "backUpObject": "xyz", + "trendIndication": "MORE_SEVERE", + "thresholdInfo": { + "observedMeasurement": "new", + "observedValue": 123 + }, + "stateChangeDefinition": { + }, + "monitoredAttributes": { + "newAtt": "new" + }, + "proposedRepairActions": "xyz", + "additionalText": "xyz", + "additionalInformation": { + "addInfo": "new" + }, + "alarmId": "1", + "alarmType": "COMMUNICATIONS_ALARM" + }, + "stndDefinedFieldsVersion": "1.0" + } + } + ] +} + diff --git a/src/test/resources/ves7_valid_eventWithStndDefinedFields.json b/src/test/resources/ves7_valid_eventWithStndDefinedFields.json deleted file mode 100644 index 5d40b9d9..00000000 --- a/src/test/resources/ves7_valid_eventWithStndDefinedFields.json +++ /dev/null @@ -1,49 +0,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": { - "header": { - "uri": "xyz", - "notificationId": "xyz", - "notificationType": "notifyNewAlarm", - "eventTime": "xyz", - "systemDN": "xyz" - }, - "body": { - "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" - } - } -} \ No newline at end of file diff --git a/src/test/resources/ves_stdnDefined_empty_namespace_invalid.json b/src/test/resources/ves_stdnDefined_empty_namespace_invalid.json index bf5f0953..a63bca17 100644 --- a/src/test/resources/ves_stdnDefined_empty_namespace_invalid.json +++ b/src/test/resources/ves_stdnDefined_empty_namespace_invalid.json @@ -15,7 +15,7 @@ "vesEventListenerVersion": "7.2" }, "stndDefinedFields": { - "schemaReference": "https://www.3gpp.org/Rel-16/TS28532_generic_fault_supervision.json#definitions/schemas/notifyNewAlarm-NotifType", + "schemaReference": "https://forge.3gpp.org/rep/sa5/data-models/blob/REL-16/OpenAPI/faultMnS.yaml#definitions/schemas/notifyNewAlarm-NotifType", "data": { "uri": "xyz", "notificationId": "xyz", diff --git a/src/test/resources/ves_stdnDefined_invalid.json b/src/test/resources/ves_stdnDefined_invalid.json new file mode 100644 index 00000000..fce300ae --- /dev/null +++ b/src/test/resources/ves_stdnDefined_invalid.json @@ -0,0 +1,54 @@ +{ + "event": { + "commonEventHeader": { + "version": "4.1", + "vesEventListenerVersion": "7.2", + "domain": "stndDefined", + "eventId": "stndDefined-gNB_Nokia000001", + "eventName": "stndDefined-gNB-Nokia-PowerLost", + "stndDefinedNamespace": "3GPP-FaultSupervision", + "startEpochMicrosec": 1413378172000000, + "lastEpochMicrosec": 1413378172000000, + "reportingEntityName": "ibcx0001vm002oam001", + "sourceName": "scfx0001vm002cap001", + "sequence": 1, + "priority": "High" + }, + "stndDefinedFields": { + "schemaReference": "https://forge.3gpp.org/rep/sa5/data-models/blob/REL-16/OpenAPI/faultMnS.yaml#components/schemas/NotifyNewAlarm", + "data": { + "href": 1, + "uri": "1", + "notificationId": 1, + "notificationType": "notifyNewAlarm", + "eventTime": "xyz", + "systemDN": "xyz", + "probableCause": 1, + "perceivedSeverity": 1, + "rootCauseIndicator": false, + "specificProblem": "xyz", + "correlatedNotifications": [], + "backedUpStatus": true, + "backUpObject": "xyz", + "trendIndication": "123", + "thresholdInfo": { + "observedMeasurement": "new", + "observedValue": 123 + }, + "stateChangeDefinition": { + }, + "monitoredAttributes": { + "newAtt": "new" + }, + "proposedRepairActions": "xyz", + "additionalText": "xyz", + "additionalInformation": { + "addInfo": "new" + }, + "alarmId": 1, + "alarmType": "COMMUNICATIONS_ALARM" + }, + "stndDefinedFieldsVersion": "1.0" + } + } +} \ No newline at end of file diff --git a/src/test/resources/ves_stdnDefined_missing_local_schema_reference.json b/src/test/resources/ves_stdnDefined_missing_local_schema_reference.json new file mode 100644 index 00000000..1ee36532 --- /dev/null +++ b/src/test/resources/ves_stdnDefined_missing_local_schema_reference.json @@ -0,0 +1,54 @@ +{ + "event": { + "commonEventHeader": { + "version": "4.1", + "vesEventListenerVersion": "7.2", + "domain": "stndDefined", + "eventId": "stndDefined-gNB_Nokia000001", + "eventName": "stndDefined-gNB-Nokia-PowerLost", + "stndDefinedNamespace": "3GPP-FaultSupervision", + "startEpochMicrosec": 1413378172000000, + "lastEpochMicrosec": 1413378172000000, + "reportingEntityName": "ibcx0001vm002oam001", + "sourceName": "scfx0001vm002cap001", + "sequence": 1, + "priority": "High" + }, + "stndDefinedFields": { + "schemaReference": "https://forge.3gpp.org/rep/sa5/data-models/blob/REL-16/OpenAPI/faultMnS.yaml", + "data": { + "href": 1, + "uri": "1", + "notificationId": 1, + "notificationType": "notifyNewAlarm", + "eventTime": "xyz", + "systemDN": "xyz", + "probableCause": 1, + "perceivedSeverity": "INDETERMINATE", + "rootCauseIndicator": false, + "specificProblem": "xyz", + "correlatedNotifications": [], + "backedUpStatus": true, + "backUpObject": "xyz", + "trendIndication": "MORE_SEVERE", + "thresholdInfo": { + "observedMeasurement": "new", + "observedValue": 123 + }, + "stateChangeDefinition": { + }, + "monitoredAttributes": { + "newAtt": "new" + }, + "proposedRepairActions": "xyz", + "additionalText": "xyz", + "additionalInformation": { + "addInfo": "new" + }, + "alarmId": "1", + "alarmType": "COMMUNICATIONS_ALARM" + }, + "stndDefinedFieldsVersion": "1.0" + } + } +} \ No newline at end of file diff --git a/src/test/resources/ves_stdnDefined_missing_namespace_invalid.json b/src/test/resources/ves_stdnDefined_missing_namespace_invalid.json index 230dc54e..7a35286d 100644 --- a/src/test/resources/ves_stdnDefined_missing_namespace_invalid.json +++ b/src/test/resources/ves_stdnDefined_missing_namespace_invalid.json @@ -14,7 +14,7 @@ "vesEventListenerVersion": "7.2" }, "stndDefinedFields": { - "schemaReference": "https://www.3gpp.org/Rel-16/TS28532_generic_fault_supervision.json#definitions/schemas/notifyNewAlarm-NotifType", + "schemaReference": "https://forge.3gpp.org/rep/sa5/data-models/blob/REL-16/OpenAPI/faultMnS.yaml#definitions/schemas/notifyNewAlarm-NotifType", "data": { "uri": "xyz", "notificationId": "xyz", diff --git a/src/test/resources/ves_stdnDefined_valid.json b/src/test/resources/ves_stdnDefined_valid.json index aa026e71..99b7ce37 100644 --- a/src/test/resources/ves_stdnDefined_valid.json +++ b/src/test/resources/ves_stdnDefined_valid.json @@ -1,45 +1,54 @@ { "event": { "commonEventHeader": { + "version": "4.1", + "vesEventListenerVersion": "7.2", "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" + "startEpochMicrosec": 1413378172000000, + "lastEpochMicrosec": 1413378172000000, + "reportingEntityName": "ibcx0001vm002oam001", + "sourceName": "scfx0001vm002cap001", + "sequence": 1, + "priority": "High" }, "stndDefinedFields": { - "schemaReference": "https://www.3gpp.org/Rel-16/TS28532_generic_fault_supervision.json#definitions/schemas/notifyNewAlarm-NotifType", + "schemaReference": "https://forge.3gpp.org/rep/sa5/data-models/blob/REL-16/OpenAPI/faultMnS.yaml#components/schemas/NotifyNewAlarm", "data": { - "uri": "xyz", - "notificationId": "xyz", + "href": 1, + "uri": "1", + "notificationId": 1, "notificationType": "notifyNewAlarm", "eventTime": "xyz", "systemDN": "xyz", - "probableCause": "xyz", - "perceivedSeverity": "Major", + "probableCause": 1, + "perceivedSeverity": "INDETERMINATE", "rootCauseIndicator": false, "specificProblem": "xyz", "correlatedNotifications": [], "backedUpStatus": true, "backUpObject": "xyz", - "trendIndication": "No change", - "thresholdInfo": {}, - "stateChangeDefinition": [], - "monitoredAttributes": [], + "trendIndication": "MORE_SEVERE", + "thresholdInfo": { + "observedMeasurement": "new", + "observedValue": 123 + }, + "stateChangeDefinition": { + }, + "monitoredAttributes": { + "newAtt": "new" + }, "proposedRepairActions": "xyz", "additionalText": "xyz", - "additionalInformation": [], - "alarmId": "xyz", - "alarmType": "Environmental Alarm" + "additionalInformation": { + "addInfo": "new" + }, + "alarmId": "1", + "alarmType": "COMMUNICATIONS_ALARM" }, "stndDefinedFieldsVersion": "1.0" } } -} +} \ No newline at end of file diff --git a/src/test/resources/ves_stdnDefined_with_empty_stndDefined_fields_data.json b/src/test/resources/ves_stdnDefined_with_empty_stndDefined_fields_data.json new file mode 100644 index 00000000..2d91c438 --- /dev/null +++ b/src/test/resources/ves_stdnDefined_with_empty_stndDefined_fields_data.json @@ -0,0 +1,24 @@ +{ + "event": { + "commonEventHeader": { + "version": "4.1", + "vesEventListenerVersion": "7.2", + "domain": "stndDefined", + "eventId": "stndDefined-gNB_Nokia000001", + "eventName": "stndDefined-gNB-Nokia-PowerLost", + "stndDefinedNamespace": "3GPP-FaultSupervision", + "startEpochMicrosec": 1413378172000000, + "lastEpochMicrosec": 1413378172000000, + "reportingEntityName": "ibcx0001vm002oam001", + "sourceName": "scfx0001vm002cap001", + "sequence": 1, + "priority": "High" + }, + "stndDefinedFields": { + "schemaReference": "https://forge.3gpp.org/rep/sa5/data-models/blob/REL-16/OpenAPI/faultMnS.yaml#components/schemas/NotifyNewAlarm", + "data": { + }, + "stndDefinedFieldsVersion": "1.0" + } + } +} diff --git a/src/test/resources/ves_stdnDefined_without_schema_reference.json b/src/test/resources/ves_stdnDefined_without_schema_reference.json new file mode 100644 index 00000000..33342c6c --- /dev/null +++ b/src/test/resources/ves_stdnDefined_without_schema_reference.json @@ -0,0 +1,22 @@ +{ + "event": { + "commonEventHeader": { + "version": "4.1", + "vesEventListenerVersion": "7.2", + "domain": "stndDefined", + "eventId": "stndDefined-gNB_Nokia000001", + "eventName": "stndDefined-gNB-Nokia-PowerLost", + "stndDefinedNamespace": "3GPP-FaultSupervision", + "startEpochMicrosec": 1413378172000000, + "lastEpochMicrosec": 1413378172000000, + "reportingEntityName": "ibcx0001vm002oam001", + "sourceName": "scfx0001vm002cap001", + "sequence": 1, + "priority": "High" + }, + "stndDefinedFields": { + "data": {}, + "stndDefinedFieldsVersion": "1.0" + } + } +} \ No newline at end of file diff --git a/src/test/resources/ves_stdnDefined_wrong_internal_file_reference.json b/src/test/resources/ves_stdnDefined_wrong_internal_file_reference.json new file mode 100644 index 00000000..9e835443 --- /dev/null +++ b/src/test/resources/ves_stdnDefined_wrong_internal_file_reference.json @@ -0,0 +1,54 @@ +{ + "event": { + "commonEventHeader": { + "version": "4.1", + "vesEventListenerVersion": "7.2", + "domain": "stndDefined", + "eventId": "stndDefined-gNB_Nokia000001", + "eventName": "stndDefined-gNB-Nokia-PowerLost", + "stndDefinedNamespace": "3GPP-FaultSupervision", + "startEpochMicrosec": 1413378172000000, + "lastEpochMicrosec": 1413378172000000, + "reportingEntityName": "ibcx0001vm002oam001", + "sourceName": "scfx0001vm002cap001", + "sequence": 1, + "priority": "High" + }, + "stndDefinedFields": { + "schemaReference": "https://forge.3gpp.org/rep/sa5/data-models/blob/REL-16/OpenAPI/faultMnS.yaml#components/schemas/dummyRef", + "data": { + "href": 1, + "uri": "1", + "notificationId": 1, + "notificationType": "notifyNewAlarm", + "eventTime": "xyz", + "systemDN": "xyz", + "probableCause": 1, + "perceivedSeverity": "INDETERMINATE", + "rootCauseIndicator": false, + "specificProblem": "xyz", + "correlatedNotifications": [], + "backedUpStatus": true, + "backUpObject": "xyz", + "trendIndication": "MORE_SEVERE", + "thresholdInfo": { + "observedMeasurement": "new", + "observedValue": 123 + }, + "stateChangeDefinition": { + }, + "monitoredAttributes": { + "newAtt": "new" + }, + "proposedRepairActions": "xyz", + "additionalText": "xyz", + "additionalInformation": { + "addInfo": "new" + }, + "alarmId": "1", + "alarmType": "COMMUNICATIONS_ALARM" + }, + "stndDefinedFieldsVersion": "1.0" + } + } +} \ No newline at end of file -- cgit 1.2.3-korg