From ab6421bcf7b480f9955b6b4376554ec9677e71ed Mon Sep 17 00:00:00 2001 From: awudzins Date: Mon, 13 Jan 2020 11:43:08 +0100 Subject: Changed EventTransformation schema to be loaded only once Issue-ID: DCAEGEN2-1774 Signed-off-by: adamwudzinski Change-Id: I50f3da2c11201a40be948ab199aaca89bbbb38db --- pom.xml | 6 + .../java/org/onap/dcae/ApplicationSettings.java | 53 ++- src/main/java/org/onap/dcae/VesApplication.java | 23 +- src/main/java/org/onap/dcae/common/Event.java | 34 -- .../org/onap/dcae/common/EventTransformation.java | 35 ++ .../java/org/onap/dcae/common/EventUpdater.java | 28 +- .../java/org/onap/dcae/common/HeaderUtils.java | 2 +- .../java/org/onap/dcae/restapi/EventValidator.java | 8 +- .../org/onap/dcae/ApplicationSettingsTest.java | 8 +- .../org/onap/dcae/restapi/EventValidatorTest.java | 29 +- .../onap/dcae/restapi/VesRestControllerTest.java | 159 +++++++++ src/test/resources/api_version_config.json | 7 + src/test/resources/eventTransform.json | 396 +++++++++++++++++++++ 13 files changed, 685 insertions(+), 103 deletions(-) delete mode 100644 src/main/java/org/onap/dcae/common/Event.java create mode 100644 src/main/java/org/onap/dcae/common/EventTransformation.java create mode 100644 src/test/java/org/onap/dcae/restapi/VesRestControllerTest.java create mode 100644 src/test/resources/api_version_config.json create mode 100644 src/test/resources/eventTransform.json diff --git a/pom.xml b/pom.xml index 5dfcaf48..4bdad84f 100644 --- a/pom.xml +++ b/pom.xml @@ -439,6 +439,12 @@ api-custom-header 1.1.4 + + org.functionaljava + functionaljava + 4.8.1 + compile + diff --git a/src/main/java/org/onap/dcae/ApplicationSettings.java b/src/main/java/org/onap/dcae/ApplicationSettings.java index 1e9ae698..8458df8d 100644 --- a/src/main/java/org/onap/dcae/ApplicationSettings.java +++ b/src/main/java/org/onap/dcae/ApplicationSettings.java @@ -3,7 +3,7 @@ * PROJECT * ================================================================================ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. - * Copyright (C) 2018 - 2019 Nokia. All rights reserved.s + * Copyright (C) 2018 - 2020 Nokia. All rights reserved.s * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,21 +21,28 @@ package org.onap.dcae; +import static java.lang.String.format; + import com.google.common.annotations.VisibleForTesting; +import com.google.common.reflect.TypeToken; +import com.google.gson.Gson; import com.networknt.schema.JsonSchema; import io.vavr.Function1; import io.vavr.collection.HashMap; -import io.vavr.collection.List; import io.vavr.collection.Map; +import java.io.FileReader; +import java.io.IOException; +import java.lang.reflect.Type; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import javax.annotation.Nullable; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.PropertiesConfiguration; +import org.onap.dcae.common.EventTransformation; import org.onap.dcae.common.configuration.AuthMethodType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.annotation.Nullable; -import java.nio.file.Path; -import java.nio.file.Paths; -import static java.lang.String.format; /** * Abstraction over application configuration. @@ -43,13 +50,16 @@ import static java.lang.String.format; */ public class ApplicationSettings { + private static final String EVENT_TRANSFORM_FILE_PATH = "./etc/eventTransform.json"; + private static final String COULD_NOT_FIND_FILE = "Couldn't find file " + EVENT_TRANSFORM_FILE_PATH; + private static final Logger log = LoggerFactory.getLogger(ApplicationSettings.class); private static final String FALLBACK_VES_VERSION = "v5"; private final String appInvocationDir; private final String configurationFileLocation; private final PropertiesConfiguration properties = new PropertiesConfiguration(); - private final JSonSchemasSupplier jSonSchemasSupplier = new JSonSchemasSupplier(); private final Map loadedJsonSchemas; + private final List eventTransformations; public ApplicationSettings(String[] args, Function1> argsParser) { this(args, argsParser, System.getProperty("user.dir")); @@ -64,7 +74,8 @@ public class ApplicationSettings { parsedArgs.filterKeys(k -> !"c".equals(k)).forEach(this::addOrUpdate); String collectorSchemaFile = properties.getString("collector.schema.file", format("{\"%s\":\"etc/CommonEventFormat_28.4.1.json\"}", FALLBACK_VES_VERSION)); - loadedJsonSchemas = jSonSchemasSupplier.loadJsonSchemas(collectorSchemaFile); + loadedJsonSchemas = new JSonSchemasSupplier().loadJsonSchemas(collectorSchemaFile); + eventTransformations = loadEventTransformations(); } public void reloadProperties() { @@ -76,22 +87,22 @@ public class ApplicationSettings { throw new ApplicationException(ex); } } + public Map validAuthorizationCredentials() { return prepareUsersMap(properties.getString("header.authlist", null)); } - public Path configurationFileLocation() { return Paths.get(configurationFileLocation); } - public boolean jsonSchemaValidationEnabled() { + public boolean eventSchemaValidationEnabled() { return properties.getInt("collector.schema.checkflag", -1) > 0; } public JsonSchema jsonSchema(String version) { return loadedJsonSchemas.get(version) - .orElse(loadedJsonSchemas.get(FALLBACK_VES_VERSION)) - .getOrElseThrow(() -> new IllegalStateException("No fallback schema present in application.")); + .orElse(loadedJsonSchemas.get(FALLBACK_VES_VERSION)) + .getOrElseThrow(() -> new IllegalStateException("No fallback schema present in application.")); } public boolean isVersionSupported(String version){ @@ -159,6 +170,10 @@ public class ApplicationSettings { } } + public List getEventTransformations() { + return eventTransformations; + } + private void loadPropertiesFromFile() { try { properties.load(configurationFileLocation); @@ -182,7 +197,7 @@ public class ApplicationSettings { private Map prepareUsersMap(@Nullable String allowedUsers) { return allowedUsers == null ? HashMap.empty() - : List.of(allowedUsers.split("\\|")) + : io.vavr.collection.List.of(allowedUsers.split("\\|")) .map(t->t.split(",")) .toMap(t-> t[0].trim(), t -> t[1].trim()); } @@ -205,6 +220,18 @@ public class ApplicationSettings { return filePath; } + private List loadEventTransformations() { + Type EVENT_TRANSFORM_LIST_TYPE = new TypeToken>() {}.getType(); + + try (FileReader fr = new FileReader(EVENT_TRANSFORM_FILE_PATH)) { + log.info("parse " + EVENT_TRANSFORM_FILE_PATH + " file"); + return new Gson().fromJson(fr, EVENT_TRANSFORM_LIST_TYPE); + } catch (IOException e) { + log.error(COULD_NOT_FIND_FILE, e); + throw new ApplicationException(COULD_NOT_FIND_FILE, e); + } + } + @VisibleForTesting String getStringDirectly(String key) { return properties.getString(key); diff --git a/src/main/java/org/onap/dcae/VesApplication.java b/src/main/java/org/onap/dcae/VesApplication.java index e3340820..bc5b1a8f 100644 --- a/src/main/java/org/onap/dcae/VesApplication.java +++ b/src/main/java/org/onap/dcae/VesApplication.java @@ -3,6 +3,7 @@ * PROJECT * ================================================================================ * Copyright (C) 2017-2018 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. @@ -47,7 +48,7 @@ public class VesApplication { private static final Logger incomingRequestsLogger = LoggerFactory.getLogger("org.onap.dcae.common.input"); private static final Logger oplog = LoggerFactory.getLogger("org.onap.dcae.common.output"); private static final Logger errorLog = LoggerFactory.getLogger("org.onap.dcae.common.error"); - private static ApplicationSettings properties; + private static ApplicationSettings applicationSettings; private static ConfigurableApplicationContext context; private static ConfigLoader configLoader; private static ScheduledThreadPoolExecutor scheduledThreadPoolExecutor; @@ -57,7 +58,7 @@ public class VesApplication { public static void main(String[] args) { app = new SpringApplication(VesApplication.class); - properties = new ApplicationSettings(args, CLIUtils::processCmdLine); + applicationSettings = new ApplicationSettings(args, CLIUtils::processCmdLine); scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(1); init(); app.setAddCommandLineProperties(true); @@ -68,7 +69,7 @@ public class VesApplication { public static void restartApplication() { Thread thread = new Thread(() -> { context.close(); - properties.reloadProperties(); + applicationSettings.reloadProperties(); scheduleFeatures.cancel(true); init(); context = SpringApplication.run(VesApplication.class); @@ -89,32 +90,32 @@ public class VesApplication { private static void createSchedulePoolExecutor() { scheduleFeatures = scheduledThreadPoolExecutor.scheduleAtFixedRate(configLoader::updateConfig, - properties.configurationUpdateFrequency(), - properties.configurationUpdateFrequency(), + applicationSettings.configurationUpdateFrequency(), + applicationSettings.configurationUpdateFrequency(), TimeUnit.MINUTES); } private static void createConfigLoader() { configLoader = ConfigLoader.create(getEventPublisher()::reconfigure, - Paths.get(properties.dMaaPConfigurationFileLocation()), - properties.configurationFileLocation()); + Paths.get(applicationSettings.dMaaPConfigurationFileLocation()), + applicationSettings.configurationFileLocation()); } private static EventPublisher getEventPublisher() { return EventPublisher.createPublisher(oplog, DMaaPConfigurationParser - .parseToDomainMapping(Paths.get(properties.dMaaPConfigurationFileLocation())).get()); + .parseToDomainMapping(Paths.get(applicationSettings.dMaaPConfigurationFileLocation())).get()); } private static Map getDmapConfig() { return DMaaPConfigurationParser - .parseToDomainMapping(Paths.get(properties.dMaaPConfigurationFileLocation())).get(); + .parseToDomainMapping(Paths.get(applicationSettings.dMaaPConfigurationFileLocation())).get(); } @Bean @Lazy public ApplicationSettings applicationSettings() { - return properties; + return applicationSettings; } @Bean @@ -132,7 +133,7 @@ public class VesApplication { @Bean @Qualifier("eventSender") public EventSender eventSender() { - return new EventSender(eventPublisher,properties); + return new EventSender(eventPublisher, applicationSettings); } } diff --git a/src/main/java/org/onap/dcae/common/Event.java b/src/main/java/org/onap/dcae/common/Event.java deleted file mode 100644 index 1fa8179e..00000000 --- a/src/main/java/org/onap/dcae/common/Event.java +++ /dev/null @@ -1,34 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * PROJECT - * ================================================================================ - * Copyright (C) 2017 AT&T Intellectual Property. 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; - -import com.google.gson.JsonObject; - -import java.util.List; - -class Event { - final JsonObject filter; - final List processors; - - Event(JsonObject filter, List processors) { - this.filter = filter; - this.processors = processors; - } -} diff --git a/src/main/java/org/onap/dcae/common/EventTransformation.java b/src/main/java/org/onap/dcae/common/EventTransformation.java new file mode 100644 index 00000000..f85fd2de --- /dev/null +++ b/src/main/java/org/onap/dcae/common/EventTransformation.java @@ -0,0 +1,35 @@ +/*- + * ============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; + +import com.google.gson.JsonObject; + +import java.util.List; + +public class EventTransformation { + final JsonObject filter; + final List processors; + + EventTransformation(JsonObject filter, List processors) { + this.filter = filter; + this.processors = processors; + } +} diff --git a/src/main/java/org/onap/dcae/common/EventUpdater.java b/src/main/java/org/onap/dcae/common/EventUpdater.java index 1caa4f18..1469d47e 100644 --- a/src/main/java/org/onap/dcae/common/EventUpdater.java +++ b/src/main/java/org/onap/dcae/common/EventUpdater.java @@ -3,7 +3,7 @@ * PROJECT * ================================================================================ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. - * Copyright (C) 2019 Nokia. All rights reserved.s + * Copyright (C) 2020 Nokia. All rights reserved.s * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,18 +21,12 @@ package org.onap.dcae.common; -import com.google.common.reflect.TypeToken; -import com.google.gson.Gson; -import java.io.FileReader; -import java.io.IOException; -import java.lang.reflect.Type; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import java.util.UUID; import org.json.JSONArray; import org.json.JSONObject; -import org.onap.dcae.ApplicationException; import org.onap.dcae.ApplicationSettings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,12 +37,9 @@ public class EventUpdater { private static final String EVENT = "event"; private static final String VES_UNIQUE_ID = "VESuniqueId"; private static final String VES_VERSION = "VESversion"; - private static final String COULD_NOT_FIND_FILE = "Couldn't find file ./etc/eventTransform.json"; - private static final Type EVENT_LIST_TYPE = new TypeToken>() {}.getType(); private static final Logger log = LoggerFactory.getLogger(EventSender.class); private static final String EVENT_LITERAL = "event"; private static final String COMMON_EVENT_HEADER = "commonEventHeader"; - private static final String EVENT_TRANSFORM = "./etc/eventTransform.json"; private ApplicationSettings settings; private final SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, MM dd yyyy hh:mm:ss z"); @@ -87,18 +78,15 @@ public class EventUpdater { private JSONObject overrideEvent(JSONObject event) { JSONObject jsonObject = addCurrentTimeToEvent(event); + if (settings.eventTransformingEnabled()) { - try (FileReader fr = new FileReader(EVENT_TRANSFORM)) { - log.info("parse " + EVENT_TRANSFORM + " file"); - List events = new Gson().fromJson(fr, EVENT_LIST_TYPE); - parseEventsJson(events, new ConfigProcessorAdapter(new ConfigProcessors(jsonObject))); - } catch (IOException e) { - log.error(COULD_NOT_FIND_FILE, e); - throw new ApplicationException(COULD_NOT_FIND_FILE, e); - } + List eventTransformations = settings.getEventTransformations(); + applyMatchingTransformations(eventTransformations, new ConfigProcessorAdapter(new ConfigProcessors(jsonObject))); } + if (jsonObject.has(VES_VERSION)) jsonObject.remove(VES_VERSION); + log.debug("Modified event:" + jsonObject); return jsonObject; } @@ -112,8 +100,8 @@ public class EventUpdater { return event; } - private void parseEventsJson(List eventsTransform, ConfigProcessorAdapter configProcessorAdapter) { - for (Event eventTransform : eventsTransform) { + private void applyMatchingTransformations(List eventsTransforms, ConfigProcessorAdapter configProcessorAdapter) { + for (EventTransformation eventTransform : eventsTransforms) { JSONObject filterObj = new JSONObject(eventTransform.filter.toString()); if (configProcessorAdapter.isFilterMet(filterObj)) { callProcessorsMethod(configProcessorAdapter, eventTransform.processors); diff --git a/src/main/java/org/onap/dcae/common/HeaderUtils.java b/src/main/java/org/onap/dcae/common/HeaderUtils.java index a5703091..c046fb4c 100644 --- a/src/main/java/org/onap/dcae/common/HeaderUtils.java +++ b/src/main/java/org/onap/dcae/common/HeaderUtils.java @@ -33,7 +33,7 @@ import org.springframework.stereotype.Component; * @author nil */ @Component -public final class HeaderUtils { +public class HeaderUtils { public String getApiVerFilePath(String fileName) { return Objects.requireNonNull(ClassLoader.getSystemClassLoader().getResource(fileName)) diff --git a/src/main/java/org/onap/dcae/restapi/EventValidator.java b/src/main/java/org/onap/dcae/restapi/EventValidator.java index 009247c0..3261c3b3 100644 --- a/src/main/java/org/onap/dcae/restapi/EventValidator.java +++ b/src/main/java/org/onap/dcae/restapi/EventValidator.java @@ -3,7 +3,7 @@ * PROJECT * ================================================================================ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. - * Copyright (C) 2019 Nokia. All rights reserved.s + * Copyright (C) 2020 Nokia. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,12 +20,10 @@ */ package org.onap.dcae.restapi; +import java.util.Optional; import org.json.JSONObject; import org.onap.dcae.ApplicationSettings; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.http.ResponseEntity; -import java.util.Optional; public class EventValidator { private final SchemaValidator schemaValidator = new SchemaValidator(); @@ -36,7 +34,7 @@ public class EventValidator { } public Optional> validate(JSONObject jsonObject, String type, String version){ - if (applicationSettings.jsonSchemaValidationEnabled()) { + if (applicationSettings.eventSchemaValidationEnabled()) { if (jsonObject.has(type)) { if (!schemaValidator.conformsToSchema(jsonObject, applicationSettings.jsonSchema(version))) { return errorResponse(ApiException.SCHEMA_VALIDATION_FAILED); diff --git a/src/test/java/org/onap/dcae/ApplicationSettingsTest.java b/src/test/java/org/onap/dcae/ApplicationSettingsTest.java index c4ba586e..3d8a1a1e 100644 --- a/src/test/java/org/onap/dcae/ApplicationSettingsTest.java +++ b/src/test/java/org/onap/dcae/ApplicationSettingsTest.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * org.onap.dcaegen2.collectors.ves * ================================================================================ - * Copyright (C) 2018 - 2019 Nokia. All rights reserved. + * Copyright (C) 2018 - 2020 Nokia. All rights reserved. * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -244,7 +244,7 @@ public class ApplicationSettingsTest { public void shouldTellIfSchemaValidationIsEnabled() throws IOException { // when boolean jsonSchemaValidationEnabled = fromTemporaryConfiguration("collector.schema.checkflag=1") - .jsonSchemaValidationEnabled(); + .eventSchemaValidationEnabled(); // then assertTrue(jsonSchemaValidationEnabled); @@ -253,7 +253,7 @@ public class ApplicationSettingsTest { @Test public void shouldByDefaultSchemaValidationBeDisabled() throws IOException { // when - boolean jsonSchemaValidationEnabled = fromTemporaryConfiguration().jsonSchemaValidationEnabled(); + boolean jsonSchemaValidationEnabled = fromTemporaryConfiguration().eventSchemaValidationEnabled(); // then assertFalse(jsonSchemaValidationEnabled); @@ -422,4 +422,4 @@ public class ApplicationSettingsTest { private String sanitizePath(String path) { return Paths.get(path).toString(); } -} \ 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 index 4ac3c487..53595100 100644 --- a/src/test/java/org/onap/dcae/restapi/EventValidatorTest.java +++ b/src/test/java/org/onap/dcae/restapi/EventValidatorTest.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * org.onap.dcaegen2.collectors.ves * ================================================================================ - * Copyright (C) 2019 Nokia. All rights reserved. + * Copyright (C) 2020 Nokia. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,8 +20,13 @@ package org.onap.dcae.restapi; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + import com.networknt.schema.JsonSchema; import com.networknt.schema.JsonSchemaFactory; +import java.util.Optional; import org.json.JSONObject; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -32,13 +37,6 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.onap.dcae.ApplicationSettings; import org.springframework.http.ResponseEntity; -import java.io.IOException; -import java.util.Optional; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; - @ExtendWith(MockitoExtension.class) public class EventValidatorTest { private static final String DUMMY_SCHEMA_VERSION = "v5"; @@ -60,7 +58,7 @@ public class EventValidatorTest { @Test public void shouldReturnEmptyOptionalOnJsonSchemaValidationDisabled() { //given - when(settings.jsonSchemaValidationEnabled()).thenReturn(false); + when(settings.eventSchemaValidationEnabled()).thenReturn(false); //when Optional> result = sut.validate(jsonObject, DUMMY_TYPE, DUMMY_SCHEMA_VERSION); @@ -73,7 +71,7 @@ public class EventValidatorTest { @Test public void shouldReturnInvalidJsonErrorOnWrongType() { //given - when(settings.jsonSchemaValidationEnabled()).thenReturn(true); + when(settings.eventSchemaValidationEnabled()).thenReturn(true); //when Optional> result = sut.validate(jsonObject, "wrongType", DUMMY_SCHEMA_VERSION); @@ -83,11 +81,11 @@ public class EventValidatorTest { } @Test - public void shouldReturnSchemaValidationFailedErrorOnInvalidJsonObjectSchema() throws IOException { + public void shouldReturnSchemaValidationFailedErrorOnInvalidJsonObjectSchema() { //given String schemaRejectingEverything = "{\"not\":{}}"; mockJsonSchema(schemaRejectingEverything); - when(settings.jsonSchemaValidationEnabled()).thenReturn(true); + when(settings.eventSchemaValidationEnabled()).thenReturn(true); //when Optional> result = sut.validate(jsonObject, DUMMY_TYPE, DUMMY_SCHEMA_VERSION); @@ -97,11 +95,11 @@ public class EventValidatorTest { } @Test - public void shouldReturnEmptyOptionalOnValidJsonObjectSchema() throws IOException { + public void shouldReturnEmptyOptionalOnValidJsonObjectSchema() { //given String schemaAcceptingEverything = "{}"; mockJsonSchema(schemaAcceptingEverything); - when(settings.jsonSchemaValidationEnabled()).thenReturn(true); + when(settings.eventSchemaValidationEnabled()).thenReturn(true); //when Optional> result = sut.validate(jsonObject, DUMMY_TYPE, DUMMY_SCHEMA_VERSION); @@ -110,6 +108,7 @@ public class EventValidatorTest { assertEquals(Optional.empty(), result); } + private void mockJsonSchema(String jsonSchemaContent) { JsonSchemaFactory factory = JsonSchemaFactory.getInstance(); @@ -121,4 +120,4 @@ public class EventValidatorTest { return Optional.of(ResponseEntity.status(schemaValidationFailed.httpStatusCode) .body(schemaValidationFailed.toJSON().toString())); } -} \ No newline at end of file +} diff --git a/src/test/java/org/onap/dcae/restapi/VesRestControllerTest.java b/src/test/java/org/onap/dcae/restapi/VesRestControllerTest.java new file mode 100644 index 00000000..444e28e6 --- /dev/null +++ b/src/test/java/org/onap/dcae/restapi/VesRestControllerTest.java @@ -0,0 +1,159 @@ +/* + * ============LICENSE_START======================================================= + * PROJECT + * ================================================================================ + * Copyright (C) 2020 Nokia. All rights reserved.s + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.dcae.restapi; + +import com.google.common.reflect.TypeToken; +import com.google.gson.Gson; +import org.jetbrains.annotations.NotNull; +import org.json.JSONArray; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.onap.dcae.ApplicationSettings; +import org.onap.dcae.common.EventSender; +import org.onap.dcae.common.EventTransformation; +import org.onap.dcae.common.HeaderUtils; +import org.slf4j.Logger; +import org.springframework.http.ResponseEntity; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import java.io.FileReader; +import java.io.IOException; +import java.lang.reflect.Type; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class VesRestControllerTest { + + private static final String EVENT_TRANSFORM_FILE_PATH = "/eventTransform.json"; + + @InjectMocks + VesRestController vesRestController; + + @Mock + ApplicationSettings applicationSettings; + + @Mock + Logger logger; + + @Mock + EventSender eventSender; + + @Mock + HeaderUtils headerUtils; + + @Test + public void shouldReportThatApiVersionIsNotSupported() { + // given + when(applicationSettings.isVersionSupported("v20")).thenReturn(false); + MockHttpServletRequest request = givenMockHttpServletRequest(); + + // when + final ResponseEntity event = vesRestController.event("", "v20", request); + + // then + assertThat(event.getStatusCodeValue()).isEqualTo(400); + assertThat(event.getBody()).isEqualTo("API version v20 is not supported"); + verify(eventSender, never()).send(any(JSONArray.class)); + } + + @Test + public void shouldTransformEventAccordingToEventTransformFile() throws IOException { + //given + configureEventTransformations(); + configureHeadersForEventListener(); + + MockHttpServletRequest request = givenMockHttpServletRequest(); + + String validEvent = new String( + Files.readAllBytes(Paths.get(this.getClass().getResource("/ves7_valid.json").getPath())) + ); + + //when + final ResponseEntity response = vesRestController.event(validEvent, "v7", request); + + //then + assertThat(response.getStatusCodeValue()).isEqualTo(202); + assertThat(response.getBody()).isEqualTo("Accepted"); + verifyThatTransformedEventWasSend(eventSender, validEvent); + } + + private void configureEventTransformations() throws IOException { + final List eventTransformations = loadEventTransformations(); + when(applicationSettings.isVersionSupported("v7")).thenReturn(true); + when(applicationSettings.eventTransformingEnabled()).thenReturn(true); + when(applicationSettings.getEventTransformations()).thenReturn(eventTransformations); + } + + private void configureHeadersForEventListener() { + when(headerUtils.getRestApiIdentify(anyString())).thenReturn("eventListener"); + when(headerUtils.getApiVerFilePath(anyString())).thenReturn( + this.getClass().getResource("/api_version_config.json").getPath() + ); + } + + private void verifyThatTransformedEventWasSend(EventSender eventSender, String eventBeforeTransformation) { + // event before transformation + assertThat(eventBeforeTransformation).contains("\"version\": \"4.0.1\""); + assertThat(eventBeforeTransformation).contains("\"faultFieldsVersion\": \"4.0\""); + + ArgumentCaptor argument = ArgumentCaptor.forClass(JSONArray.class); + verify(eventSender).send(argument.capture()); + + final String transformedEvent = argument.getValue().toString(); + + // event after transformation + assertThat(transformedEvent).contains("\"priority\":\"High\",\"version\":3,"); + assertThat(transformedEvent).contains(",\"faultFieldsVersion\":3,\"specificProblem"); + } + + @NotNull + private MockHttpServletRequest givenMockHttpServletRequest() { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setContentType("application/json"); + + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request)); + return request; + } + + private List loadEventTransformations() throws IOException { + Type EVENT_TRANSFORM_LIST_TYPE = new TypeToken>() { + }.getType(); + + try (FileReader fr = new FileReader(this.getClass().getResource(EVENT_TRANSFORM_FILE_PATH).getPath())) { + return new Gson().fromJson(fr, EVENT_TRANSFORM_LIST_TYPE); + } + } +} diff --git a/src/test/resources/api_version_config.json b/src/test/resources/api_version_config.json new file mode 100644 index 00000000..23f585f9 --- /dev/null +++ b/src/test/resources/api_version_config.json @@ -0,0 +1,7 @@ +{ + "apiVersion": + { + "eventListener": ["4.7.2","5.4.1","7.0.1"], + "eventListener_eventBatch": ["4.7.2","5.4.1","7.0.1"] + } +} diff --git a/src/test/resources/eventTransform.json b/src/test/resources/eventTransform.json new file mode 100644 index 00000000..ab37a6eb --- /dev/null +++ b/src/test/resources/eventTransform.json @@ -0,0 +1,396 @@ +[ + { + "filter": { + "event.commonEventHeader.domain": "heartbeat", + "VESversion": "v7" + }, + "processors": [ + { + "functionName": "addAttribute", + "args": { + "field": "event.commonEventHeader.version", + "value": "3.0", + "fieldType": "number" + } + }, + { + "functionName": "addAttribute", + "args": { + "field": "event.heartbeatFields.heartbeatFieldsVersion", + "value": "2.0", + "fieldType": "number" + } + }, + { + "functionName": "map", + "args": { + "field": "event.heartbeatFields.additionalFields", + "mapType": "HashmapToNameValueArray" + } + } + ] + }, + { + "filter": { + "event.commonEventHeader.domain": "fault", + "VESversion": "v7" + }, + "processors": [ + { + "functionName": "addAttribute", + "args": { + "field": "event.commonEventHeader.version", + "value": "3.0", + "fieldType": "number" + } + }, + { + "functionName": "addAttribute", + "args": { + "field": "event.faultFields.faultFieldsVersion", + "value": "3.0", + "fieldType": "number" + } + }, + { + "functionName": "map", + "args": { + "field": "event.faultFields.alarmAdditionalInformation", + "mapType": "HashmapToNameValueArray" + } + } + ] + }, + { + "filter": { + "event.commonEventHeader.domain": "thresholdCrossingAlert", + "VESversion": "v7" + }, + "processors": [ + { + "functionName": "addAttribute", + "args": { + "field": "event.commonEventHeader.version", + "value": "3.0", + "fieldType": "number" + } + }, + { + "functionName": "addAttribute", + "args": { + "field": "event.thresholdCrossingFields.thresholdCrossingFieldsVersion", + "value": "3.0", + "fieldType": "number" + } + }, + { + "functionName": "map", + "args": { + "field": "event.thresholdCrossingFields.additionalFields", + "mapType": "HashmapToNameValueArray" + } + } + ] + }, + { + "filter": { + "event.commonEventHeader.domain": "measurement", + "VESversion": "v7" + }, + "processors": [ + { + "functionName": "addAttribute", + "args": { + "field": "event.commonEventHeader.version", + "value": "3.0", + "fieldType": "number" + } + }, + { + "functionName": "removeAttribute", + "args": { + "field": "event.measurementFields.measurementFieldsVersion" + } + }, + { + "functionName": "addAttribute", + "args": { + "field": "event.measurementFields.measurementsForVfScalingVersion", + "value": "3.0", + "fieldType": "number" + } + }, + { + "functionName": "map", + "args": { + "field": "event.measurementFields.vNicPerformanceArray[]", + "oldField": "event.measurementFields.nicPerformanceArray[]", + "attrMap": { + "nicIdentifier": "vNicIdentifier" + } + } + }, + { + "functionName": "map", + "args": { + "field": "event.measurementFields.additionalFields", + "oldField": "event.measurementFields.additionalFields", + "mapType": "hashmapToNameValueArray" + } + }, + { + "functionName": "map", + "args": { + "field": "event.measurementsForVfScalingFields", + "oldField": "event.measurementFields", + "mapType": "renameObject" + } + }, + { + "functionName": "addAttribute", + "args": { + "field": "event.commonEventHeader.domain", + "value": "measurementsForVfScaling" + } + } + ] + }, + { + "filter": { + "event.commonEventHeader.domain": "heartbeat", + "VESversion": "v4" + }, + "processors": [ + { + "functionName": "concatenateValue", + "args": { + "field": "event.commonEventHeader.eventName", + "concatenate": [ + "$event.commonEventHeader.domain", + "$event.commonEventHeader.eventType", + "$event.faultFields.alarmCondition" + ], + "delimiter": "_" + } + }, + { + "functionName": "addAttribute", + "args": { + "field": "event.heartbeatFields.heartbeatFieldsVersion", + "value": "1.0", + "fieldType": "number" + } + }, + { + "functionName": "addAttribute", + "args": { + "field": "event.heartbeatFields.heartbeatInterval", + "value": "0", + "fieldType": "integer" + } + }, + { + "functionName": "map", + "args": { + "field": "event.commonEventHeader.nfNamingCode", + "oldField": "event.commonEventHeader.functionalRole" + } + } + ] + }, + { + "filter": { + "event.commonEventHeader.domain": "fault", + "VESversion": "v4" + }, + "processors": [ + { + "functionName": "concatenateValue", + "args": { + "field": "event.commonEventHeader.eventName", + "concatenate": [ + "$event.commonEventHeader.domain", + "$event.commonEventHeader.eventType", + "$event.faultFields.alarmCondition" + ], + "delimiter": "_" + } + }, + { + "functionName": "addAttribute", + "args": { + "field": "event.faultFields.faultFieldsVersion", + "value": "2.0", + "fieldType": "number" + } + }, + { + "functionName": "addAttribute", + "args": { + "field": "event.commonEventHeader.version", + "value": "3.0", + "fieldType": "number" + } + }, + { + "functionName": "map", + "args": { + "field": "event.commonEventHeader.nfNamingCode", + "oldField": "event.commonEventHeader.functionalRole" + } + } + ] + }, + { + "filter": { + "event.commonEventHeader.domain": "thresholdCrossingAlert", + "VESversion": "v4" + }, + "processors": [ + { + "functionName": "concatenateValue", + "args": { + "field": "event.commonEventHeader.eventName", + "concatenate": [ + "$event.commonEventHeader.domain", + "$event.commonEventHeader.elementType", + "$event.faultFields.alertDescription" + ], + "delimiter": "_" + } + }, + { + "functionName": "map", + "args": { + "field": "event.commonEventHeader.nfNamingCode", + "oldField": "event.commonEventHeader.functionalRole" + } + } + ] + }, + { + "filter": { + "event.commonEventHeader.domain": "measurementsForVfScaling", + "VESversion": "v4", + "not": { + "event.commonEventHeader.reportingEntityName": "matches:.*ircc|irpr.*" + } + }, + "processors": [ + { + "functionName": "concatenateValue", + "args": { + "field": "event.commonEventHeader.eventName", + "concatenate": [ + "$event.commonEventHeader.domain", + "$event.commonEventHeader.eventType", + "$event.faultFields.alarmCondition" + ], + "delimiter": "_" + } + }, + { + "functionName": "addAttribute", + "args": { + "field": "event.measurementsForVfScalingFields.measurementsForVfScalingVersion", + "value": "2.0", + "fieldType": "number" + } + }, + { + "functionName": "map", + "args": { + "field": "event.measurementsForVfScalingFields.additionalMeasurements[].arrayOfFields[]", + "oldField": "event.measurementsForVfScalingFields.additionalMeasurements[].measurements[]" + } + }, + { + "functionName": "map", + "args": { + "oldField": "event.measurementsForVfScalingFields.aggregateCpuUsage", + "field": "event.measurementsForVfScalingFields.cpuUsageArray[0].percentUsage" + } + }, + { + "functionName": "addAttribute", + "args": { + "field": "event.measurementsForVfScalingFields.cpuUsageArray[0].cpuIdentifier", + "value": "$event.commonEventHeader.sourceName" + } + }, + { + "functionName": "map", + "args": { + "field": "event.measurementsForVfScalingFields.memoryUsageArray[0].memoryConfigured", + "oldField": "event.measurementsForVfScalingFields.memoryConfigured", + "operation": "convertMBtoKB" + } + }, + { + "functionName": "map", + "args": { + "field": "event.measurementsForVfScalingFields.memoryUsageArray[0].memoryUsed", + "oldField": "event.measurementsForVfScalingFields.memoryUsed", + "operation": "convertMBtoKB" + } + }, + { + "functionName": "addAttribute", + "args": { + "field": "event.measurementsForVfScalingFields.memoryUsageArray[0].vmIdentifier", + "value": "$event.commonEventHeader.sourceName" + } + }, + { + "functionName": "subtractValue", + "args": { + "field": "event.measurementsForVfScalingFields.memoryUsageArray[0].memoryFree", + "subtract": [ + "$event.measurementsForVfScalingFields.memoryUsageArray[0].memoryConfigured", + "$event.measurementsForVfScalingFields.memoryUsageArray[0].memoryUsed" + ] + } + }, + { + "functionName": "map", + "args": { + "field": "event.measurementsForVfScalingFields.vNicPerformanceArray[]", + "oldField": "event.measurementsForVfScalingFields.vNicUsageArray[]", + "attrMap": { + "broadcastPacketsIn": "receivedBroadcastPacketsAccumulated", + "multicastPacketsIn": "receivedMulticastPacketsAccumulated", + "bytesIn": "receivedOctetsAccumulated", + "packetsIn": "receivedTotalPacketsAccumulated", + "unicastPacketsIn": "receivedUnicastPacketsAccumulated", + "broadcastPacketsOut": "transmittedBroadcastPacketsAccumulated", + "multicastPacketsOut": "transmittedMulticastPacketsAccumulated", + "bytesOut": "transmittedOctetsAccumulated", + "packetsOut": "transmittedTotalPacketsAccumulated", + "unicastPacketsOut": "transmittedUnicastPacketsAccumulated" + } + } + }, + { + "functionName": "map", + "args": { + "field": "event.measurementsForVfScalingFields.vNicPerformanceArray[]", + "oldField": "event.measurementsForVfScalingFields.errors", + "attrMap": { + "receiveDiscards": "receivedDiscardedPacketsAccumulated", + "receiveErrors": "receivedErrorPacketsAccumulated", + "transmitDiscards": "transmittedDiscardedPacketsAccumulated", + "transmitErrors": "transmittedErrorPacketsAccumulated" + } + } + }, + { + "functionName": "addAttribute", + "args": { + "field": "event.measurementsForVfScalingFields.vNicPerformanceArray[0].valuesAreSuspect", + "value": "false" + } + } + ] + } +] + -- cgit 1.2.3-korg