Skip to content

Commit 86b8acb

Browse files
committed
La til tester for felles helsesjekk-lib
1 parent 34bc1e7 commit 86b8acb

File tree

10 files changed

+383
-103
lines changed

10 files changed

+383
-103
lines changed

lib/error-handling/build.gradle.kts

+8
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@ dependencies {
99

1010
// Test
1111
testImplementation(testLibs.bundles.withUnitTesting)
12+
testImplementation(ktorServer.testJvm)
13+
testImplementation(ktorServer.contentNegotiation)
14+
testImplementation(ktorServer.statusPages)
15+
testImplementation(ktor.serializationJackson)
16+
testImplementation(ktorClient.contentNegotiation)
17+
testImplementation(ktorServer.core)
18+
testImplementation(orgApacheKafka.kafkaStreams)
19+
testImplementation(loggingLibs.logbackClassic)
1220
}
1321

1422
tasks.withType<Test>().configureEach {

lib/error-handling/src/main/kotlin/no/nav/paw/health/listener/KafkaHealthIndicatorListener.kt

-43
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package no.nav.paw.health.listener
2+
3+
import no.nav.paw.health.model.LivenessHealthIndicator
4+
import no.nav.paw.health.model.ReadinessHealthIndicator
5+
import org.apache.kafka.streams.KafkaStreams
6+
import org.slf4j.LoggerFactory
7+
8+
private val logger = LoggerFactory.getLogger("paw.application.health.kafka")
9+
10+
fun KafkaStreams.withHealthIndicatorStateListener(
11+
livenessIndicator: LivenessHealthIndicator,
12+
readinessIndicator: ReadinessHealthIndicator
13+
) = KafkaStreams.StateListener { newState, previousState ->
14+
when (newState) {
15+
KafkaStreams.State.CREATED -> {
16+
readinessIndicator.setUnhealthy()
17+
livenessIndicator.setHealthy()
18+
}
19+
20+
KafkaStreams.State.RUNNING -> {
21+
readinessIndicator.setHealthy()
22+
livenessIndicator.setHealthy()
23+
}
24+
25+
KafkaStreams.State.REBALANCING -> {
26+
readinessIndicator.setHealthy()
27+
livenessIndicator.setHealthy()
28+
}
29+
30+
KafkaStreams.State.PENDING_ERROR -> {
31+
readinessIndicator.setUnhealthy()
32+
livenessIndicator.setHealthy()
33+
}
34+
35+
KafkaStreams.State.ERROR -> {
36+
readinessIndicator.setUnhealthy()
37+
livenessIndicator.setUnhealthy()
38+
}
39+
40+
KafkaStreams.State.PENDING_SHUTDOWN -> {
41+
readinessIndicator.setUnhealthy()
42+
livenessIndicator.setUnhealthy()
43+
}
44+
45+
KafkaStreams.State.NOT_RUNNING -> {
46+
readinessIndicator.setUnhealthy()
47+
livenessIndicator.setUnhealthy()
48+
}
49+
50+
else -> {
51+
readinessIndicator.setUnknown()
52+
livenessIndicator.setUnknown()
53+
}
54+
}
55+
56+
logger.debug("Kafka Streams state endret seg ${previousState.name} -> ${newState.name}")
57+
logger.info("Kafka Streams liveness er ${livenessIndicator.getStatus().value}")
58+
logger.info("Kafka Streams readiness er ${readinessIndicator.getStatus().value}")
59+
}

lib/error-handling/src/main/kotlin/no/nav/paw/health/model/Health.kt

+33-13
Original file line numberDiff line numberDiff line change
@@ -8,30 +8,50 @@ enum class HealthStatus(val value: String) {
88
UNHEALTHY("UNHEALTHY"),
99
}
1010

11-
interface HealthIndicator {
12-
fun setUnknown()
13-
fun setHealthy()
14-
fun setUnhealthy()
15-
fun getStatus(): HealthStatus
16-
}
17-
18-
class StandardHealthIndicator(initialStatus: HealthStatus) : HealthIndicator {
11+
open class HealthIndicator(initialStatus: HealthStatus) {
1912

2013
private val status = AtomicReference(initialStatus)
2114

22-
override fun setUnknown() {
15+
fun setUnknown() {
2316
status.set(HealthStatus.UNKNOWN)
2417
}
2518

26-
override fun setHealthy() {
19+
fun setHealthy() {
2720
status.set(HealthStatus.HEALTHY)
2821
}
2922

30-
override fun setUnhealthy() {
23+
fun setUnhealthy() {
3124
status.set(HealthStatus.UNHEALTHY)
3225
}
3326

34-
override fun getStatus(): HealthStatus {
27+
fun getStatus(): HealthStatus {
3528
return status.get()
3629
}
37-
}
30+
31+
override fun equals(other: Any?): Boolean {
32+
if (this === other) return true
33+
other as HealthIndicator
34+
return status == other.status
35+
}
36+
37+
override fun hashCode(): Int {
38+
return status.hashCode()
39+
}
40+
}
41+
42+
typealias HealthIndicatorList = MutableList<HealthIndicator>
43+
44+
fun HealthIndicatorList.getAggregatedStatus(): HealthStatus {
45+
return if (this.isEmpty()) {
46+
HealthStatus.UNKNOWN
47+
} else if (this.all { it.getStatus() == HealthStatus.HEALTHY }) {
48+
HealthStatus.HEALTHY
49+
} else if (this.any { it.getStatus() == HealthStatus.UNHEALTHY }) {
50+
HealthStatus.UNHEALTHY
51+
} else {
52+
HealthStatus.UNKNOWN
53+
}
54+
}
55+
56+
class ReadinessHealthIndicator(initialStatus: HealthStatus = HealthStatus.UNKNOWN) : HealthIndicator(initialStatus)
57+
class LivenessHealthIndicator(initialStatus: HealthStatus = HealthStatus.HEALTHY) : HealthIndicator(initialStatus)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package no.nav.paw.health.repository
2+
3+
import no.nav.paw.health.model.HealthIndicatorList
4+
import no.nav.paw.health.model.LivenessHealthIndicator
5+
import no.nav.paw.health.model.ReadinessHealthIndicator
6+
7+
class HealthIndicatorRepository {
8+
9+
private val readinessIndicators: HealthIndicatorList = mutableListOf()
10+
private val livenessIndicators: HealthIndicatorList = mutableListOf()
11+
12+
fun addReadinessIndicator(healthIndicator: ReadinessHealthIndicator): ReadinessHealthIndicator {
13+
readinessIndicators.add(healthIndicator)
14+
return healthIndicator
15+
}
16+
17+
fun addLivenessIndicator(healthIndicator: LivenessHealthIndicator): LivenessHealthIndicator {
18+
livenessIndicators.add(healthIndicator)
19+
return healthIndicator
20+
}
21+
22+
fun getReadinessIndicators(): HealthIndicatorList {
23+
return readinessIndicators
24+
}
25+
26+
fun getLivenessIndicators(): HealthIndicatorList {
27+
return livenessIndicators
28+
}
29+
}

lib/error-handling/src/main/kotlin/no/nav/paw/health/route/HealthRoutes.kt

+7-4
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,16 @@ import io.ktor.server.response.respondText
77
import io.ktor.server.routing.Route
88
import io.ktor.server.routing.get
99
import no.nav.paw.health.model.HealthStatus
10-
import no.nav.paw.health.service.HealthIndicatorService
10+
import no.nav.paw.health.model.getAggregatedStatus
11+
import no.nav.paw.health.repository.HealthIndicatorRepository
1112

1213
fun Route.healthRoutes(
13-
healthIndicatorService: HealthIndicatorService,
14+
healthIndicatorRepository: HealthIndicatorRepository,
1415
) {
1516

1617
get("/internal/isAlive") {
17-
when (val status = healthIndicatorService.getLivenessStatus()) {
18+
val livenessIndicators = healthIndicatorRepository.getLivenessIndicators()
19+
when (val status = livenessIndicators.getAggregatedStatus()) {
1820
HealthStatus.HEALTHY -> call.respondText(
1921
ContentType.Text.Plain,
2022
HttpStatusCode.OK
@@ -28,7 +30,8 @@ fun Route.healthRoutes(
2830
}
2931

3032
get("/internal/isReady") {
31-
when (val status = healthIndicatorService.getReadinessStatus()) {
33+
val readinessIndicators = healthIndicatorRepository.getReadinessIndicators()
34+
when (val status = readinessIndicators.getAggregatedStatus()) {
3235
HealthStatus.HEALTHY -> call.respondText(
3336
ContentType.Text.Plain,
3437
HttpStatusCode.OK

lib/error-handling/src/main/kotlin/no/nav/paw/health/service/HealthIndicatorService.kt

-43
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package no.nav.paw.health.listener
2+
3+
import io.kotest.core.spec.style.FreeSpec
4+
import io.kotest.matchers.shouldBe
5+
import io.mockk.mockkClass
6+
import no.nav.paw.health.model.HealthStatus
7+
import no.nav.paw.health.model.LivenessHealthIndicator
8+
import no.nav.paw.health.model.ReadinessHealthIndicator
9+
import no.nav.paw.health.model.getAggregatedStatus
10+
import no.nav.paw.health.repository.HealthIndicatorRepository
11+
import org.apache.kafka.streams.KafkaStreams
12+
13+
class KafkaStreamsStatusListenerTest : FreeSpec({
14+
15+
"Kafka Streams Status Listener skal returnere korrekt helsesjekk-status" {
16+
val kafkaStreams = mockkClass(KafkaStreams::class)
17+
val healthIndicatorRepository = HealthIndicatorRepository()
18+
19+
val liveness = healthIndicatorRepository.addLivenessIndicator(LivenessHealthIndicator())
20+
val readiness = healthIndicatorRepository.addReadinessIndicator(ReadinessHealthIndicator())
21+
22+
val listener = kafkaStreams.withHealthIndicatorStateListener(liveness, readiness)
23+
24+
healthIndicatorRepository.getReadinessIndicators().getAggregatedStatus() shouldBe HealthStatus.UNKNOWN
25+
healthIndicatorRepository.getLivenessIndicators().getAggregatedStatus() shouldBe HealthStatus.HEALTHY
26+
27+
listener.onChange(KafkaStreams.State.CREATED, KafkaStreams.State.CREATED)
28+
29+
healthIndicatorRepository.getReadinessIndicators().getAggregatedStatus() shouldBe HealthStatus.UNHEALTHY
30+
healthIndicatorRepository.getLivenessIndicators().getAggregatedStatus() shouldBe HealthStatus.HEALTHY
31+
32+
listener.onChange(KafkaStreams.State.RUNNING, KafkaStreams.State.RUNNING)
33+
34+
healthIndicatorRepository.getReadinessIndicators().getAggregatedStatus() shouldBe HealthStatus.HEALTHY
35+
healthIndicatorRepository.getLivenessIndicators().getAggregatedStatus() shouldBe HealthStatus.HEALTHY
36+
37+
listener.onChange(KafkaStreams.State.REBALANCING, KafkaStreams.State.REBALANCING)
38+
39+
healthIndicatorRepository.getReadinessIndicators().getAggregatedStatus() shouldBe HealthStatus.HEALTHY
40+
healthIndicatorRepository.getLivenessIndicators().getAggregatedStatus() shouldBe HealthStatus.HEALTHY
41+
42+
listener.onChange(KafkaStreams.State.PENDING_ERROR, KafkaStreams.State.PENDING_ERROR)
43+
44+
healthIndicatorRepository.getReadinessIndicators().getAggregatedStatus() shouldBe HealthStatus.UNHEALTHY
45+
healthIndicatorRepository.getLivenessIndicators().getAggregatedStatus() shouldBe HealthStatus.HEALTHY
46+
47+
listener.onChange(KafkaStreams.State.ERROR, KafkaStreams.State.ERROR)
48+
49+
healthIndicatorRepository.getReadinessIndicators().getAggregatedStatus() shouldBe HealthStatus.UNHEALTHY
50+
healthIndicatorRepository.getLivenessIndicators().getAggregatedStatus() shouldBe HealthStatus.UNHEALTHY
51+
52+
listener.onChange(KafkaStreams.State.PENDING_SHUTDOWN, KafkaStreams.State.PENDING_SHUTDOWN)
53+
54+
healthIndicatorRepository.getReadinessIndicators().getAggregatedStatus() shouldBe HealthStatus.UNHEALTHY
55+
healthIndicatorRepository.getLivenessIndicators().getAggregatedStatus() shouldBe HealthStatus.UNHEALTHY
56+
57+
listener.onChange(KafkaStreams.State.NOT_RUNNING, KafkaStreams.State.NOT_RUNNING)
58+
59+
healthIndicatorRepository.getReadinessIndicators().getAggregatedStatus() shouldBe HealthStatus.UNHEALTHY
60+
healthIndicatorRepository.getLivenessIndicators().getAggregatedStatus() shouldBe HealthStatus.UNHEALTHY
61+
}
62+
})

0 commit comments

Comments
 (0)