All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.http4k.chaos.ChaoticHttpHandler.kt Maven / Gradle / Ivy

There is a newer version: 5.35.2.0
Show newest version
package org.http4k.chaos

import org.http4k.chaos.ChaosBehaviours.ReturnStatus
import org.http4k.core.HttpHandler
import org.http4k.core.Request
import org.http4k.core.Response
import org.http4k.core.Status
import org.http4k.core.Status.Companion.INTERNAL_SERVER_ERROR
import org.http4k.core.Status.Companion.SERVICE_UNAVAILABLE
import org.http4k.core.Uri
import org.http4k.core.then
import org.http4k.filter.ServerFilters.CatchAll
import org.http4k.routing.RoutingHttpHandler
import org.http4k.routing.bind
import org.http4k.routing.routes
import org.http4k.server.ServerConfig
import org.http4k.server.SunHttp
import org.http4k.server.asServer
import java.lang.Integer.MAX_VALUE
import java.util.Random
import kotlin.reflect.KClass

/**
 * Useful for creating HttpHandlers with a built-in Chaos Engine API for enabling and disabling chaos.
 */
abstract class ChaoticHttpHandler : HttpHandler {

    protected abstract val app: HttpHandler

    private val chaosEngine = ChaosEngine()

    fun behave() = chaosEngine.disable()

    fun misbehave(behaviour: Behaviour = ReturnStatus(INTERNAL_SERVER_ERROR)) = chaosEngine.enable(behaviour)

    fun misbehave(stage: Stage) = chaosEngine.enable(stage)

    fun returnStatus(status: Status) = misbehave(ReturnStatus(status))

    override fun invoke(request: Request) = chaosEngine
        .then(CatchAll())
        .then(attachChaosIfSupported())(request)

    private fun attachChaosIfSupported() = try {
        app.withChaosApi(chaosEngine, controlsPath = "/chaos")
    } catch (e: NoClassDefFoundError) {
        routes(
            routes("/chaos" bind { _: Request -> Response(SERVICE_UNAVAILABLE).body(e.stackTraceToString()) }),
            when (app) {
                is RoutingHttpHandler -> app as RoutingHttpHandler
                else -> routes("/{path:.*}" bind app)
            }
        )
    }
}

/**
 * Convert this ChaoticHttpHandler into a running server, defaulting on a port dependent on the classname.
 */
fun ChaoticHttpHandler.start(
    port: Int = this::class.defaultPort, serverConfig: (Int) -> ServerConfig = ::SunHttp
) =
    asServer(serverConfig(port)).start().also {
        println("Started ${this::class.simpleName ?: "server"} on $port")
    }

/**
 * Calculate a random standard port number for a ChaoticHttpHandler using the classname as a seed
 */
val  KClass.defaultPort
    get() = Random((simpleName.hashCode() % MAX_VALUE).toLong()).nextInt(65535 - 10000) + 10000

/**
 * Local URI for this ChaoticHttpHandler
 */
val  KClass.defaultLocalUri get() = Uri.of("http://localhost:$defaultPort")




© 2015 - 2024 Weber Informatics LLC | Privacy Policy