Fix common event header parsing 85/64985/8
authorFilip Krzywka <filip.krzywka@nokia.com>
Thu, 6 Sep 2018 11:37:27 +0000 (13:37 +0200)
committerFilip Krzywka <filip.krzywka@nokia.com>
Tue, 11 Sep 2018 07:28:16 +0000 (07:28 +0000)
During JSON parsing we were using 3 times 'version' field. Replaced
parsing with protobuf parser to avoid mistakes like this in future

Change-Id: I6224dc6533ab553e7e2315a95567a1fa48c1c5ad
Issue-ID: DCAEGEN2-710
Signed-off-by: Filip Krzywka <filip.krzywka@nokia.com>
hv-collector-core/src/main/kotlin/org/onap/dcae/collectors/veshv/impl/MessageValidator.kt
hv-collector-domain/src/main/kotlin/org/onap/dcae/collectors/veshv/domain/validation.kt [new file with mode: 0644]
hv-collector-ves-message-generator/pom.xml
hv-collector-ves-message-generator/src/main/kotlin/org/onap/dcae/collectors/veshv/ves/message/generator/impl/CommonEventHeaderParser.kt
hv-collector-ves-message-generator/src/main/kotlin/org/onap/dcae/collectors/veshv/ves/message/generator/impl/MessageParametersParserImpl.kt
hv-collector-ves-message-generator/src/test/kotlin/org/onap/dcae/collectors/veshv/ves/message/generator/impl/CommonEventHeaderParserTest.kt [new file with mode: 0644]

index 543d7dc..8affa0b 100644 (file)
  */
 package org.onap.dcae.collectors.veshv.impl
 
+import org.onap.dcae.collectors.veshv.domain.headerRequiredFieldDescriptors
 import org.onap.dcae.collectors.veshv.model.VesMessage
 import org.onap.ves.VesEventV5.VesEvent.CommonEventHeader
 
 internal object MessageValidator {
 
-    private val requiredFieldDescriptors = listOf(
-            "version",
-            "eventName",
-            "domain",
-            "eventId",
-            "sourceName",
-            "reportingEntityName",
-            "priority",
-            "startEpochMicrosec",
-            "lastEpochMicrosec",
-            "sequence")
-            .map { fieldName -> CommonEventHeader.getDescriptor().findFieldByName(fieldName) }
-
     fun isValid(message: VesMessage): Boolean {
         return allMandatoryFieldsArePresent(message.header)
     }
 
     private fun allMandatoryFieldsArePresent(header: CommonEventHeader) =
-            requiredFieldDescriptors
+            headerRequiredFieldDescriptors
                     .all { fieldDescriptor -> header.hasField(fieldDescriptor) }
 }
diff --git a/hv-collector-domain/src/main/kotlin/org/onap/dcae/collectors/veshv/domain/validation.kt b/hv-collector-domain/src/main/kotlin/org/onap/dcae/collectors/veshv/domain/validation.kt
new file mode 100644 (file)
index 0000000..91c7545
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * ============LICENSE_START=======================================================
+ * dcaegen2-collectors-veshv
+ * ================================================================================
+ * Copyright (C) 2018 NOKIA
+ * ================================================================================
+ * 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.collectors.veshv.domain
+
+import org.onap.ves.VesEventV5
+
+val headerRequiredFieldDescriptors = listOf(
+        "version",
+        "eventName",
+        "domain",
+        "eventId",
+        "sourceName",
+        "reportingEntityName",
+        "priority",
+        "startEpochMicrosec",
+        "lastEpochMicrosec",
+        "sequence")
+        .map { fieldName -> VesEventV5.VesEvent.CommonEventHeader.getDescriptor().findFieldByName(fieldName) }
\ No newline at end of file
index f06a911..4afe796 100644 (file)
             <version>${project.parent.version}</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>com.google.protobuf</groupId>
+            <artifactId>protobuf-java-util</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
index e5977fb..768685c 100644 (file)
  */
 package org.onap.dcae.collectors.veshv.ves.message.generator.impl
 
-import com.google.protobuf.ByteString
-import org.onap.ves.VesEventV5.VesEvent.CommonEventHeader
-import org.onap.ves.VesEventV5.VesEvent.CommonEventHeader.Domain
-import org.onap.ves.VesEventV5.VesEvent.CommonEventHeader.Priority
-import org.onap.ves.VesEventV5.VesEvent.CommonEventHeader.newBuilder
+import arrow.core.Option
+import com.google.protobuf.util.JsonFormat
+import org.onap.dcae.collectors.veshv.domain.headerRequiredFieldDescriptors
+import org.onap.ves.VesEventV5.VesEvent.*
 import javax.json.JsonObject
 
 /**
@@ -31,22 +30,21 @@ import javax.json.JsonObject
  * @since July 2018
  */
 class CommonEventHeaderParser {
-    fun parse(json: JsonObject): CommonEventHeader = newBuilder()
-            .setVersion(json.getString("version"))
-            .setDomain(Domain.valueOf(json.getString("domain")))
-            .setSequence(json.getInt("sequence"))
-            .setPriority(Priority.forNumber(json.getInt("priority")))
-            .setEventId(json.getString("version"))
-            .setEventName(json.getString("version"))
-            .setEventType(json.getString("version"))
-            .setStartEpochMicrosec(json.getJsonNumber("startEpochMicrosec").longValue())
-            .setLastEpochMicrosec(json.getJsonNumber("lastEpochMicrosec").longValue())
-            .setNfNamingCode(json.getString("nfNamingCode"))
-            .setNfcNamingCode(json.getString("nfcNamingCode"))
-            .setReportingEntityId(json.getString("reportingEntityId"))
-            .setReportingEntityName(ByteString.copyFromUtf8(json.getString("reportingEntityName")))
-            .setSourceId(ByteString.copyFromUtf8(json.getString("sourceId")))
-            .setSourceName(json.getString("sourceName"))
-            .build()
+    fun parse(json: JsonObject): Option<CommonEventHeader> =
+            Option.fromNullable(
+                    CommonEventHeader.newBuilder()
+                            .apply { JsonFormat.parser().merge(json.toString(), this) }
+                            .build()
+                            .takeUnless { !isValid(it) }
+            )
+
+
+    private fun isValid(header: CommonEventHeader): Boolean {
+        return allMandatoryFieldsArePresent(header)
+    }
+
+    private fun allMandatoryFieldsArePresent(header: CommonEventHeader) =
+            headerRequiredFieldDescriptors
+                    .all { fieldDescriptor -> header.hasField(fieldDescriptor) }
 
 }
index f309561..ea0ee28 100644 (file)
@@ -21,6 +21,7 @@ package org.onap.dcae.collectors.veshv.ves.message.generator.impl
 
 import arrow.core.Option
 import arrow.core.Try
+import arrow.core.identity
 import org.onap.dcae.collectors.veshv.ves.message.generator.api.MessageParameters
 import org.onap.dcae.collectors.veshv.ves.message.generator.api.MessageParametersParser
 import org.onap.dcae.collectors.veshv.ves.message.generator.api.MessageType
@@ -42,6 +43,7 @@ internal class MessageParametersParserImpl(
                         .map {
                             val commonEventHeader = commonEventHeaderParser
                                     .parse(it.getJsonObject("commonEventHeader"))
+                                    .fold({ throw IllegalStateException("Invalid common header") }, ::identity)
                             val messageType = MessageType.valueOf(it.getString("messageType"))
                             val messagesAmount = it.getJsonNumber("messagesAmount")?.longValue()
                                     ?: throw NullPointerException("\"messagesAmount\" could not be parsed from message.")
diff --git a/hv-collector-ves-message-generator/src/test/kotlin/org/onap/dcae/collectors/veshv/ves/message/generator/impl/CommonEventHeaderParserTest.kt b/hv-collector-ves-message-generator/src/test/kotlin/org/onap/dcae/collectors/veshv/ves/message/generator/impl/CommonEventHeaderParserTest.kt
new file mode 100644 (file)
index 0000000..c16459c
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * ============LICENSE_START=======================================================
+ * dcaegen2-collectors-veshv
+ * ================================================================================
+ * Copyright (C) 2018 NOKIA
+ * ================================================================================
+ * 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.collectors.veshv.ves.message.generator.impl
+
+import arrow.core.Option
+import arrow.core.identity
+import com.google.protobuf.util.JsonFormat
+import org.assertj.core.api.Assertions.assertThat
+import org.jetbrains.spek.api.Spek
+import org.jetbrains.spek.api.dsl.describe
+import org.jetbrains.spek.api.dsl.given
+import org.jetbrains.spek.api.dsl.it
+import org.onap.dcae.collectors.veshv.tests.utils.commonHeader
+import org.onap.ves.VesEventV5
+import java.io.ByteArrayInputStream
+import javax.json.Json
+import kotlin.test.fail
+
+class CommonEventHeaderParserTest : Spek({
+
+    describe("Common event header parser") {
+        val parser = CommonEventHeaderParser()
+
+        given("valid header in JSON format") {
+            val commonEventHeader = commonHeader(
+                    domain = VesEventV5.VesEvent.CommonEventHeader.Domain.STATE_CHANGE,
+                    id = "sample-event-id")
+            val json = JsonFormat.printer().print(commonEventHeader).byteInputStream()
+
+            it("should parse common event header") {
+                val result =
+                        parser.parse(jsonObject(json))
+                                .fold({ fail() }, ::identity)
+
+                assertThat(result).describedAs("common event header").isEqualTo(commonEventHeader)
+            }
+        }
+
+        given("invalid header in JSON format") {
+            val json = "{}".byteInputStream()
+
+            it("should throw exception") {
+                val result = parser.parse(jsonObject(json))
+
+                assertFailed(result)
+            }
+        }
+
+        given("invalid JSON") {
+            val json = "{}}}}".byteInputStream()
+
+            it("should throw exception") {
+                val result = parser.parse(jsonObject(json))
+
+                assertFailed(result)
+            }
+        }
+    }
+})
+
+fun assertFailed(result: Option<VesEventV5.VesEvent.CommonEventHeader>) =
+        result.fold({}, { fail() })
+
+fun jsonObject(json: ByteArrayInputStream) = Json.createReader(json).readObject()
\ No newline at end of file