Improve coverage of xNF simulator

Also refactor to make it possible.

Change-Id: I6da6d3f33e57c524a7e353ecebd3e045d8ceed2a
Issue-ID: DCAEGEN2-739
Signed-off-by: Piotr Jaszczyk <piotr.jaszczyk@nokia.com>
diff --git a/hv-collector-utils/pom.xml b/hv-collector-utils/pom.xml
index f1b7f06..81daf9b 100644
--- a/hv-collector-utils/pom.xml
+++ b/hv-collector-utils/pom.xml
@@ -85,6 +85,20 @@
             <artifactId>arrow-syntax</artifactId>
         </dependency>
         <dependency>
+            <groupId>org.jetbrains.kotlinx</groupId>
+            <artifactId>kotlinx-coroutines-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.ratpack</groupId>
+            <artifactId>ratpack-core</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>javax.json</groupId>
+            <artifactId>javax.json-api</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
         </dependency>
@@ -121,7 +135,10 @@
             <artifactId>logback-classic</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.glassfish</groupId>
+            <artifactId>javax.json</artifactId>
+            <scope>provided</scope>
+        </dependency>
     </dependencies>
-
-
 </project>
\ No newline at end of file
diff --git a/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/arrow/core.kt b/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/arrow/core.kt
index 2d538b7..a99fef5 100644
--- a/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/arrow/core.kt
+++ b/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/arrow/core.kt
@@ -35,6 +35,10 @@
 
 fun <A> Either<A, A>.flatten() = fold(::identity, ::identity)
 
+fun <B> Either<Throwable, B>.rightOrThrow() = fold({ throw it }, ::identity)
+
+fun <A, B> Either<A, B>.rightOrThrow(mapper: (A) -> Throwable) = fold({ throw mapper(it) }, ::identity)
+
 fun <A> AtomicReference<A>.getOption() = Option.fromNullable(get())
 
 fun <A> Option.Companion.fromNullablesChain(firstValue: A?, vararg nextValues: () -> A?): Option<A> =
diff --git a/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/arrow/effects.kt b/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/arrow/effects.kt
index cef537e..05d1309 100644
--- a/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/arrow/effects.kt
+++ b/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/arrow/effects.kt
@@ -50,10 +50,14 @@
         flatten().attempt().unsafeRunSync().fold({ onError(it).io().unsafeRunSync() }, { onSuccess() })
 
 
-fun IO<Any>.void() = map { Unit }
+fun IO<Any>.unit() = map { Unit }
 
-fun <T> Mono<T>.asIo() = IO.async<T> { proc ->
-    subscribe({ proc(Right(it)) }, { proc(Left(it)) })
+fun <T> Mono<T>.asIo() = IO.async<T> { callback ->
+    subscribe({
+        callback(Right(it))
+    }, {
+        callback(Left(it))
+    })
 }
 
 fun <T> Flux<IO<T>>.evaluateIo(): Flux<T> =
diff --git a/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/http/Status.kt b/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/http/Status.kt
deleted file mode 100644
index 081dd0d..0000000
--- a/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/http/Status.kt
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * ============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.utils.http
-
-/**
- * @author Jakub Dudycz <jakub.dudycz@nokia.com>
- * @since August 2018
- */
-class Status {
-    companion object {
-        const val OK = 200
-        const val SERVICE_UNAVAILABLE = 503
-    }
-}
diff --git a/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/http/http.kt b/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/http/http.kt
new file mode 100644
index 0000000..c5c4639
--- /dev/null
+++ b/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/http/http.kt
@@ -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.utils.http
+
+import arrow.typeclasses.Show
+import java.util.*
+import javax.json.Json
+
+/**
+ * @author Jakub Dudycz <jakub.dudycz@nokia.com>
+ * @since August 2018
+ */
+object HttpConstants {
+    const val STATUS_OK = 200
+    const val STATUS_ACCEPTED = 202
+    const val STATUS_BAD_REQUEST = 400
+    const val STATUS_NOT_FOUND = 404
+    const val STATUS_INTERNAL_SERVER_ERROR = 500
+    const val STATUS_SERVICE_UNAVAILABLE = 503
+
+    const val CONTENT_TYPE_JSON = "application/json"
+    const val CONTENT_TYPE_TEXT = "text/plain"
+}
+
+enum class HttpStatus(val number: Int) {
+    OK(HttpConstants.STATUS_OK),
+    ACCEPTED(HttpConstants.STATUS_ACCEPTED),
+    BAD_REQUEST(HttpConstants.STATUS_BAD_REQUEST),
+    NOT_FOUND(HttpConstants.STATUS_NOT_FOUND),
+    INTERNAL_SERVER_ERROR(HttpConstants.STATUS_INTERNAL_SERVER_ERROR),
+    SERVICE_UNAVAILABLE(HttpConstants.STATUS_SERVICE_UNAVAILABLE)
+}
+
+
+enum class ContentType(val value: String) {
+    JSON(HttpConstants.CONTENT_TYPE_JSON),
+    TEXT(HttpConstants.CONTENT_TYPE_TEXT)
+}
+
+data class Response(val status: HttpStatus, val content: Content<Any>)
+data class Content<T>(val type: ContentType, val value: T, val serializer: Show<T> = Show.any())
+
+/**
+ * @author Piotr Jaszczyk <piotr.jaszczyk@nokia.com>
+ * @since September 2018
+ */
+object Responses {
+
+    fun acceptedResponse(id: UUID): Response {
+        return Response(
+                HttpStatus.ACCEPTED,
+                Content(ContentType.TEXT, id)
+        )
+    }
+
+    fun statusResponse(name: String, message: String, httpStatus: HttpStatus = HttpStatus.OK): Response {
+        return Response(httpStatus,
+                Content(ContentType.JSON,
+                        Json.createObjectBuilder()
+                                .add("status", name)
+                                .add("message", message)
+                                .build()))
+    }
+}
diff --git a/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/http/ratpack.kt b/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/http/ratpack.kt
new file mode 100644
index 0000000..0282d0c
--- /dev/null
+++ b/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/http/ratpack.kt
@@ -0,0 +1,77 @@
+/*
+ * ============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.utils.http
+
+import arrow.core.Either
+import arrow.effects.IO
+import org.onap.dcae.collectors.veshv.utils.logging.Logger
+import javax.json.Json
+
+/**
+ * @author Piotr Jaszczyk <piotr.jaszczyk@nokia.com>
+ * @since August 2018
+ */
+
+private val logger = Logger("org.onap.dcae.collectors.veshv.utils.arrow.ratpack")
+
+fun ratpack.http.Response.sendOrError(action: IO<Unit>) {
+    sendAndHandleErrors(action.map {
+        Response(
+                HttpStatus.OK,
+                Content(
+                        ContentType.JSON,
+                        Json.createObjectBuilder().add("response", "Request accepted").build()))
+    })
+}
+
+fun <A> ratpack.http.Response.sendEitherErrorOrResponse(response: Either<A, Response>) {
+    when(response) {
+        is Either.Left -> send(errorResponse(response.a.toString()))
+        is Either.Right -> sendAndHandleErrors(IO.just(response.b))
+    }
+}
+
+fun ratpack.http.Response.sendAndHandleErrors(response: IO<Response>) {
+    response.attempt().unsafeRunSync().fold(
+            { err ->
+                logger.warn("Error occurred. Sending .", err)
+                val message = err.message
+                send(errorResponse(message))
+            },
+            ::send
+    )
+}
+
+private fun errorResponse(message: String?): Response {
+    return Response(
+            HttpStatus.INTERNAL_SERVER_ERROR,
+            Content(
+                    ContentType.JSON,
+                    Json.createObjectBuilder().add("error", message).build()))
+}
+
+fun ratpack.http.Response.send(response: Response) {
+    val respWithStatus = status(response.status.number)
+    response.content.apply {
+        respWithStatus.send(
+                type.value,
+                serializer.run { value.show() })
+    }
+}
diff --git a/hv-collector-utils/src/test/kotlin/org/onap/dcae/collectors/veshv/utils/http/ResponsesTest.kt b/hv-collector-utils/src/test/kotlin/org/onap/dcae/collectors/veshv/utils/http/ResponsesTest.kt
new file mode 100644
index 0000000..f9f716a
--- /dev/null
+++ b/hv-collector-utils/src/test/kotlin/org/onap/dcae/collectors/veshv/utils/http/ResponsesTest.kt
@@ -0,0 +1,101 @@
+/*
+ * ============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.utils.http
+
+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.jetbrains.spek.api.dsl.on
+import java.util.*
+import javax.json.JsonObject
+
+/**
+ * @author Piotr Jaszczyk <piotr.jaszczyk@nokia.com>
+ * @since September 2018
+ */
+internal class ResponsesTest : Spek({
+    describe("response factory") {
+        describe("accepted response") {
+            given("uuid") {
+                val uuid = UUID.randomUUID()
+
+                on("calling acceptedResponse") {
+                    val result = Responses.acceptedResponse(uuid)
+
+                    it ("should have ACCEPTED status") {
+                        assertThat(result.status).isEqualTo(HttpStatus.ACCEPTED)
+                    }
+
+                    it ("should have text body") {
+                        assertThat(result.content.type).isEqualTo(ContentType.TEXT)
+                    }
+
+                    it ("should contain UUID text in the body") {
+                        val serialized = result.content.serializer.run { result.content.value.show() }
+                        assertThat(serialized).isEqualTo(uuid.toString())
+                    }
+                }
+            }
+        }
+        describe("status response") {
+            given("all params are specified") {
+                val status = "ok"
+                val message = "good job"
+                val httpStatus = HttpStatus.OK
+
+                on("calling statusResponse") {
+                    val result = Responses.statusResponse(status, message, httpStatus)
+                    val json = result.content.value as JsonObject
+
+                    it ("should have OK status") {
+                        assertThat(result.status).isEqualTo(HttpStatus.OK)
+                    }
+
+                    it ("should have json body") {
+                        assertThat(result.content.type).isEqualTo(ContentType.JSON)
+                    }
+
+                    it ("should contain status as string") {
+                        assertThat(json.getString("status")).isEqualTo(status)
+                    }
+
+                    it ("should contain message") {
+                        assertThat(json.getString("message")).isEqualTo(message)
+                    }
+                }
+            }
+
+            given("default params are omitted") {
+                val status = "ok"
+                val message = "good job"
+
+                on("calling statusResponse") {
+                    val result = Responses.statusResponse(status, message)
+
+                    it ("should have OK status") {
+                        assertThat(result.status).isEqualTo(HttpStatus.OK)
+                    }
+                }
+            }
+        }
+    }
+})