From 86b8acb9bd28a85d6849dcc1521ef18c000e75bc Mon Sep 17 00:00:00 2001 From: Thomas Johansen Date: Thu, 12 Sep 2024 12:43:02 +0200 Subject: [PATCH] La til tester for felles helsesjekk-lib --- lib/error-handling/build.gradle.kts | 8 ++ .../listener/KafkaHealthIndicatorListener.kt | 43 ------ .../listener/KafkaStreamsStatusListener.kt | 59 ++++++++ .../kotlin/no/nav/paw/health/model/Health.kt | 46 +++++-- .../repository/HealthIndicatorRepository.kt | 29 ++++ .../no/nav/paw/health/route/HealthRoutes.kt | 11 +- .../health/service/HealthIndicatorService.kt | 43 ------ .../KafkaStreamsStatusListenerTest.kt | 62 +++++++++ .../HealthIndicatorRepositoryTest.kt | 58 ++++++++ .../nav/paw/health/route/HealthRoutesTest.kt | 127 ++++++++++++++++++ 10 files changed, 383 insertions(+), 103 deletions(-) delete mode 100644 lib/error-handling/src/main/kotlin/no/nav/paw/health/listener/KafkaHealthIndicatorListener.kt create mode 100644 lib/error-handling/src/main/kotlin/no/nav/paw/health/listener/KafkaStreamsStatusListener.kt create mode 100644 lib/error-handling/src/main/kotlin/no/nav/paw/health/repository/HealthIndicatorRepository.kt delete mode 100644 lib/error-handling/src/main/kotlin/no/nav/paw/health/service/HealthIndicatorService.kt create mode 100644 lib/error-handling/src/test/kotlin/no/nav/paw/health/listener/KafkaStreamsStatusListenerTest.kt create mode 100644 lib/error-handling/src/test/kotlin/no/nav/paw/health/repository/HealthIndicatorRepositoryTest.kt create mode 100644 lib/error-handling/src/test/kotlin/no/nav/paw/health/route/HealthRoutesTest.kt diff --git a/lib/error-handling/build.gradle.kts b/lib/error-handling/build.gradle.kts index 1d9f81d1..a925ada9 100644 --- a/lib/error-handling/build.gradle.kts +++ b/lib/error-handling/build.gradle.kts @@ -9,6 +9,14 @@ dependencies { // Test testImplementation(testLibs.bundles.withUnitTesting) + testImplementation(ktorServer.testJvm) + testImplementation(ktorServer.contentNegotiation) + testImplementation(ktorServer.statusPages) + testImplementation(ktor.serializationJackson) + testImplementation(ktorClient.contentNegotiation) + testImplementation(ktorServer.core) + testImplementation(orgApacheKafka.kafkaStreams) + testImplementation(loggingLibs.logbackClassic) } tasks.withType().configureEach { diff --git a/lib/error-handling/src/main/kotlin/no/nav/paw/health/listener/KafkaHealthIndicatorListener.kt b/lib/error-handling/src/main/kotlin/no/nav/paw/health/listener/KafkaHealthIndicatorListener.kt deleted file mode 100644 index 991ded9b..00000000 --- a/lib/error-handling/src/main/kotlin/no/nav/paw/health/listener/KafkaHealthIndicatorListener.kt +++ /dev/null @@ -1,43 +0,0 @@ -package no.nav.paw.health.listener - -import no.nav.paw.health.model.HealthIndicator -import org.apache.kafka.streams.KafkaStreams -import org.slf4j.LoggerFactory - -private val logger = LoggerFactory.getLogger("paw.application.health.kafka") - -fun KafkaStreams.withHealthIndicatorStateListener( - livenessHealthIndicator: HealthIndicator, - readinessHealthIndicator: HealthIndicator -) = KafkaStreams.StateListener { newState, previousState -> - when (newState) { - KafkaStreams.State.RUNNING -> { - readinessHealthIndicator.setHealthy() - } - - KafkaStreams.State.REBALANCING -> { - readinessHealthIndicator.setHealthy() - } - - KafkaStreams.State.PENDING_ERROR -> { - readinessHealthIndicator.setUnhealthy() - } - - KafkaStreams.State.PENDING_SHUTDOWN -> { - readinessHealthIndicator.setUnhealthy() - } - - KafkaStreams.State.ERROR -> { - readinessHealthIndicator.setUnhealthy() - livenessHealthIndicator.setUnhealthy() - } - - else -> { - readinessHealthIndicator.setUnknown() - } - } - - logger.debug("Kafka Streams state endret seg ${previousState.name} -> ${newState.name}") - logger.info("Kafka Streams liveness er ${livenessHealthIndicator.getStatus().value}") - logger.info("Kafka Streams readiness er ${readinessHealthIndicator.getStatus().value}") -} \ No newline at end of file diff --git a/lib/error-handling/src/main/kotlin/no/nav/paw/health/listener/KafkaStreamsStatusListener.kt b/lib/error-handling/src/main/kotlin/no/nav/paw/health/listener/KafkaStreamsStatusListener.kt new file mode 100644 index 00000000..b6f50ff1 --- /dev/null +++ b/lib/error-handling/src/main/kotlin/no/nav/paw/health/listener/KafkaStreamsStatusListener.kt @@ -0,0 +1,59 @@ +package no.nav.paw.health.listener + +import no.nav.paw.health.model.LivenessHealthIndicator +import no.nav.paw.health.model.ReadinessHealthIndicator +import org.apache.kafka.streams.KafkaStreams +import org.slf4j.LoggerFactory + +private val logger = LoggerFactory.getLogger("paw.application.health.kafka") + +fun KafkaStreams.withHealthIndicatorStateListener( + livenessIndicator: LivenessHealthIndicator, + readinessIndicator: ReadinessHealthIndicator +) = KafkaStreams.StateListener { newState, previousState -> + when (newState) { + KafkaStreams.State.CREATED -> { + readinessIndicator.setUnhealthy() + livenessIndicator.setHealthy() + } + + KafkaStreams.State.RUNNING -> { + readinessIndicator.setHealthy() + livenessIndicator.setHealthy() + } + + KafkaStreams.State.REBALANCING -> { + readinessIndicator.setHealthy() + livenessIndicator.setHealthy() + } + + KafkaStreams.State.PENDING_ERROR -> { + readinessIndicator.setUnhealthy() + livenessIndicator.setHealthy() + } + + KafkaStreams.State.ERROR -> { + readinessIndicator.setUnhealthy() + livenessIndicator.setUnhealthy() + } + + KafkaStreams.State.PENDING_SHUTDOWN -> { + readinessIndicator.setUnhealthy() + livenessIndicator.setUnhealthy() + } + + KafkaStreams.State.NOT_RUNNING -> { + readinessIndicator.setUnhealthy() + livenessIndicator.setUnhealthy() + } + + else -> { + readinessIndicator.setUnknown() + livenessIndicator.setUnknown() + } + } + + logger.debug("Kafka Streams state endret seg ${previousState.name} -> ${newState.name}") + logger.info("Kafka Streams liveness er ${livenessIndicator.getStatus().value}") + logger.info("Kafka Streams readiness er ${readinessIndicator.getStatus().value}") +} \ No newline at end of file diff --git a/lib/error-handling/src/main/kotlin/no/nav/paw/health/model/Health.kt b/lib/error-handling/src/main/kotlin/no/nav/paw/health/model/Health.kt index 9f4ae3cb..e68880da 100644 --- a/lib/error-handling/src/main/kotlin/no/nav/paw/health/model/Health.kt +++ b/lib/error-handling/src/main/kotlin/no/nav/paw/health/model/Health.kt @@ -8,30 +8,50 @@ enum class HealthStatus(val value: String) { UNHEALTHY("UNHEALTHY"), } -interface HealthIndicator { - fun setUnknown() - fun setHealthy() - fun setUnhealthy() - fun getStatus(): HealthStatus -} - -class StandardHealthIndicator(initialStatus: HealthStatus) : HealthIndicator { +open class HealthIndicator(initialStatus: HealthStatus) { private val status = AtomicReference(initialStatus) - override fun setUnknown() { + fun setUnknown() { status.set(HealthStatus.UNKNOWN) } - override fun setHealthy() { + fun setHealthy() { status.set(HealthStatus.HEALTHY) } - override fun setUnhealthy() { + fun setUnhealthy() { status.set(HealthStatus.UNHEALTHY) } - override fun getStatus(): HealthStatus { + fun getStatus(): HealthStatus { return status.get() } -} \ No newline at end of file + + override fun equals(other: Any?): Boolean { + if (this === other) return true + other as HealthIndicator + return status == other.status + } + + override fun hashCode(): Int { + return status.hashCode() + } +} + +typealias HealthIndicatorList = MutableList + +fun HealthIndicatorList.getAggregatedStatus(): HealthStatus { + return if (this.isEmpty()) { + HealthStatus.UNKNOWN + } else if (this.all { it.getStatus() == HealthStatus.HEALTHY }) { + HealthStatus.HEALTHY + } else if (this.any { it.getStatus() == HealthStatus.UNHEALTHY }) { + HealthStatus.UNHEALTHY + } else { + HealthStatus.UNKNOWN + } +} + +class ReadinessHealthIndicator(initialStatus: HealthStatus = HealthStatus.UNKNOWN) : HealthIndicator(initialStatus) +class LivenessHealthIndicator(initialStatus: HealthStatus = HealthStatus.HEALTHY) : HealthIndicator(initialStatus) \ No newline at end of file diff --git a/lib/error-handling/src/main/kotlin/no/nav/paw/health/repository/HealthIndicatorRepository.kt b/lib/error-handling/src/main/kotlin/no/nav/paw/health/repository/HealthIndicatorRepository.kt new file mode 100644 index 00000000..85b418cd --- /dev/null +++ b/lib/error-handling/src/main/kotlin/no/nav/paw/health/repository/HealthIndicatorRepository.kt @@ -0,0 +1,29 @@ +package no.nav.paw.health.repository + +import no.nav.paw.health.model.HealthIndicatorList +import no.nav.paw.health.model.LivenessHealthIndicator +import no.nav.paw.health.model.ReadinessHealthIndicator + +class HealthIndicatorRepository { + + private val readinessIndicators: HealthIndicatorList = mutableListOf() + private val livenessIndicators: HealthIndicatorList = mutableListOf() + + fun addReadinessIndicator(healthIndicator: ReadinessHealthIndicator): ReadinessHealthIndicator { + readinessIndicators.add(healthIndicator) + return healthIndicator + } + + fun addLivenessIndicator(healthIndicator: LivenessHealthIndicator): LivenessHealthIndicator { + livenessIndicators.add(healthIndicator) + return healthIndicator + } + + fun getReadinessIndicators(): HealthIndicatorList { + return readinessIndicators + } + + fun getLivenessIndicators(): HealthIndicatorList { + return livenessIndicators + } +} \ No newline at end of file diff --git a/lib/error-handling/src/main/kotlin/no/nav/paw/health/route/HealthRoutes.kt b/lib/error-handling/src/main/kotlin/no/nav/paw/health/route/HealthRoutes.kt index 1337e3af..cc56678f 100644 --- a/lib/error-handling/src/main/kotlin/no/nav/paw/health/route/HealthRoutes.kt +++ b/lib/error-handling/src/main/kotlin/no/nav/paw/health/route/HealthRoutes.kt @@ -7,14 +7,16 @@ import io.ktor.server.response.respondText import io.ktor.server.routing.Route import io.ktor.server.routing.get import no.nav.paw.health.model.HealthStatus -import no.nav.paw.health.service.HealthIndicatorService +import no.nav.paw.health.model.getAggregatedStatus +import no.nav.paw.health.repository.HealthIndicatorRepository fun Route.healthRoutes( - healthIndicatorService: HealthIndicatorService, + healthIndicatorRepository: HealthIndicatorRepository, ) { get("/internal/isAlive") { - when (val status = healthIndicatorService.getLivenessStatus()) { + val livenessIndicators = healthIndicatorRepository.getLivenessIndicators() + when (val status = livenessIndicators.getAggregatedStatus()) { HealthStatus.HEALTHY -> call.respondText( ContentType.Text.Plain, HttpStatusCode.OK @@ -28,7 +30,8 @@ fun Route.healthRoutes( } get("/internal/isReady") { - when (val status = healthIndicatorService.getReadinessStatus()) { + val readinessIndicators = healthIndicatorRepository.getReadinessIndicators() + when (val status = readinessIndicators.getAggregatedStatus()) { HealthStatus.HEALTHY -> call.respondText( ContentType.Text.Plain, HttpStatusCode.OK diff --git a/lib/error-handling/src/main/kotlin/no/nav/paw/health/service/HealthIndicatorService.kt b/lib/error-handling/src/main/kotlin/no/nav/paw/health/service/HealthIndicatorService.kt deleted file mode 100644 index 831ddad9..00000000 --- a/lib/error-handling/src/main/kotlin/no/nav/paw/health/service/HealthIndicatorService.kt +++ /dev/null @@ -1,43 +0,0 @@ -package no.nav.paw.health.service - -import no.nav.paw.health.model.HealthIndicator -import no.nav.paw.health.model.HealthStatus -import no.nav.paw.health.model.StandardHealthIndicator - -class HealthIndicatorService { - - private val readinessIndicators = mutableListOf() - private val livenessIndicators = mutableListOf() - - fun addReadinessIndicator(): HealthIndicator { - val healthIndicator = StandardHealthIndicator(HealthStatus.UNKNOWN) - readinessIndicators.add(healthIndicator) - return healthIndicator - } - - fun addLivenessIndicator(): HealthIndicator { - val healthIndicator = StandardHealthIndicator(HealthStatus.HEALTHY) - livenessIndicators.add(healthIndicator) - return healthIndicator - } - - fun getReadinessStatus(): HealthStatus { - return if (readinessIndicators.all { it.getStatus() == HealthStatus.HEALTHY }) { - HealthStatus.HEALTHY - } else if (readinessIndicators.any { it.getStatus() == HealthStatus.UNHEALTHY }) { - HealthStatus.UNHEALTHY - } else { - HealthStatus.UNKNOWN - } - } - - fun getLivenessStatus(): HealthStatus { - return if (livenessIndicators.all { it.getStatus() == HealthStatus.HEALTHY }) { - HealthStatus.HEALTHY - } else if (livenessIndicators.any { it.getStatus() == HealthStatus.UNHEALTHY }) { - HealthStatus.UNHEALTHY - } else { - HealthStatus.UNKNOWN - } - } -} \ No newline at end of file diff --git a/lib/error-handling/src/test/kotlin/no/nav/paw/health/listener/KafkaStreamsStatusListenerTest.kt b/lib/error-handling/src/test/kotlin/no/nav/paw/health/listener/KafkaStreamsStatusListenerTest.kt new file mode 100644 index 00000000..b9a5f344 --- /dev/null +++ b/lib/error-handling/src/test/kotlin/no/nav/paw/health/listener/KafkaStreamsStatusListenerTest.kt @@ -0,0 +1,62 @@ +package no.nav.paw.health.listener + +import io.kotest.core.spec.style.FreeSpec +import io.kotest.matchers.shouldBe +import io.mockk.mockkClass +import no.nav.paw.health.model.HealthStatus +import no.nav.paw.health.model.LivenessHealthIndicator +import no.nav.paw.health.model.ReadinessHealthIndicator +import no.nav.paw.health.model.getAggregatedStatus +import no.nav.paw.health.repository.HealthIndicatorRepository +import org.apache.kafka.streams.KafkaStreams + +class KafkaStreamsStatusListenerTest : FreeSpec({ + + "Kafka Streams Status Listener skal returnere korrekt helsesjekk-status" { + val kafkaStreams = mockkClass(KafkaStreams::class) + val healthIndicatorRepository = HealthIndicatorRepository() + + val liveness = healthIndicatorRepository.addLivenessIndicator(LivenessHealthIndicator()) + val readiness = healthIndicatorRepository.addReadinessIndicator(ReadinessHealthIndicator()) + + val listener = kafkaStreams.withHealthIndicatorStateListener(liveness, readiness) + + healthIndicatorRepository.getReadinessIndicators().getAggregatedStatus() shouldBe HealthStatus.UNKNOWN + healthIndicatorRepository.getLivenessIndicators().getAggregatedStatus() shouldBe HealthStatus.HEALTHY + + listener.onChange(KafkaStreams.State.CREATED, KafkaStreams.State.CREATED) + + healthIndicatorRepository.getReadinessIndicators().getAggregatedStatus() shouldBe HealthStatus.UNHEALTHY + healthIndicatorRepository.getLivenessIndicators().getAggregatedStatus() shouldBe HealthStatus.HEALTHY + + listener.onChange(KafkaStreams.State.RUNNING, KafkaStreams.State.RUNNING) + + healthIndicatorRepository.getReadinessIndicators().getAggregatedStatus() shouldBe HealthStatus.HEALTHY + healthIndicatorRepository.getLivenessIndicators().getAggregatedStatus() shouldBe HealthStatus.HEALTHY + + listener.onChange(KafkaStreams.State.REBALANCING, KafkaStreams.State.REBALANCING) + + healthIndicatorRepository.getReadinessIndicators().getAggregatedStatus() shouldBe HealthStatus.HEALTHY + healthIndicatorRepository.getLivenessIndicators().getAggregatedStatus() shouldBe HealthStatus.HEALTHY + + listener.onChange(KafkaStreams.State.PENDING_ERROR, KafkaStreams.State.PENDING_ERROR) + + healthIndicatorRepository.getReadinessIndicators().getAggregatedStatus() shouldBe HealthStatus.UNHEALTHY + healthIndicatorRepository.getLivenessIndicators().getAggregatedStatus() shouldBe HealthStatus.HEALTHY + + listener.onChange(KafkaStreams.State.ERROR, KafkaStreams.State.ERROR) + + healthIndicatorRepository.getReadinessIndicators().getAggregatedStatus() shouldBe HealthStatus.UNHEALTHY + healthIndicatorRepository.getLivenessIndicators().getAggregatedStatus() shouldBe HealthStatus.UNHEALTHY + + listener.onChange(KafkaStreams.State.PENDING_SHUTDOWN, KafkaStreams.State.PENDING_SHUTDOWN) + + healthIndicatorRepository.getReadinessIndicators().getAggregatedStatus() shouldBe HealthStatus.UNHEALTHY + healthIndicatorRepository.getLivenessIndicators().getAggregatedStatus() shouldBe HealthStatus.UNHEALTHY + + listener.onChange(KafkaStreams.State.NOT_RUNNING, KafkaStreams.State.NOT_RUNNING) + + healthIndicatorRepository.getReadinessIndicators().getAggregatedStatus() shouldBe HealthStatus.UNHEALTHY + healthIndicatorRepository.getLivenessIndicators().getAggregatedStatus() shouldBe HealthStatus.UNHEALTHY + } +}) \ No newline at end of file diff --git a/lib/error-handling/src/test/kotlin/no/nav/paw/health/repository/HealthIndicatorRepositoryTest.kt b/lib/error-handling/src/test/kotlin/no/nav/paw/health/repository/HealthIndicatorRepositoryTest.kt new file mode 100644 index 00000000..c98219e1 --- /dev/null +++ b/lib/error-handling/src/test/kotlin/no/nav/paw/health/repository/HealthIndicatorRepositoryTest.kt @@ -0,0 +1,58 @@ +package no.nav.paw.health.repository + +import io.kotest.core.spec.style.FreeSpec +import io.kotest.matchers.shouldBe +import no.nav.paw.health.model.HealthStatus +import no.nav.paw.health.model.LivenessHealthIndicator +import no.nav.paw.health.model.ReadinessHealthIndicator +import no.nav.paw.health.model.getAggregatedStatus + +class HealthIndicatorRepositoryTest : FreeSpec({ + + "Skal returnere korrekt helsesjekk-status" { + val healthIndicatorRepository = HealthIndicatorRepository() + + val liveness1 = healthIndicatorRepository.addLivenessIndicator(LivenessHealthIndicator()) + val liveness2 = healthIndicatorRepository.addLivenessIndicator(LivenessHealthIndicator()) + val liveness3 = healthIndicatorRepository.addLivenessIndicator(LivenessHealthIndicator()) + + val readiness1 = healthIndicatorRepository.addReadinessIndicator(ReadinessHealthIndicator()) + val readiness2 = healthIndicatorRepository.addReadinessIndicator(ReadinessHealthIndicator()) + val readiness3 = healthIndicatorRepository.addReadinessIndicator(ReadinessHealthIndicator()) + + healthIndicatorRepository.getReadinessIndicators().getAggregatedStatus() shouldBe HealthStatus.UNKNOWN + healthIndicatorRepository.getLivenessIndicators().getAggregatedStatus() shouldBe HealthStatus.HEALTHY + + readiness1.setUnhealthy() + liveness1.setUnhealthy() + + healthIndicatorRepository.getReadinessIndicators().getAggregatedStatus() shouldBe HealthStatus.UNHEALTHY + healthIndicatorRepository.getLivenessIndicators().getAggregatedStatus() shouldBe HealthStatus.UNHEALTHY + + readiness2.setUnhealthy() + readiness3.setUnhealthy() + liveness2.setUnhealthy() + liveness3.setUnhealthy() + + healthIndicatorRepository.getReadinessIndicators().getAggregatedStatus() shouldBe HealthStatus.UNHEALTHY + healthIndicatorRepository.getLivenessIndicators().getAggregatedStatus() shouldBe HealthStatus.UNHEALTHY + + readiness1.setHealthy() + liveness1.setHealthy() + + healthIndicatorRepository.getReadinessIndicators().getAggregatedStatus() shouldBe HealthStatus.UNHEALTHY + healthIndicatorRepository.getLivenessIndicators().getAggregatedStatus() shouldBe HealthStatus.UNHEALTHY + + readiness2.setHealthy() + liveness2.setHealthy() + + healthIndicatorRepository.getReadinessIndicators().getAggregatedStatus() shouldBe HealthStatus.UNHEALTHY + healthIndicatorRepository.getLivenessIndicators().getAggregatedStatus() shouldBe HealthStatus.UNHEALTHY + + readiness3.setHealthy() + liveness3.setHealthy() + + healthIndicatorRepository.getReadinessIndicators().getAggregatedStatus() shouldBe HealthStatus.HEALTHY + healthIndicatorRepository.getLivenessIndicators().getAggregatedStatus() shouldBe HealthStatus.HEALTHY + } +}) \ No newline at end of file diff --git a/lib/error-handling/src/test/kotlin/no/nav/paw/health/route/HealthRoutesTest.kt b/lib/error-handling/src/test/kotlin/no/nav/paw/health/route/HealthRoutesTest.kt new file mode 100644 index 00000000..9d80fa75 --- /dev/null +++ b/lib/error-handling/src/test/kotlin/no/nav/paw/health/route/HealthRoutesTest.kt @@ -0,0 +1,127 @@ +package no.nav.paw.health.route + +import io.kotest.core.spec.style.FreeSpec +import io.kotest.matchers.shouldBe +import io.ktor.client.call.body +import io.ktor.client.request.get +import io.ktor.http.HttpStatusCode +import io.ktor.serialization.jackson.jackson +import io.ktor.server.plugins.statuspages.StatusPages +import io.ktor.server.routing.IgnoreTrailingSlash +import io.ktor.server.routing.routing +import io.ktor.server.testing.testApplication +import no.nav.paw.health.model.HealthStatus +import no.nav.paw.health.model.LivenessHealthIndicator +import no.nav.paw.health.model.ReadinessHealthIndicator +import no.nav.paw.health.repository.HealthIndicatorRepository +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation as ClientContentNegotiation +import io.ktor.server.application.install as serverInstall +import io.ktor.server.plugins.contentnegotiation.ContentNegotiation as ServerContentNegotiation + +class HealthRoutesTest : FreeSpec({ + + "Endepunkter for helsesjekk skal returnere korrekt helsesjekk-status" { + + val healthIndicatorRepository = HealthIndicatorRepository() + + testApplication { + application { + serverInstall(IgnoreTrailingSlash) + serverInstall(StatusPages) + serverInstall(ServerContentNegotiation) { + jackson {} + } + routing { + healthRoutes(healthIndicatorRepository) + } + } + + val client = createClient { + install(ClientContentNegotiation) { + jackson {} + } + } + + val livenessResponse1 = client.get("/internal/isAlive") + val readinessResponse1 = client.get("/internal/isReady") + + livenessResponse1.status shouldBe HttpStatusCode.ServiceUnavailable + livenessResponse1.body() shouldBe HealthStatus.UNKNOWN.value + readinessResponse1.status shouldBe HttpStatusCode.ServiceUnavailable + readinessResponse1.body() shouldBe HealthStatus.UNKNOWN.value + + val liveness1 = healthIndicatorRepository.addLivenessIndicator(LivenessHealthIndicator()) + val liveness2 = healthIndicatorRepository.addLivenessIndicator(LivenessHealthIndicator()) + val liveness3 = healthIndicatorRepository.addLivenessIndicator(LivenessHealthIndicator()) + + val readiness1 = healthIndicatorRepository.addReadinessIndicator(ReadinessHealthIndicator()) + val readiness2 = healthIndicatorRepository.addReadinessIndicator(ReadinessHealthIndicator()) + val readiness3 = healthIndicatorRepository.addReadinessIndicator(ReadinessHealthIndicator()) + + val livenessResponse2 = client.get("/internal/isAlive") + val readinessResponse2 = client.get("/internal/isReady") + + livenessResponse2.status shouldBe HttpStatusCode.OK + livenessResponse2.body() shouldBe HealthStatus.HEALTHY.value + readinessResponse2.status shouldBe HttpStatusCode.ServiceUnavailable + readinessResponse2.body() shouldBe HealthStatus.UNKNOWN.value + + readiness1.setUnhealthy() + liveness1.setUnhealthy() + + val livenessResponse3 = client.get("/internal/isAlive") + val readinessResponse3 = client.get("/internal/isReady") + + livenessResponse3.status shouldBe HttpStatusCode.ServiceUnavailable + livenessResponse3.body() shouldBe HealthStatus.UNHEALTHY.value + readinessResponse3.status shouldBe HttpStatusCode.ServiceUnavailable + readinessResponse3.body() shouldBe HealthStatus.UNHEALTHY.value + + readiness2.setUnhealthy() + readiness3.setUnhealthy() + liveness2.setUnhealthy() + liveness3.setUnhealthy() + + val livenessResponse4 = client.get("/internal/isAlive") + val readinessResponse4 = client.get("/internal/isReady") + + livenessResponse4.status shouldBe HttpStatusCode.ServiceUnavailable + livenessResponse4.body() shouldBe HealthStatus.UNHEALTHY.value + readinessResponse4.status shouldBe HttpStatusCode.ServiceUnavailable + readinessResponse4.body() shouldBe HealthStatus.UNHEALTHY.value + + readiness1.setHealthy() + liveness1.setHealthy() + + val livenessResponse5 = client.get("/internal/isAlive") + val readinessResponse5 = client.get("/internal/isReady") + + livenessResponse5.status shouldBe HttpStatusCode.ServiceUnavailable + livenessResponse5.body() shouldBe HealthStatus.UNHEALTHY.value + readinessResponse5.status shouldBe HttpStatusCode.ServiceUnavailable + readinessResponse5.body() shouldBe HealthStatus.UNHEALTHY.value + + readiness2.setHealthy() + liveness2.setHealthy() + + val livenessResponse6 = client.get("/internal/isAlive") + val readinessResponse6 = client.get("/internal/isReady") + + livenessResponse6.status shouldBe HttpStatusCode.ServiceUnavailable + livenessResponse6.body() shouldBe HealthStatus.UNHEALTHY.value + readinessResponse6.status shouldBe HttpStatusCode.ServiceUnavailable + readinessResponse6.body() shouldBe HealthStatus.UNHEALTHY.value + + readiness3.setHealthy() + liveness3.setHealthy() + + val livenessResponse7 = client.get("/internal/isAlive") + val readinessResponse7 = client.get("/internal/isReady") + + livenessResponse7.status shouldBe HttpStatusCode.OK + livenessResponse7.body() shouldBe HealthStatus.HEALTHY.value + readinessResponse7.status shouldBe HttpStatusCode.OK + readinessResponse7.body() shouldBe HealthStatus.HEALTHY.value + } + } +}) \ No newline at end of file