From 85bedddf8340cbbe57f941a919a980540aeeef59 Mon Sep 17 00:00:00 2001 From: Bartosz Gardziejewski Date: Thu, 9 Apr 2020 11:49:18 +0200 Subject: Add variables to PNF simulator events and update logging Issue-ID: INT-1517 Signed-off-by: Bartosz Gardziejewski Change-Id: I48931c0b4c68cd4de548cfa7dbaa950a24d13545 --- pnfsimulator/README.md | 115 +++++++++++++- .../integration/VariablesReplacement.java | 86 ++++++++++ .../integration/suites/DockerBasedTestsSuite.java | 3 +- .../test/resources/templates/cmNotification.json | 32 ++++ pnfsimulator/pom.xml | 7 +- .../pnfsimulator/rest/model/SimulatorRequest.java | 4 + .../pnfsimulator/simulator/SimulatorService.java | 20 ++- .../simulator/TemplateVariablesReplacer.java | 50 ++++++ .../simulator/client/HttpClientAdapterImpl.java | 29 ++-- .../pnfsimulator/simulator/scheduler/EventJob.java | 2 + pnfsimulator/src/main/resources/logback.xml | 71 ++++----- .../pnfsimulator/rest/SimulatorControllerTest.java | 2 +- .../simulator/SimulatorServiceTest.java | 47 +++++- .../simulator/TemplateVariablesReplacerTest.java | 174 +++++++++++++++++++++ pnfsimulator/src/test/resources/logback-test.xml | 22 +-- .../simulator/validExampleMeasurementEvent.json | 7 +- pnfsimulator/templates/cmNotification.json | 32 ++++ pom.xml | 7 + 18 files changed, 612 insertions(+), 98 deletions(-) create mode 100644 pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/VariablesReplacement.java create mode 100644 pnfsimulator/integration/src/test/resources/templates/cmNotification.json create mode 100644 pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/TemplateVariablesReplacer.java create mode 100644 pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/TemplateVariablesReplacerTest.java create mode 100644 pnfsimulator/templates/cmNotification.json diff --git a/pnfsimulator/README.md b/pnfsimulator/README.md index 7cf8ba7..23cc76b 100644 --- a/pnfsimulator/README.md +++ b/pnfsimulator/README.md @@ -5,7 +5,7 @@ Simulator that generates VES events related to PNF PNP integration. ### Setting up Preferred way to start simulator is to use `docker-compose up -d` command. All required docker images will be downloaded from ONAP Nexus, however there is possibility to build those -images locally. It can be achieve by invoking `mvn clean package docker:build` from top directory. +images locally. It can be achieve by invoking `mvn clean install -P docker` from top directory. ### API Simulator provides REST endpoints which can be used to trigger sending events to VES. @@ -22,7 +22,8 @@ Parameters: repeatInterval - time (in seconds) between events vesServerUrl - valid path to VES Collector templateName - name of template file (check *Templates* section) - patch - part of event which will be merged into template + patch - part of event which will be merged into template + variables - correct json containing variables to merge with patched template Sample Request: @@ -42,7 +43,13 @@ Sample Request: "version": 3.0 } } - } + }, + "variables": { + "dn":"Abcd", + "anyObject": { + "key": "value" + } + } } *One-time event sending* @@ -263,6 +270,103 @@ Corresponding result of keyword substitution (event that will be sent): } } +### In place variables support +Simulator supports dynamic keywords e.g. #dN to automatically substitute selected phrases in defined json schema. +Keywords have to be specified as separated json values, so no mixing keywords inside textual fields are acceptable. Current implementation +supports placing variables in json templates as well as in patches latter sent as part of the requests. + +####Example: + +Request: +```json +{ + "simulatorParams": { + "repeatCount": 1, + "repeatInterval": 1, + "vesServerUrl": "http://ves:5123" + }, + "templateName": "cmNotification.json", + "patch": {}, + "variables": { + "dN": "NRNB=5, NRCEL=1234", + "attributeList": { + "threshXHighQ": "50", + "threshXHighP": "52" + } + } +} +``` + +cmNotification.json template is installed automatically after startup of the simulator but can be found also in repository in 'templates' folder: +```json +{ + "event": { + "otherFields": { + "otherFieldsVersion": "3.0", + "jsonObjects": [ + { + "objectName": "CustomNotification", + "objectInstances": [ + { + "objectInstance": { + "cm3gppNotifyFields": { + "dN": "#dN", + "notificationType": "notifyMOIAttributeValueChange", + "notificationId": "notificationID123121312323", + "sourceIndicator": "sONOperation", + "eventTime": "#Timestamp", + "systemDN": "NRNB=5", + "attributeList": "#attributeList", + "correlatedNotifications": { + "notificationID-notifyMOIAttributeValueChange": "sONOperation" + }, + "additionalText": "sometext", + "cm3gppNotifyFieldsVersion": "1.0" + } + } + } + ] + } + ] + } + } +} +``` + +Expected output of such request (body of an event being send to a ves) should be as follows: +```json +{ + "event": { + "otherFields": { + "otherFieldsVersion": "3.0", + "jsonObjects": [{ + "objectName": "CustomNotification", + "objectInstances": [{ + "objectInstance": { + "cm3gppNotifyFields": { + "dN": "NRNB=5, NRCEL=1234", + "notificationType": "notifyMOIAttributeValueChange", + "notificationId": "notificationID123121312323", + "sourceIndicator": "sONOperation", + "eventTime": "1571306716", + "systemDN": "NRNB=5", + "attributeList": { + "threshXHighQ": "50", + "threshXHighP": "52" + }, + "correlatedNotifications": { + "notificationID-notifyMOIAttributeValueChange": "sONOperation" + }, + "additionalText": "sometext", + "cm3gppNotifyFieldsVersion": "1.0" + } + } + }] + }] + } + } +} +``` ### Logging Every start of simulator will generate new logs that can be found in docker pnf-simualtor container under path: @@ -292,7 +396,7 @@ Integration tests are located in folder 'integration'. Tests are using docker-co This docker-compose has pnfsimulator image set on nexus3.onap.org:10003/onap/pnf-simulator:1.0.1-SNAPSHOT. To test your local changes before running integration tests please build project using: - 'mvn clean package docker:build' + 'mvn clean install -P docerk' then go to 'integration' folder and run: @@ -318,6 +422,9 @@ Warning: according to VES implementation which uses certificate with Common Name 1. ```keytool -import -file rootCA.crt -alias firstCA -keystore trustStore``` 2. Copy truststore to ```/app/store/``` +#### Testing keystore with real/mocked ves server +```curl --cacert rootCA.crt --cert client.crt --key client.key https://VES_SECURED_URL -d "{}" -X POST -H "Content-type: application/json" -kv``` + #### How to refresh configuration of app Depends your needs, you are able to change client certificate, replace trustStore to accept new server certificate change keystore and truststore passwords or completely disable client cert authentication. diff --git a/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/VariablesReplacement.java b/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/VariablesReplacement.java new file mode 100644 index 0000000..c0bd989 --- /dev/null +++ b/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/VariablesReplacement.java @@ -0,0 +1,86 @@ +package org.onap.pnfsimulator.integration; + +import static io.restassured.RestAssured.given; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.hamcrest.Matchers.equalTo; + +import com.google.gson.JsonObject; +import java.net.Inet4Address; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.Collections; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = {Main.class, TestConfiguration.class}, + webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) +public class VariablesReplacement { + + @Autowired + private VesSimulatorService vesSimulatorService; + + private String currentVesSimulatorIp; + + @Before + public void setUp() throws Exception { + currentVesSimulatorIp = getCurrentIpAddress(); + } + + @Test + public void whenTriggeredSimulatorShouldReplaceStringKeyword() { + String startUrl = prepareRequestUrl(); + String body = "{\n" + "\"templateName\": \"cmNotification.json\",\n" + "\"patch\":{},\n" + "\"variables\":{\n" + + "\"dN\": \"NRNB=5, NRCEL=1234\",\n" + "\"attributeList\":{\n" + + "\"threshXHighQ\": \"50\",\n" + "\"threshXHighP\": \"52\"\n" + "}\n" + "},\n" + + "\"simulatorParams\": {\n" + "\"vesServerUrl\": \"https://" + currentVesSimulatorIp + + ":9443/ves-simulator/eventListener/v5\",\n" + "\"repeatInterval\": 1,\n" + + "\"repeatCount\": 1\n" + "}\n" + "}"; + ArgumentCaptor parameterCaptor = ArgumentCaptor.forClass(JsonObject.class); + + given().contentType("application/json").body(body).when().post(startUrl).then().statusCode(200) + .body("message", equalTo("Request started")); + + Mockito.verify(vesSimulatorService, Mockito.timeout(3000)).sendEventToDmaapV5(parameterCaptor.capture()); + + assertAttributeList(parameterCaptor); + assertDn(parameterCaptor); + } + + private void assertDn(ArgumentCaptor parameterCaptor) { + String dn = parameterCaptor.getValue().getAsJsonObject("event").getAsJsonObject("otherFields") + .getAsJsonArray("jsonObjects").get(0) + .getAsJsonObject().getAsJsonArray("objectInstances") + .get(0).getAsJsonObject().getAsJsonObject("objectInstance") + .getAsJsonObject("cm3gppNotifyFields").getAsJsonPrimitive("dN").getAsString(); + assertThat(dn).isEqualTo("NRNB=5, NRCEL=1234"); + } + + private void assertAttributeList(ArgumentCaptor parameterCaptor) { + JsonObject attributeList = parameterCaptor.getValue().getAsJsonObject("event").getAsJsonObject("otherFields") + .getAsJsonArray("jsonObjects").get(0).getAsJsonObject() + .getAsJsonArray("objectInstances").get(0).getAsJsonObject() + .getAsJsonObject("objectInstance").getAsJsonObject("cm3gppNotifyFields") + .getAsJsonObject("attributeList"); + assertThat(attributeList.get("threshXHighQ").getAsString()).isEqualTo("50"); + assertThat(attributeList.get("threshXHighP").getAsString()).isEqualTo("52"); + } + + private String prepareRequestUrl() { + return "http://0.0.0.0:5000/simulator/start"; + } + + private String getCurrentIpAddress() throws SocketException { + return Collections.list(NetworkInterface.getNetworkInterfaces()).stream() + .flatMap(i -> Collections.list(i.getInetAddresses()).stream()) + .filter(ip -> ip instanceof Inet4Address).map(e -> (Inet4Address) e).findFirst() + .orElseThrow(RuntimeException::new).getHostAddress(); + } + +} diff --git a/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/suites/DockerBasedTestsSuite.java b/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/suites/DockerBasedTestsSuite.java index cc2ac58..9ca7f60 100644 --- a/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/suites/DockerBasedTestsSuite.java +++ b/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/suites/DockerBasedTestsSuite.java @@ -30,10 +30,11 @@ import org.onap.pnfsimulator.integration.BasicAvailabilityTest; import org.onap.pnfsimulator.integration.OptionalTemplatesTest; import org.onap.pnfsimulator.integration.SearchInTemplatesTest; import org.onap.pnfsimulator.integration.TemplatesManagementTest; +import org.onap.pnfsimulator.integration.VariablesReplacement; @RunWith(Suite.class) @SuiteClasses({BasicAvailabilityTest.class, TemplatesManagementTest.class, OptionalTemplatesTest.class, - SearchInTemplatesTest.class}) + SearchInTemplatesTest.class, VariablesReplacement.class}) public class DockerBasedTestsSuite { @ClassRule diff --git a/pnfsimulator/integration/src/test/resources/templates/cmNotification.json b/pnfsimulator/integration/src/test/resources/templates/cmNotification.json new file mode 100644 index 0000000..750ce30 --- /dev/null +++ b/pnfsimulator/integration/src/test/resources/templates/cmNotification.json @@ -0,0 +1,32 @@ +{ + "event": { + "otherFields": { + "otherFieldsVersion": "3.0", + "jsonObjects": [ + { + "objectName": "CustomNotification", + "objectInstances": [ + { + "objectInstance": { + "cm3gppNotifyFields": { + "dN": "#dN", + "notificationType": "notifyMOIAttributeValueChange", + "notificationId": "notificationID123121312323", + "sourceIndicator": "sONOperation", + "eventTime": "#Timestamp", + "systemDN": "NRNB=5", + "attributeList": "#attributeList", + "correlatedNotifications": { + "notificationID-notifyMOIAttributeValueChange": "sONOperation" + }, + "additionalText": "sometext", + "cm3gppNotifyFieldsVersion": "1.0" + } + } + } + ] + } + ] + } + } +} diff --git a/pnfsimulator/pom.xml b/pnfsimulator/pom.xml index 37930dd..6ffe1e1 100644 --- a/pnfsimulator/pom.xml +++ b/pnfsimulator/pom.xml @@ -175,7 +175,12 @@ junit-jupiter-migrationsupport test - + + org.skyscreamer + jsonassert + test + + org.assertj assertj-core test diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/model/SimulatorRequest.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/model/SimulatorRequest.java index 2b06658..d00b311 100644 --- a/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/model/SimulatorRequest.java +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/model/SimulatorRequest.java @@ -48,4 +48,8 @@ public class SimulatorRequest { @JsonDeserialize(using = JsonObjectDeserializer.class) private JsonObject patch; + @Nullable + @JsonDeserialize(using = JsonObjectDeserializer.class) + private JsonObject variables; + } diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/SimulatorService.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/SimulatorService.java index 02f50e4..e5576b8 100644 --- a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/SimulatorService.java +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/SimulatorService.java @@ -45,6 +45,7 @@ import java.util.Optional; public class SimulatorService { private final TemplatePatcher templatePatcher; + private final TemplateVariablesReplacer templateVariablesReplacer; private final TemplateReader templateReader; private final EventDataService eventDataService; private final EventScheduler eventScheduler; @@ -53,14 +54,20 @@ public class SimulatorService { private static final JsonObject EMPTY_JSON_OBJECT = new JsonObject(); @Autowired - public SimulatorService(TemplatePatcher templatePatcher, TemplateReader templateReader, - EventScheduler eventScheduler, EventDataService eventDataService, - SimulatorConfigService simulatorConfigService, SslAuthenticationHelper sslAuthenticationHelper) { + public SimulatorService( + TemplatePatcher templatePatcher, + TemplateReader templateReader, + EventScheduler eventScheduler, + EventDataService eventDataService, + SimulatorConfigService simulatorConfigService, + TemplateVariablesReplacer templateVariablesReplacer, + SslAuthenticationHelper sslAuthenticationHelper) { this.templatePatcher = templatePatcher; this.templateReader = templateReader; this.eventDataService = eventDataService; this.eventScheduler = eventScheduler; this.simulatorConfigService = simulatorConfigService; + this.templateVariablesReplacer = templateVariablesReplacer; this.sslAuthenticationHelper = sslAuthenticationHelper; } @@ -71,16 +78,19 @@ public class SimulatorService { JsonObject input = Optional.ofNullable(simulatorRequest.getPatch()).orElse(new JsonObject()); JsonObject patchedJson = templatePatcher .mergeTemplateWithPatch(template, input); + JsonObject variables = Optional.ofNullable(simulatorRequest.getVariables()).orElse(new JsonObject()); + JsonObject patchedJsonWithVariablesSubstituted = templateVariablesReplacer.substituteVariables(patchedJson, variables); + JsonObject keywords = new JsonObject(); - EventData eventData = eventDataService.persistEventData(template, patchedJson, input, keywords); + EventData eventData = eventDataService.persistEventData(template, patchedJsonWithVariablesSubstituted, input, keywords); String targetVesUrl = getDefaultUrlIfNotProvided(simulatorParams.getVesServerUrl()); return eventScheduler .scheduleEvent(targetVesUrl, Optional.ofNullable(simulatorParams.getRepeatInterval()).orElse(1), Optional.ofNullable(simulatorParams.getRepeatCount()).orElse(1), simulatorRequest.getTemplateName(), eventData.getId(), - patchedJson); + patchedJsonWithVariablesSubstituted); } public void triggerOneTimeEvent(FullEvent event) throws IOException, GeneralSecurityException { diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/TemplateVariablesReplacer.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/TemplateVariablesReplacer.java new file mode 100644 index 0000000..eb0b141 --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/TemplateVariablesReplacer.java @@ -0,0 +1,50 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 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.pnfsimulator.simulator; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +import java.util.Map.Entry; + +import lombok.val; +import org.springframework.stereotype.Component; + +@Component +public class TemplateVariablesReplacer { + private static final Gson GSON = new Gson(); + private static final String OBJECT_KEYWORD_MARK = "#"; + private static final String ESCAPED_QUOTE = "\""; + private static final String STRING_KEYWORD_MARK = ESCAPED_QUOTE + OBJECT_KEYWORD_MARK + "%s" + ESCAPED_QUOTE; + + JsonObject substituteVariables(JsonObject source, JsonObject variables) { + var result = source.toString(); + for (val variable : variables.entrySet()) { + result = substituteVariable(result, variable); + } + return GSON.fromJson(result, JsonObject.class); + } + + private String substituteVariable(String sourceAsString, Entry variable) { + return sourceAsString.replaceAll(String.format(STRING_KEYWORD_MARK, variable.getKey()), variable.getValue().toString()); + } + +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapterImpl.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapterImpl.java index 7ddef86..a881698 100644 --- a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapterImpl.java +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapterImpl.java @@ -50,20 +50,20 @@ public class HttpClientAdapterImpl implements HttpClientAdapter { private static final String CONTENT_TYPE = "Content-Type"; private static final String APPLICATION_JSON = "application/json"; private static final RequestConfig CONFIG = RequestConfig.custom() - .setConnectTimeout(CONNECTION_TIMEOUT) - .setConnectionRequestTimeout(CONNECTION_TIMEOUT) - .setSocketTimeout(CONNECTION_TIMEOUT) - .build(); + .setConnectTimeout(CONNECTION_TIMEOUT) + .setConnectionRequestTimeout(CONNECTION_TIMEOUT) + .setSocketTimeout(CONNECTION_TIMEOUT) + .build(); private static final Marker INVOKE = MarkerFactory.getMarker("INVOKE"); private SslSupportLevel sslSupportLevel; private HttpClient client; private final String targetUrl; public HttpClientAdapterImpl(String targetUrl, SslAuthenticationHelper sslAuthenticationHelper) - throws IOException, GeneralSecurityException { + throws IOException, GeneralSecurityException { this.sslSupportLevel = sslAuthenticationHelper.isClientCertificateEnabled() - ? SslSupportLevel.CLIENT_CERT_AUTH - : SslSupportLevel.getSupportLevelBasedOnProtocol(targetUrl); + ? SslSupportLevel.CLIENT_CERT_AUTH + : SslSupportLevel.getSupportLevelBasedOnProtocol(targetUrl); this.client = sslSupportLevel.getClient(CONFIG, sslAuthenticationHelper); this.targetUrl = targetUrl; } @@ -76,11 +76,8 @@ public class HttpClientAdapterImpl implements HttpClientAdapter { @Override public void send(String content) { try { - HttpPost request = createRequest(content); - HttpResponse response = client.execute(request); - - //response has to be fully consumed otherwise apache won't release connection - EntityUtils.consumeQuietly(response.getEntity()); + HttpResponse response = sendAndRetrieve(content); + EntityUtils.consumeQuietly(response.getEntity()); //response has to be fully consumed otherwise apache won't release connection LOGGER.info(INVOKE, "Message sent, ves response code: {}", response.getStatusLine()); } catch (IOException e) { LOGGER.warn("Error sending message to ves: {}", e.getMessage(), e.getCause()); @@ -91,6 +88,13 @@ public class HttpClientAdapterImpl implements HttpClientAdapter { return sslSupportLevel; } + private HttpResponse sendAndRetrieve(String content) throws IOException { + HttpPost request = createRequest(content); + HttpResponse httpResponse = client.execute(request); + request.releaseConnection(); + return httpResponse; + } + private HttpPost createRequest(String content) throws UnsupportedEncodingException { HttpPost request = new HttpPost(this.targetUrl); StringEntity stringEntity = new StringEntity(content); @@ -101,5 +105,4 @@ public class HttpClientAdapterImpl implements HttpClientAdapter { return request; } - } diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/scheduler/EventJob.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/scheduler/EventJob.java index 21e0466..a467370 100644 --- a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/scheduler/EventJob.java +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/scheduler/EventJob.java @@ -73,6 +73,8 @@ public class EventJob implements Job { private Optional getHttpClientAdapter(JobDataMap jobDataMap, String vesUrl) { HttpClientAdapter adapter = null; try { + adapter = (HttpClientAdapter) (jobDataMap.containsKey(CLIENT_ADAPTER) ? jobDataMap.get(CLIENT_ADAPTER) + : new HttpClientAdapterImpl(vesUrl, new SslAuthenticationHelper())); adapter = (HttpClientAdapter) ( jobDataMap.containsKey(CLIENT_ADAPTER) ? jobDataMap.get(CLIENT_ADAPTER) diff --git a/pnfsimulator/src/main/resources/logback.xml b/pnfsimulator/src/main/resources/logback.xml index 8569b56..b93fedf 100644 --- a/pnfsimulator/src/main/resources/logback.xml +++ b/pnfsimulator/src/main/resources/logback.xml @@ -21,50 +21,35 @@ - - - - - - + + + + + + + - - - %nopexception%logger - |%date{yyyy-MM-dd'T'HH:mm:ss.SSSXXX,UTC} - |%level - |%replace(%replace(%message){'\t','\\\\t'}){'\n','\\\\n'} - |%replace(%replace(%mdc){'\t','\\\\t'}){'\n','\\\\n'} - |%replace(%replace(%rootException){'\t','\\\\t'}){'\n','\\\\n'} - |%replace(%replace(%marker){'\t','\\\\t'}){'\n','\\\\n'} - |%thread - |%n - - + + + ${CONSOLE_LOG_PATTERN} + + - - - %nopexception%logger - |%date{yyyy-MM-dd'T'HH:mm:ss.SSSXXX,UTC} - |%level - |%replace(%replace(%message){'\t','\\\\t'}){'\n','\\\\n'} - |%replace(%replace(%mdc){'\t','\\\\t'}){'\n','\\\\n'} - |%replace(%replace(%rootException){'\t','\\\\t'}){'\n','\\\\n'} - |%replace(%replace(%marker){'\t','\\\\t'}){'\n','\\\\n'} - |%thread - |%n - - ${log-path}/${outputFilename}.log - - ${archive}/${outputFilename}.%d{yyyy-MM-dd}.%i.log.zip - ${maxFileSize} - ${maxHistory} - ${totalSizeCap} - - + + + ${FILE_LOG_PATTERN} + + ${log-path}/${outputFilename}.log + + ${archive}/${outputFilename}.%d{yyyy-MM-dd}.%i.log.zip + ${maxFileSize} + ${maxHistory} + ${totalSizeCap} + + - - - - + + + + diff --git a/pnfsimulator/src/test/java/org/onap/pnfsimulator/rest/SimulatorControllerTest.java b/pnfsimulator/src/test/java/org/onap/pnfsimulator/rest/SimulatorControllerTest.java index 0b87f69..4fa5021 100644 --- a/pnfsimulator/src/test/java/org/onap/pnfsimulator/rest/SimulatorControllerTest.java +++ b/pnfsimulator/src/test/java/org/onap/pnfsimulator/rest/SimulatorControllerTest.java @@ -94,7 +94,7 @@ class SimulatorControllerTest { static void beforeAll() { SimulatorParams simulatorParams = new SimulatorParams("http://0.0.0.0:8080", 1, 1); SimulatorRequest simulatorRequest = new SimulatorRequest(simulatorParams, - "testTemplate.json", new JsonObject()); + "testTemplate.json", new JsonObject(), new JsonObject()); simulatorRequestBody = GSON_OBJ.toJson(simulatorRequest); } diff --git a/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/SimulatorServiceTest.java b/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/SimulatorServiceTest.java index c83c5cf..45e1ed4 100644 --- a/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/SimulatorServiceTest.java +++ b/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/SimulatorServiceTest.java @@ -82,6 +82,10 @@ class SimulatorServiceTest { + " \"domain\":\"notification\",\n" + " \"eventName\":\"#RandomString(20)\",\n" + " \"eventOrderNo\":\"#Increment\"}}}", JsonObject.class); + private static final JsonObject VALID_VARIABLES = GSON.fromJson("{\"dn\": \"TestDN-1\", \"measurement\":{\n" + + " \"name\": \"AdditionalM\",\n" + + " \"value\": \"1.5\"\n" + + " }}", JsonObject.class); private static final String SOME_CUSTOM_SOURCE = "SomeCustomSource"; private static final String CLOSED_LOOP_VNF = "ClosedLoopVNF"; private static final String SAMPLE_ID = "sampleId"; @@ -112,7 +116,8 @@ class SimulatorServiceTest { simulatorConfigService = mock(SimulatorConfigService.class); simulatorService = new SimulatorService(templatePatcher, templateReader, - eventScheduler, eventDataService, simulatorConfigService, sslAuthenticationHelper); + eventScheduler, eventDataService, simulatorConfigService, + new TemplateVariablesReplacer(),new SslAuthenticationHelper()); } @Test @@ -120,13 +125,14 @@ class SimulatorServiceTest { String templateName = "validExampleMeasurementEvent.json"; SimulatorParams simulatorParams = new SimulatorParams(VES_URL, 1, 1); SimulatorRequest simulatorRequest = new SimulatorRequest(simulatorParams, - templateName, VALID_PATCH); + templateName, VALID_PATCH, VALID_VARIABLES); doReturn(SAMPLE_EVENT).when(eventDataService).persistEventData(any(JsonObject.class), any(JsonObject.class), any(JsonObject.class), any(JsonObject.class)); simulatorService.triggerEvent(simulatorRequest); assertEventHasExpectedStructure(VES_URL, templateName, SOME_CUSTOM_SOURCE); + assertEventHasReplacedVariables(); } @Test @@ -134,7 +140,7 @@ class SimulatorServiceTest { String templateName = "validExampleMeasurementEvent.json"; SimulatorRequest simulatorRequest = new SimulatorRequest( new SimulatorParams("", 1, 1), - templateName, VALID_PATCH); + templateName, VALID_PATCH, new JsonObject()); doReturn(SAMPLE_EVENT).when(eventDataService).persistEventData(any(JsonObject.class), any(JsonObject.class), any(JsonObject.class), any(JsonObject.class)); when(simulatorConfigService.getConfiguration()).thenReturn(new SimulatorConfig(SAMPLE_ID, inDbVesUrl)); @@ -159,7 +165,7 @@ class SimulatorServiceTest { SimulatorParams simulatorParams = new SimulatorParams(VES_URL, 1, 1); SimulatorRequest simulatorRequest = new SimulatorRequest(simulatorParams, - "invalidJsonStructureEvent.json", patch); + "invalidJsonStructureEvent.json", patch, new JsonObject()); doReturn(eventData).when(eventDataService).persistEventData(any(JsonObject.class), any(JsonObject.class), any(JsonObject.class), any(JsonObject.class)); //when @@ -172,7 +178,7 @@ class SimulatorServiceTest { String templateName = "validExampleMeasurementEvent.json"; SimulatorRequest simulatorRequest = new SimulatorRequest( new SimulatorParams("", 1, 1), - templateName, null); + templateName, null, new JsonObject()); doReturn(SAMPLE_EVENT).when(eventDataService).persistEventData(any(JsonObject.class), any(JsonObject.class), any(JsonObject.class), any(JsonObject.class)); doReturn(new SimulatorConfig(SAMPLE_ID, inDbVesUrl)).when(simulatorConfigService).getConfiguration(); @@ -184,7 +190,11 @@ class SimulatorServiceTest { @Test void shouldSuccessfullySendOneTimeEventWithVesUrlWhenPassed() throws IOException, GeneralSecurityException { - SimulatorService spiedTestedService = spy(new SimulatorService(templatePatcher, templateReader, eventScheduler, eventDataService, simulatorConfigService, new SslAuthenticationHelper())); + SimulatorService spiedTestedService = spy(new SimulatorService( + templatePatcher, templateReader, eventScheduler, + eventDataService, simulatorConfigService, + new TemplateVariablesReplacer(), + new SslAuthenticationHelper())); HttpClientAdapter adapterMock = mock(HttpClientAdapter.class); doNothing().when(adapterMock).send(eventContentCaptor.capture()); @@ -200,7 +210,12 @@ class SimulatorServiceTest { @Test void shouldSubstituteKeywordsAndSuccessfullySendOneTimeEvent() throws IOException, GeneralSecurityException { - SimulatorService spiedTestedService = spy(new SimulatorService(templatePatcher, templateReader, eventScheduler, eventDataService, simulatorConfigService, new SslAuthenticationHelper())); + SimulatorService spiedTestedService = spy(new SimulatorService( + templatePatcher, templateReader, eventScheduler, + eventDataService, simulatorConfigService, + new TemplateVariablesReplacer(), + new SslAuthenticationHelper()) + ); HttpClientAdapter adapterMock = mock(HttpClientAdapter.class); doNothing().when(adapterMock).send(eventContentCaptor.capture()); @@ -267,4 +282,22 @@ class SimulatorServiceTest { private SimulatorConfig getSimulatorConfig() { return new SimulatorConfig(SAMPLE_ID, inDbVesUrl); } + + private void assertEventHasReplacedVariables() { + String measurementName = GSON.fromJson(bodyCaptor.getValue(), JsonObject.class) + .get("event").getAsJsonObject() + .get("measurementsForVfScalingFields").getAsJsonObject() + .get("additionalMeasurements").getAsJsonArray().get(0).getAsJsonObject() + .get("arrayOfFields").getAsJsonArray().get(0).getAsJsonObject() + .get("name").getAsString(); + + String reportingEntityName = GSON.fromJson(bodyCaptor.getValue(), JsonObject.class) + .get("event").getAsJsonObject() + .get("commonEventHeader").getAsJsonObject() + .get("reportingEntityName").getAsString(); + + assertThat(measurementName).isEqualTo("AdditionalM"); + assertThat(reportingEntityName).isEqualTo("TestDN-1"); + } + } diff --git a/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/TemplateVariablesReplacerTest.java b/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/TemplateVariablesReplacerTest.java new file mode 100644 index 0000000..5b7e4f4 --- /dev/null +++ b/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/TemplateVariablesReplacerTest.java @@ -0,0 +1,174 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 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.pnfsimulator.simulator; + + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import lombok.val; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestInstance.Lifecycle; +import org.skyscreamer.jsonassert.JSONAssert; + +@TestInstance(Lifecycle.PER_CLASS) +class TemplateVariablesReplacerTest { + + private static final Gson GSON = new Gson(); + + private TemplateVariablesReplacer replacer; + + @BeforeAll + void setUp() { + replacer = new TemplateVariablesReplacer(); + } + + @Test + void shouldReplaceStringVariable() { + val sourceAsString = "{\"test1\":\"#variable1\", \"variable1\":\"value2 #variable1\"}"; + val expectedAsString = "{\"test1\":\"valueOfVariable1\", \"variable1\":\"value2 #variable1\"}"; + val variablesAsString = "{\"variable1\":\"valueOfVariable1\"}"; + + val source = GSON.fromJson(sourceAsString, JsonObject.class); + val variables = GSON.fromJson(variablesAsString, JsonObject.class); + + JsonObject result = replacer.substituteVariables(source, variables); + JSONAssert.assertEquals(expectedAsString, result.toString(), true); + } + + @Test + void shouldReplaceStringAndNumberVariable() { + val sourceAsString = "{\"test1\":\"#variable1\", \"test2\":\"#variable2\"}"; + val expectedAsString = "{\"test1\":\"valueOfVariable1=1\", \"test2\":2}"; + val variablesAsString = "{\"variable1\":\"valueOfVariable1=1\", \"variable2\":2}"; + + val source = new Gson().fromJson(sourceAsString, JsonObject.class); + val variables = new Gson().fromJson(variablesAsString, JsonObject.class); + + JsonObject result = replacer.substituteVariables(source, variables); + JSONAssert.assertEquals(expectedAsString, result.toString(), true); + } + + @Test + void shouldReplaceSimpleStringVariable() { + val sourceAsString = "{\"test1\":\"value1\", \"variable1\":\"#variable1\"}"; + val expectedAsString = "{\"test1\":\"value1\", \"variable1\":\"valueOfVariable1\"}"; + val variablesAsString = "{\"variable1\":\"valueOfVariable1\"}"; + + val source = GSON.fromJson(sourceAsString, JsonObject.class); + val variables = GSON.fromJson(variablesAsString, JsonObject.class); + + JsonObject result = replacer.substituteVariables(source, variables); + JSONAssert.assertEquals(expectedAsString, result.toString(), true); + } + + @Test + void shouldReplaceObjectVariable() { + val sourceAsString = "{\"test1\":\"value1\", \"variable1\":\"#variable1\"}"; + val expectedAsString = "{\"test1\":\"value1\", \"variable1\":{\"replaced1\":\"valueOfVariable1\"}}"; + val variablesAsString = "{\"variable1\":{\"replaced1\":\"valueOfVariable1\"}}"; + + val source = GSON.fromJson(sourceAsString, JsonObject.class); + val variables = GSON.fromJson(variablesAsString, JsonObject.class); + + JsonObject result = replacer.substituteVariables(source, variables); + JSONAssert.assertEquals(expectedAsString, result.toString(), true); + } + + @Test + void shouldReplaceIntegerVariable() { + val sourceAsString = "{\"test1\":\"value1\", \"variable1\":\"#variable1\"}"; + val expectedAsString = "{\"test1\":\"value1\", \"variable1\": 1}"; + val variablesAsString = "{\"variable1\": 1}"; + + val source = GSON.fromJson(sourceAsString, JsonObject.class); + val variables = GSON.fromJson(variablesAsString, JsonObject.class); + + JsonObject result = replacer.substituteVariables(source, variables); + JSONAssert.assertEquals(expectedAsString, result.toString(), true); + } + + @Test + void shouldReplaceBoolVariable() { + val sourceAsString = "{\"test1\":\"value1\", \"variable1\":\"#variable1\"}"; + val expectedAsString = "{\"test1\":\"value1\", \"variable1\": true}"; + val variablesAsString = "{\"variable1\": true}"; + + val source = GSON.fromJson(sourceAsString, JsonObject.class); + val variables = GSON.fromJson(variablesAsString, JsonObject.class); + + JsonObject result = replacer.substituteVariables(source, variables); + JSONAssert.assertEquals(expectedAsString, result.toString(), true); + } + + @Test + void shouldReplaceDifferentVariables() { + val sourceAsString = "{\"test1\":\"value1\", \"variable1\":\"#variable\", \"variable2\":\"text #variable\"}"; + val expectedAsString = "{\"test1\":\"value1\", \"variable1\":{\"replaced1\":\"valueOfVariable1\"}, \"variable2\":\"text #variable\"}"; + val variablesAsString = "{\"variable\":{\"replaced1\":\"valueOfVariable1\"}}"; + + val source = GSON.fromJson(sourceAsString, JsonObject.class); + val variables = GSON.fromJson(variablesAsString, JsonObject.class); + + JsonObject result = replacer.substituteVariables(source, variables); + JSONAssert.assertEquals(expectedAsString, result.toString(), true); + } + + @Test + void shouldReplaceArrayVariables() { + val sourceAsString = "{\"test1\":\"value1\", \"variable1\":\"#variable1\"}"; + val expectedAsString = "{\"test1\":\"value1\", \"variable1\":[1,2,3]}"; + val variablesAsString = "{\"variable1\":[1,2,3]}"; + + val source = GSON.fromJson(sourceAsString, JsonObject.class); + val variables = GSON.fromJson(variablesAsString, JsonObject.class); + + JsonObject result = replacer.substituteVariables(source, variables); + JSONAssert.assertEquals(expectedAsString, result.toString(), true); + } + + @Test + void shouldReplaceArrayWithStringVariables() { + val sourceAsString = "{\"test1\":\"value1\", \"variable1\":\"#variable1\"}"; + val expectedAsString = "{\"test1\":\"value1\", \"variable1\":[\"1\",\"2\",\"3\"]}"; + val variablesAsString = "{\"variable1\":[\"1\",\"2\",\"3\"]}"; + + val source = GSON.fromJson(sourceAsString, JsonObject.class); + val variables = GSON.fromJson(variablesAsString, JsonObject.class); + + JsonObject result = replacer.substituteVariables(source, variables); + JSONAssert.assertEquals(expectedAsString, result.toString(), true); + } + + @Test + void shouldReplaceArrayAsStringVariables() { + val sourceAsString = "{\"test1\":\"#variable1\", \"variable1\":\"Text #variable1\"}"; + val expectedAsString = "{\"test1\":[1,2,3], \"variable1\": \"Text #variable1\"}"; + val variablesAsString = "{\"variable1\":[1,2,3]}"; + + val source = GSON.fromJson(sourceAsString, JsonObject.class); + val variables = GSON.fromJson(variablesAsString, JsonObject.class); + + JsonObject result = replacer.substituteVariables(source, variables); + JSONAssert.assertEquals(expectedAsString, result.toString(), true); + } + +} \ No newline at end of file diff --git a/pnfsimulator/src/test/resources/logback-test.xml b/pnfsimulator/src/test/resources/logback-test.xml index ad4f0c8..0dedeba 100644 --- a/pnfsimulator/src/test/resources/logback-test.xml +++ b/pnfsimulator/src/test/resources/logback-test.xml @@ -26,32 +26,18 @@ + + - %nopexception%logger - |%date{yyyy-MM-dd'T'HH:mm:ss.SSSXXX,UTC} - |%level - |%replace(%replace(%message){'\t','\\\\t'}){'\n','\\\\n'} - |%replace(%replace(%mdc){'\t','\\\\t'}){'\n','\\\\n'} - |%replace(%replace(%rootException){'\t','\\\\t'}){'\n','\\\\n'} - |%replace(%replace(%marker){'\t','\\\\t'}){'\n','\\\\n'} - |%thread - |%n + ${CONSOLE_LOG_PATTERN} - %nopexception%logger - |%date{yyyy-MM-dd'T'HH:mm:ss.SSSXXX,UTC} - |%level - |%replace(%replace(%message){'\t','\\\\t'}){'\n','\\\\n'} - |%replace(%replace(%mdc){'\t','\\\\t'}){'\n','\\\\n'} - |%replace(%replace(%rootException){'\t','\\\\t'}){'\n','\\\\n'} - |%replace(%replace(%marker){'\t','\\\\t'}){'\n','\\\\n'} - |%thread - |%n + ${FILE_LOG_PATTERN} ${log-path}/${outputFilename}.log diff --git a/pnfsimulator/src/test/resources/org/onap/pnfsimulator/simulator/validExampleMeasurementEvent.json b/pnfsimulator/src/test/resources/org/onap/pnfsimulator/simulator/validExampleMeasurementEvent.json index 989d6ea..a240b93 100644 --- a/pnfsimulator/src/test/resources/org/onap/pnfsimulator/simulator/validExampleMeasurementEvent.json +++ b/pnfsimulator/src/test/resources/org/onap/pnfsimulator/simulator/validExampleMeasurementEvent.json @@ -6,7 +6,7 @@ "eventId": "4cfc-91cf-31a46", "nfType": "mrfx", "priority": "Normal", - "reportingEntityName": "myVNF", + "reportingEntityName": "#dn", "sequence": 1, "sourceName": "ClosedLoopVNF", "startEpochMicrosec": 1531616794, @@ -45,10 +45,7 @@ { "name": "licenseUsage", "arrayOfFields": [ - { - "name": "G711AudioPort", - "value": "1" - }, + "#measurement", { "name": "G729AudioPort", "value": "1" diff --git a/pnfsimulator/templates/cmNotification.json b/pnfsimulator/templates/cmNotification.json new file mode 100644 index 0000000..750ce30 --- /dev/null +++ b/pnfsimulator/templates/cmNotification.json @@ -0,0 +1,32 @@ +{ + "event": { + "otherFields": { + "otherFieldsVersion": "3.0", + "jsonObjects": [ + { + "objectName": "CustomNotification", + "objectInstances": [ + { + "objectInstance": { + "cm3gppNotifyFields": { + "dN": "#dN", + "notificationType": "notifyMOIAttributeValueChange", + "notificationId": "notificationID123121312323", + "sourceIndicator": "sONOperation", + "eventTime": "#Timestamp", + "systemDN": "NRNB=5", + "attributeList": "#attributeList", + "correlatedNotifications": { + "notificationID-notifyMOIAttributeValueChange": "sONOperation" + }, + "additionalText": "sometext", + "cm3gppNotifyFieldsVersion": "1.0" + } + } + } + ] + } + ] + } + } +} diff --git a/pom.xml b/pom.xml index 3e00cc6..e328340 100644 --- a/pom.xml +++ b/pom.xml @@ -103,6 +103,7 @@ 0.29.1 5.0.4.RELEASE 5.1.0 + 1.5.0 @@ -261,6 +262,12 @@ + + org.skyscreamer + jsonassert + ${jsonassert.version} + test + org.assertj assertj-core -- cgit 1.2.3-korg