diff options
Diffstat (limited to 'sources/hv-collector-utils/src')
16 files changed, 1415 insertions, 0 deletions
diff --git a/sources/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/arrow/core.kt b/sources/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/arrow/core.kt new file mode 100644 index 00000000..7381592d --- /dev/null +++ b/sources/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/arrow/core.kt @@ -0,0 +1,47 @@ +/* + * ============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.arrow + +import arrow.core.Either +import arrow.core.Option +import arrow.core.identity +import arrow.syntax.collections.firstOption +import java.util.concurrent.atomic.AtomicReference + +/** + * @author Piotr Jaszczyk <piotr.jaszczyk@nokia.com> + * @since July 2018 + */ + +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> = + if (firstValue != null) + Option.just(firstValue) + else nextValues.asSequence() + .map { it() } + .filter { it != null } + .firstOption() diff --git a/sources/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/arrow/effects.kt b/sources/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/arrow/effects.kt new file mode 100644 index 00000000..05d13094 --- /dev/null +++ b/sources/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/arrow/effects.kt @@ -0,0 +1,69 @@ +/* + * ============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.arrow + +import arrow.core.Either +import arrow.core.Left +import arrow.core.Right +import arrow.effects.IO +import reactor.core.publisher.Flux +import reactor.core.publisher.Mono +import kotlin.system.exitProcess + +/** + * @author Piotr Jaszczyk <piotr.jaszczyk@nokia.com> + * @since June 2018 + */ + +sealed class ExitCode { + abstract val code: Int + + fun io() = IO { + exitProcess(code) + } +} + +object ExitSuccess : ExitCode() { + override val code = 0 +} + +data class ExitFailure(override val code: Int) : ExitCode() + +fun Either<IO<Unit>, IO<Unit>>.unsafeRunEitherSync(onError: (Throwable) -> ExitCode, onSuccess: () -> Unit) = + flatten().attempt().unsafeRunSync().fold({ onError(it).io().unsafeRunSync() }, { onSuccess() }) + + +fun IO<Any>.unit() = map { Unit } + +fun <T> Mono<T>.asIo() = IO.async<T> { callback -> + subscribe({ + callback(Right(it)) + }, { + callback(Left(it)) + }) +} + +fun <T> Flux<IO<T>>.evaluateIo(): Flux<T> = + flatMap { io -> + io.attempt().unsafeRunSync().fold( + { Flux.error<T>(it) }, + { Flux.just<T>(it) } + ) + } diff --git a/sources/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/commandline/ArgBasedConfiguration.kt b/sources/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/commandline/ArgBasedConfiguration.kt new file mode 100644 index 00000000..b14f1be5 --- /dev/null +++ b/sources/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/commandline/ArgBasedConfiguration.kt @@ -0,0 +1,57 @@ +/* + * ============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.commandline + +import arrow.core.Either +import arrow.core.Option +import arrow.core.Try +import arrow.core.flatMap +import org.apache.commons.cli.CommandLine +import org.apache.commons.cli.CommandLineParser +import org.apache.commons.cli.Options +import java.io.File +import java.nio.file.Path +import java.nio.file.Paths + +abstract class ArgBasedConfiguration<T>(private val parser: CommandLineParser) { + abstract val cmdLineOptionsList: List<CommandLineOption> + + fun parse(args: Array<out String>): Either<WrongArgumentError, T> { + val parseResult = Try { + val commandLineOptions = cmdLineOptionsList.map { it.option }.fold(Options(), Options::addOption) + parser.parse(commandLineOptions, args) + } + return parseResult + .toEither() + .mapLeft { ex -> WrongArgumentError(ex, cmdLineOptionsList) } + .map(this::getConfiguration) + .flatMap { + it.toEither { + WrongArgumentError( + message = "Unexpected error when parsing command line arguments", + cmdLineOptionsList = cmdLineOptionsList) + } + } + } + + protected abstract fun getConfiguration(cmdLine: CommandLine): Option<T> + + protected fun stringPathToPath(path: String): Path = Paths.get(File(path).toURI()) +} diff --git a/sources/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/commandline/CommandLineOption.kt b/sources/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/commandline/CommandLineOption.kt new file mode 100644 index 00000000..9439bff5 --- /dev/null +++ b/sources/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/commandline/CommandLineOption.kt @@ -0,0 +1,142 @@ +/* + * ============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.commandline + +import org.apache.commons.cli.Option + + +enum class CommandLineOption(val option: Option, val required: Boolean = false) { + HEALTH_CHECK_API_PORT(Option.builder("H") + .longOpt("health-check-api-port") + .hasArg() + .desc("Health check rest api listen port") + .build() + ), + LISTEN_PORT(Option.builder("p") + .longOpt("listen-port") + .hasArg() + .desc("Listen port") + .build(), + required = true + ), + CONSUL_CONFIG_URL(Option.builder("c") + .longOpt("config-url") + .hasArg() + .desc("URL of ves configuration on consul") + .build(), + required = true + ), + CONSUL_FIRST_REQUEST_DELAY(Option.builder("d") + .longOpt("first-request-delay") + .hasArg() + .desc("Delay of first request to consul in seconds") + .build() + ), + CONSUL_REQUEST_INTERVAL(Option.builder("I") + .longOpt("request-interval") + .hasArg() + .desc("Interval of consul configuration requests in seconds") + .build() + ), + VES_HV_PORT(Option.builder("v") + .longOpt("ves-port") + .hasArg() + .desc("VesHvCollector port") + .build(), + required = true + ), + VES_HV_HOST(Option.builder("h") + .longOpt("ves-host") + .hasArg() + .desc("VesHvCollector host") + .build(), + required = true + ), + KAFKA_SERVERS(Option.builder("s") + .longOpt("kafka-bootstrap-servers") + .hasArg() + .desc("Comma-separated Kafka bootstrap servers in <host>:<port> format") + .build(), + required = true + ), + KAFKA_TOPICS(Option.builder("f") + .longOpt("kafka-topics") + .hasArg() + .desc("Comma-separated Kafka topics") + .build(), + required = true + ), + SSL_DISABLE(Option.builder("l") + .longOpt("ssl-disable") + .desc("Disable SSL encryption") + .build() + ), + KEY_STORE_FILE(Option.builder("k") + .longOpt("key-store") + .hasArg() + .desc("Key store in PKCS12 format") + .build() + ), + KEY_STORE_PASSWORD(Option.builder("kp") + .longOpt("key-store-password") + .hasArg() + .desc("Key store password") + .build() + ), + TRUST_STORE_FILE(Option.builder("t") + .longOpt("trust-store") + .hasArg() + .desc("File with trusted certificate bundle in PKCS12 format") + .build() + ), + TRUST_STORE_PASSWORD(Option.builder("tp") + .longOpt("trust-store-password") + .hasArg() + .desc("Trust store password") + .build() + ), + IDLE_TIMEOUT_SEC(Option.builder("i") + .longOpt("idle-timeout-sec") + .hasArg() + .desc("""Idle timeout for remote hosts. After given time without any data exchange the + |connection might be closed.""".trimMargin()) + .build() + ), + MAXIMUM_PAYLOAD_SIZE_BYTES(Option.builder("m") + .longOpt("max-payload-size") + .hasArg() + .desc("Maximum supported payload size in bytes") + .build() + ), + DUMMY_MODE(Option.builder("u") + .longOpt("dummy") + .desc("If present will start in dummy mode (dummy external services)") + .build() + ); + + fun environmentVariableName(prefix: String = DEFAULT_ENV_PREFIX): String = + option.longOpt.toUpperCase().replace('-', '_').let { mainPart -> + "${prefix}_${mainPart}" + } + + companion object { + private const val DEFAULT_ENV_PREFIX = "VESHV" + } +} diff --git a/sources/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/commandline/WrongArgumentError.kt b/sources/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/commandline/WrongArgumentError.kt new file mode 100644 index 00000000..9c2a20c1 --- /dev/null +++ b/sources/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/commandline/WrongArgumentError.kt @@ -0,0 +1,70 @@ +/* + * ============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.commandline + +import arrow.core.Option +import org.apache.commons.cli.HelpFormatter +import org.apache.commons.cli.Options + + +data class WrongArgumentError( + val message: String, + val cause: Throwable? = null, + val cmdLineOptionsList: List<CommandLineOption>) { + + constructor(par: Throwable, cmdLineOptionsList: List<CommandLineOption>) : + this(par.message ?: "", + par, + cmdLineOptionsList) + + fun printMessage() { + println(message) + } + + fun printHelp(programName: String) { + val formatter = HelpFormatter() + val footer = "All parameters can be specified as environment variables using upper-snake-case full " + + "name with prefix `VESHV_`." + + formatter.printHelp( + programName, + generateRequiredParametersNote(cmdLineOptionsList), + getOptions(), + footer) + } + + private fun getOptions() = cmdLineOptionsList.map { it.option }.fold(Options(), Options::addOption) + + companion object { + fun generateRequiredParametersNote(cmdLineOptionsList: List<CommandLineOption>): String { + val requiredParams = Option.fromNullable(cmdLineOptionsList.filter { it.required } + .takeUnless { it.isEmpty() }) + return requiredParams.fold( + { "" }, + { + it.map { commandLineOption -> commandLineOption.option.opt } + .joinToString(prefix = "Required parameters: ", separator = ", ") + } + ) + } + } + +} + diff --git a/sources/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/commandline/extensions.kt b/sources/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/commandline/extensions.kt new file mode 100644 index 00000000..a8414472 --- /dev/null +++ b/sources/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/commandline/extensions.kt @@ -0,0 +1,66 @@ +/* + * ============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.commandline + +import arrow.core.Option +import arrow.core.getOrElse +import arrow.effects.IO +import arrow.syntax.function.curried +import org.apache.commons.cli.CommandLine +import org.onap.dcae.collectors.veshv.utils.arrow.ExitFailure +import org.onap.dcae.collectors.veshv.utils.arrow.fromNullablesChain + +/** + * @author Piotr Jaszczyk <piotr.jaszczyk@nokia.com> + * @since June 2018 + */ + +fun handleWrongArgumentError(programName: String, err: WrongArgumentError): IO<Unit> = IO { + err.printMessage() + err.printHelp(programName) +}.flatMap { ExitFailure(2).io() } + +val handleWrongArgumentErrorCurried = ::handleWrongArgumentError.curried() + +fun CommandLine.longValue(cmdLineOpt: CommandLineOption, default: Long): Long = + longValue(cmdLineOpt).getOrElse { default } + +fun CommandLine.stringValue(cmdLineOpt: CommandLineOption, default: String): String = + optionValue(cmdLineOpt).getOrElse { default } + +fun CommandLine.intValue(cmdLineOpt: CommandLineOption, default: Int): Int = + intValue(cmdLineOpt).getOrElse { default } + +fun CommandLine.intValue(cmdLineOpt: CommandLineOption): Option<Int> = + optionValue(cmdLineOpt).map(String::toInt) + +fun CommandLine.longValue(cmdLineOpt: CommandLineOption): Option<Long> = + optionValue(cmdLineOpt).map(String::toLong) + +fun CommandLine.stringValue(cmdLineOpt: CommandLineOption): Option<String> = + optionValue(cmdLineOpt) + +fun CommandLine.hasOption(cmdLineOpt: CommandLineOption): Boolean = + this.hasOption(cmdLineOpt.option.opt) || + System.getenv(cmdLineOpt.environmentVariableName()) != null + +private fun CommandLine.optionValue(cmdLineOpt: CommandLineOption) = Option.fromNullablesChain( + getOptionValue(cmdLineOpt.option.opt), + { System.getenv(cmdLineOpt.environmentVariableName()) }) diff --git a/sources/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/http/http.kt b/sources/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/http/http.kt new file mode 100644 index 00000000..c5c46397 --- /dev/null +++ b/sources/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/sources/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/http/ratpack.kt b/sources/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/http/ratpack.kt new file mode 100644 index 00000000..0282d0c7 --- /dev/null +++ b/sources/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/sources/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/logging/Logger.kt b/sources/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/logging/Logger.kt new file mode 100644 index 00000000..033dd5e5 --- /dev/null +++ b/sources/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/logging/Logger.kt @@ -0,0 +1,137 @@ +/* + * ============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.logging + +import kotlin.reflect.KClass +import org.slf4j.LoggerFactory + +@Suppress("TooManyFunctions", "SuboptimalLoggerUsage") +class Logger(val logger: org.slf4j.Logger) { + constructor(clazz: KClass<out Any>) : this(LoggerFactory.getLogger(clazz.java)) + constructor(name: String) : this(LoggerFactory.getLogger(name)) + + // + // TRACE + // + + val traceEnabled: Boolean + get() = logger.isTraceEnabled + + fun trace(messageProvider: () -> String) { + if (logger.isTraceEnabled) { + logger.trace(messageProvider()) + } + } + + // + // DEBUG + // + + fun debug(message: String) { + logger.debug(message) + } + + fun debug(message: String, t: Throwable) { + logger.debug(message, t) + } + + fun debug(messageProvider: () -> String) { + if (logger.isDebugEnabled) { + logger.debug(messageProvider()) + } + } + + fun debug(t: Throwable, messageProvider: () -> String) { + if (logger.isDebugEnabled) { + logger.debug(messageProvider(), t) + } + } + + // + // INFO + // + fun info(message: String) { + logger.info(message) + } + + fun info(messageProvider: () -> String) { + if (logger.isInfoEnabled) { + logger.info(messageProvider()) + } + } + + fun info(message: String, t: Throwable) { + logger.info(message, t) + } + + fun info(t: Throwable, messageProvider: () -> String) { + if (logger.isInfoEnabled) { + logger.info(messageProvider(), t) + } + } + + // + // WARN + // + + fun warn(message: String) { + logger.warn(message) + } + + fun warn(message: String, t: Throwable) { + logger.warn(message, t) + } + + fun warn(messageProvider: () -> String) { + if (logger.isWarnEnabled) { + logger.warn(messageProvider()) + } + } + + fun warn(t: Throwable, messageProvider: () -> String) { + if (logger.isWarnEnabled) { + logger.warn(messageProvider(), t) + } + } + + // + // ERROR + // + + fun error(message: String) { + logger.error(message) + } + + fun error(message: String, t: Throwable) { + logger.error(message, t) + } + + fun error(messageProvider: () -> String) { + if (logger.isErrorEnabled) { + logger.error(messageProvider()) + } + } + + fun error(t: Throwable, messageProvider: () -> String) { + if (logger.isErrorEnabled) { + logger.error(messageProvider(), t) + } + } +} diff --git a/sources/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/logging/reactive_logging.kt b/sources/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/logging/reactive_logging.kt new file mode 100644 index 00000000..714702d3 --- /dev/null +++ b/sources/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/logging/reactive_logging.kt @@ -0,0 +1,28 @@ +/* + * ============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.logging + +import reactor.core.publisher.Flux + +fun <T> Logger.handleReactiveStreamError(ex: Throwable, returnFlux: Flux<T> = Flux.empty()): Flux<T> { + logger.warn("Error while handling message stream: ${ex::class.qualifiedName} (${ex.message})") + logger.debug("Detailed stack trace", ex) + return returnFlux +} diff --git a/sources/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/server_handle.kt b/sources/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/server_handle.kt new file mode 100644 index 00000000..bdb63b68 --- /dev/null +++ b/sources/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/server_handle.kt @@ -0,0 +1,46 @@ +/* + * ============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 + +import arrow.effects.IO +import reactor.netty.DisposableServer + +/** + * @author Piotr Jaszczyk <piotr.jaszczyk@nokia.com> + * @since August 2018 + */ +abstract class ServerHandle(val host: String, val port: Int) { + abstract fun shutdown(): IO<Unit> + abstract fun await(): IO<Unit> +} + +/** + * @author Piotr Jaszczyk <piotr.jaszczyk@nokia.com> + * @since August 2018 + */ +class NettyServerHandle(private val ctx: DisposableServer) : ServerHandle(ctx.host(), ctx.port()) { + override fun shutdown() = IO { + ctx.disposeNow() + } + + override fun await() = IO<Unit> { + ctx.channel().closeFuture().sync() + } +} diff --git a/sources/hv-collector-utils/src/test/kotlin/org/onap/dcae/collectors/veshv/utils/arrow/CoreKtTest.kt b/sources/hv-collector-utils/src/test/kotlin/org/onap/dcae/collectors/veshv/utils/arrow/CoreKtTest.kt new file mode 100644 index 00000000..2eb11b27 --- /dev/null +++ b/sources/hv-collector-utils/src/test/kotlin/org/onap/dcae/collectors/veshv/utils/arrow/CoreKtTest.kt @@ -0,0 +1,141 @@ +/* + * ============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.arrow + +import arrow.core.None +import arrow.core.Option +import arrow.core.Some +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.concurrent.atomic.AtomicReference + + +/** + * @author Piotr Jaszczyk <piotr.jaszczyk></piotr.jaszczyk>@nokia.com> + * @since August 2018 + */ +internal class CoreKtTest : Spek({ + describe("AtomicReference.getOption") { + given("empty atomic reference") { + val atomicReference = AtomicReference<String>() + + on("getOption") { + val result = atomicReference.getOption() + + it("should be None") { + assertThat(result).isEqualTo(None) + } + } + } + given("non-empty atomic reference") { + val initialValue = "reksio" + val atomicReference = AtomicReference(initialValue) + + on("getOption") { + val result = atomicReference.getOption() + + it("should be Some($initialValue)") { + assertThat(result).isEqualTo(Some(initialValue)) + } + } + } + } + + describe("Option.fromNullablesChain") { + given("one non-null element") { + val just = "some text" + on("calling factory") { + val result = Option.fromNullablesChain(just) + + it("should return Some($just)") { + assertThat(result).isEqualTo(Some(just)) + } + } + } + + given("one null element") { + val just: String? = null + on("calling factory") { + val result = Option.fromNullablesChain(just) + + it("should return None") { + assertThat(result).isEqualTo(None) + } + } + } + + given("first non-null element") { + val first = "some text" + val second: String? = null + var secondAskedForValue = false + on("calling factory") { + val result = Option.fromNullablesChain(first, { secondAskedForValue = true; second }) + + it("should return Some($first)") { + assertThat(result).isEqualTo(Some(first)) + } + + it("should have not called second provider (should be lazy)") { + assertThat(secondAskedForValue).isFalse() + } + } + } + + given("two non-null elements") { + val first = "some text" + val second = "another text" + on("calling factory") { + val result = Option.fromNullablesChain(first, { second }) + + it("should return Some($first)") { + assertThat(result).isEqualTo(Some(first)) + } + } + } + + given("two null elements") { + val first: String? = null + val second: String? = null + on("calling factory") { + val result = Option.fromNullablesChain(first, { second }) + + it("should return None") { + assertThat(result).isEqualTo(None) + } + } + } + + given("second non-null element") { + val first: String? = null + val second = "another text" + on("calling factory") { + val result = Option.fromNullablesChain(first, { second }) + + it("should return Some($second)") { + assertThat(result).isEqualTo(Some(second)) + } + } + } + } +}) diff --git a/sources/hv-collector-utils/src/test/kotlin/org/onap/dcae/collectors/veshv/utils/commandline/CommandLineOptionTest.kt b/sources/hv-collector-utils/src/test/kotlin/org/onap/dcae/collectors/veshv/utils/commandline/CommandLineOptionTest.kt new file mode 100644 index 00000000..f36df043 --- /dev/null +++ b/sources/hv-collector-utils/src/test/kotlin/org/onap/dcae/collectors/veshv/utils/commandline/CommandLineOptionTest.kt @@ -0,0 +1,62 @@ +/* + * ============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.commandline + +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 + +/** + * @author Piotr Jaszczyk <piotr.jaszczyk@nokia.com> + * @since September 2018 + */ +class CommandLineOptionTest : Spek({ + describe("command line options enum") { + describe("environment variables") { + given("sample option and prefix") { + val opt = CommandLineOption.KAFKA_SERVERS + val prefix = "CONFIG" + + on("calling environmentVariableName") { + val result = opt.environmentVariableName(prefix) + + it("should return prefixed upper snake cased long option name") { + assertThat(result).isEqualTo("CONFIG_KAFKA_BOOTSTRAP_SERVERS") + } + } + } + + given("sample option without prefix") { + val opt = CommandLineOption.DUMMY_MODE + + on("calling environmentVariableName") { + val result = opt.environmentVariableName() + + it("should return prefixed upper snake cased long option name") { + assertThat(result).isEqualTo("VESHV_DUMMY") + } + } + } + } + } +}) diff --git a/sources/hv-collector-utils/src/test/kotlin/org/onap/dcae/collectors/veshv/utils/commandline/WrongArgumentErrorTest.kt b/sources/hv-collector-utils/src/test/kotlin/org/onap/dcae/collectors/veshv/utils/commandline/WrongArgumentErrorTest.kt new file mode 100644 index 00000000..63d9eb82 --- /dev/null +++ b/sources/hv-collector-utils/src/test/kotlin/org/onap/dcae/collectors/veshv/utils/commandline/WrongArgumentErrorTest.kt @@ -0,0 +1,61 @@ +/* + * ============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.commandline + +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 org.onap.dcae.collectors.veshv.utils.commandline.CommandLineOption.HEALTH_CHECK_API_PORT +import org.onap.dcae.collectors.veshv.utils.commandline.CommandLineOption.LISTEN_PORT + +class WrongArgumentErrorTest : Spek ({ + + describe("help message logic test") { + + given("at least one required option") { + val filledOptionList = listOf( + HEALTH_CHECK_API_PORT, + LISTEN_PORT) + on("help message preparation") { + val requiredParameters = WrongArgumentError.generateRequiredParametersNote(filledOptionList) + + it("should print out required fields") { + assertThat(requiredParameters).isEqualTo("Required parameters: p") + } + } + } + + given("no required option") { + val filledOptionList = listOf(HEALTH_CHECK_API_PORT) + + on("help message preparation") { + val requiredParameters = WrongArgumentError.generateRequiredParametersNote(filledOptionList) + + it("should not print required fields") { + assertThat(requiredParameters).isEqualTo("") + } + } + } + } + +})
\ No newline at end of file diff --git a/sources/hv-collector-utils/src/test/kotlin/org/onap/dcae/collectors/veshv/utils/http/ResponsesTest.kt b/sources/hv-collector-utils/src/test/kotlin/org/onap/dcae/collectors/veshv/utils/http/ResponsesTest.kt new file mode 100644 index 00000000..f9f716a1 --- /dev/null +++ b/sources/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) + } + } + } + } + } +}) diff --git a/sources/hv-collector-utils/src/test/kotlin/org/onap/dcae/collectors/veshv/utils/logging/LoggerTest.kt b/sources/hv-collector-utils/src/test/kotlin/org/onap/dcae/collectors/veshv/utils/logging/LoggerTest.kt new file mode 100644 index 00000000..c27fb8c8 --- /dev/null +++ b/sources/hv-collector-utils/src/test/kotlin/org/onap/dcae/collectors/veshv/utils/logging/LoggerTest.kt @@ -0,0 +1,230 @@ +/* + * ============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.logging + +import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.verify +import com.nhaarman.mockitokotlin2.verifyNoMoreInteractions +import com.nhaarman.mockitokotlin2.whenever +import org.jetbrains.spek.api.Spek +import org.jetbrains.spek.api.dsl.describe +import org.jetbrains.spek.api.dsl.it + +/** + * @author Piotr Jaszczyk <piotr.jaszczyk@nokia.com> + * @since May 2018 + */ +object LoggerTest : Spek({ + + lateinit var slf4jLogger: org.slf4j.Logger + lateinit var cut: Logger + + beforeEachTest { + slf4jLogger = mock() + cut = Logger(slf4jLogger) + } + + afterEachTest { + verifyNoMoreInteractions(slf4jLogger) + } + + describe("Thin Kotlin logging facade for Slf4j") { + val message = "sample message" + val exception = Exception("fail") + + describe("debug levels") { + it("should log message") { + cut.debug(message) + verify(slf4jLogger).debug(message) + } + + it("should log message with exception") { + cut.debug(message, exception) + verify(slf4jLogger).debug(message, exception) + } + + describe("lazy logging message") { + + it("should log when debug is ON") { + whenever(slf4jLogger.isDebugEnabled).thenReturn(true) + cut.debug { message } + verify(slf4jLogger).isDebugEnabled + verify(slf4jLogger).debug(message) + } + + it("should not log when debug is OFF") { + whenever(slf4jLogger.isDebugEnabled).thenReturn(false) + cut.debug { message } + verify(slf4jLogger).isDebugEnabled + } + } + + describe("lazy logging message with exception") { + + it("should log when debug is ON") { + whenever(slf4jLogger.isDebugEnabled).thenReturn(true) + cut.debug(exception) { message } + verify(slf4jLogger).isDebugEnabled + verify(slf4jLogger).debug(message, exception) + } + + it("should not log when debug is OFF") { + whenever(slf4jLogger.isDebugEnabled).thenReturn(false) + cut.debug(exception) { message } + verify(slf4jLogger).isDebugEnabled + } + } + } + + describe("info levels") { + it("should log message") { + cut.info(message) + verify(slf4jLogger).info(message) + } + + it("should log message with exception") { + cut.info(message, exception) + verify(slf4jLogger).info(message, exception) + } + + describe("lazy logging message") { + + it("should log when debug is ON") { + whenever(slf4jLogger.isInfoEnabled).thenReturn(true) + cut.info { message } + verify(slf4jLogger).isInfoEnabled + verify(slf4jLogger).info(message) + } + + it("should not log when debug is OFF") { + whenever(slf4jLogger.isInfoEnabled).thenReturn(false) + cut.info { message } + verify(slf4jLogger).isInfoEnabled + } + } + + describe("lazy logging message with exception") { + + it("should log when debug is ON") { + whenever(slf4jLogger.isInfoEnabled).thenReturn(true) + cut.info(exception) { message } + verify(slf4jLogger).isInfoEnabled + verify(slf4jLogger).info(message, exception) + } + + it("should not log when debug is OFF") { + whenever(slf4jLogger.isInfoEnabled).thenReturn(false) + cut.info(exception) { message } + verify(slf4jLogger).isInfoEnabled + } + } + } + + describe("warning levels") { + it("should log message") { + cut.warn(message) + verify(slf4jLogger).warn(message) + } + + it("should log message with exception") { + cut.warn(message, exception) + verify(slf4jLogger).warn(message, exception) + } + + describe("lazy logging message") { + + it("should log when debug is ON") { + whenever(slf4jLogger.isWarnEnabled).thenReturn(true) + cut.warn { message } + verify(slf4jLogger).isWarnEnabled + verify(slf4jLogger).warn(message) + } + + it("should not log when debug is OFF") { + whenever(slf4jLogger.isWarnEnabled).thenReturn(false) + cut.warn { message } + verify(slf4jLogger).isWarnEnabled + } + } + + describe("lazy logging message with exception") { + + it("should log when debug is ON") { + whenever(slf4jLogger.isWarnEnabled).thenReturn(true) + cut.warn(exception) { message } + verify(slf4jLogger).isWarnEnabled + verify(slf4jLogger).warn(message, exception) + } + + it("should not log when debug is OFF") { + whenever(slf4jLogger.isWarnEnabled).thenReturn(false) + cut.warn(exception) { message } + verify(slf4jLogger).isWarnEnabled + } + } + } + + describe("error levels") { + it("should log message") { + cut.error(message) + verify(slf4jLogger).error(message) + } + + it("should log message with exception") { + cut.error(message, exception) + verify(slf4jLogger).error(message, exception) + } + + describe("lazy logging message") { + + it("should log when debug is ON") { + whenever(slf4jLogger.isErrorEnabled).thenReturn(true) + cut.error { message } + verify(slf4jLogger).isErrorEnabled + verify(slf4jLogger).error(message) + } + + it("should not log when debug is OFF") { + whenever(slf4jLogger.isErrorEnabled).thenReturn(false) + cut.error { message } + verify(slf4jLogger).isErrorEnabled + } + } + + describe("lazy logging message with exception") { + + it("should log when debug is ON") { + whenever(slf4jLogger.isErrorEnabled).thenReturn(true) + cut.error(exception) { message } + verify(slf4jLogger).isErrorEnabled + verify(slf4jLogger).error(message, exception) + } + + it("should not log when debug is OFF") { + whenever(slf4jLogger.isErrorEnabled).thenReturn(false) + cut.error(exception) { message } + verify(slf4jLogger).isErrorEnabled + } + } + } + + + } +}) |