From ec3ccafc4dba428cba640d93525bfe61bbc260e8 Mon Sep 17 00:00:00 2001 From: Fabrice Lecomte Date: Sat, 12 Apr 2025 05:31:24 +0200 Subject: [PATCH] test: limit log level in some tests --- src/test/kotlin/eventDemo/LogHelper.kt | 32 +++ .../projection/GameStateRepositoryTest.kt | 185 ++++++++++-------- 2 files changed, 136 insertions(+), 81 deletions(-) create mode 100644 src/test/kotlin/eventDemo/LogHelper.kt diff --git a/src/test/kotlin/eventDemo/LogHelper.kt b/src/test/kotlin/eventDemo/LogHelper.kt new file mode 100644 index 0000000..fd9cd51 --- /dev/null +++ b/src/test/kotlin/eventDemo/LogHelper.kt @@ -0,0 +1,32 @@ +package eventDemo + +import ch.qos.logback.classic.Level +import ch.qos.logback.classic.Logger +import org.slf4j.LoggerFactory + +inline fun withLogLevel( + vararg logs: Pair, + block: () -> T, +): T { + val originalLevels = + run { + logs.toList().associate { (log, level) -> + val logger = LoggerFactory.getLogger(log) as Logger + log to logger.level + } + } + + logs.forEach { (log, level) -> + val logger = LoggerFactory.getLogger(log) as Logger + logger.level = level + } + + val output = block() + + logs.forEach { (log, level) -> + val logger = LoggerFactory.getLogger(log) as Logger + logger.level = originalLevels[log] + } + + return output +} diff --git a/src/test/kotlin/eventDemo/business/event/projection/GameStateRepositoryTest.kt b/src/test/kotlin/eventDemo/business/event/projection/GameStateRepositoryTest.kt index d7c1f89..1877f0b 100644 --- a/src/test/kotlin/eventDemo/business/event/projection/GameStateRepositoryTest.kt +++ b/src/test/kotlin/eventDemo/business/event/projection/GameStateRepositoryTest.kt @@ -1,6 +1,10 @@ package eventDemo.business.event.projection +import ch.qos.logback.classic.Level +import com.rabbitmq.client.impl.ForgivingExceptionHandler +import com.zaxxer.hikari.pool.ProxyConnection import eventDemo.Tag +import eventDemo.business.command.GameCommandHandler import eventDemo.business.entity.GameId import eventDemo.business.entity.Player import eventDemo.business.event.GameEventHandler @@ -8,6 +12,7 @@ import eventDemo.business.event.event.NewPlayerEvent import eventDemo.business.event.projection.gameState.GameState import eventDemo.business.event.projection.gameState.GameStateRepository import eventDemo.testKoinApplicationWithConfig +import eventDemo.withLogLevel import io.kotest.assertions.nondeterministic.eventually import io.kotest.assertions.nondeterministic.eventuallyConfig import io.kotest.common.KotestInternal @@ -19,6 +24,7 @@ import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.joinAll import kotlinx.coroutines.launch +import org.slf4j.Logger import kotlin.test.assertNotNull import kotlin.time.Duration.Companion.seconds @@ -52,106 +58,123 @@ class GameStateRepositoryTest : } test("get should build the last version of the state") { - val aggregateId = GameId() - testKoinApplicationWithConfig { - val repo = get() - val eventHandler = get() - val projectionBus = get() - - var state: GameState? = null - projectionBus.subscribe { - repo.getLast(aggregateId).also { - state = it - } - } - - eventHandler - .handle(aggregateId) { NewPlayerEvent(aggregateId = aggregateId, player = player1, version = it) } - .also { - eventually(1.seconds) { - assertNotNull(state).players.isNotEmpty() shouldBeEqual true - assertNotNull(state).players shouldBeEqual setOf(player1) - } - } - - eventHandler - .handle(aggregateId) { NewPlayerEvent(aggregateId = aggregateId, player = player2, version = it) } - .also { - eventually(1.seconds) { - assertNotNull(repo.getLast(aggregateId)).also { - assertNotNull(it.players) shouldBeEqual setOf(player1, player2) - } - } - } - } - } - - test("getUntil should build the state until the event") { - repeat(10) { + withLogLevel( + GameCommandHandler::class.java.name to Level.ERROR, + ForgivingExceptionHandler::class.java.name to Level.OFF, + ) { val aggregateId = GameId() testKoinApplicationWithConfig { val repo = get() val eventHandler = get() + val projectionBus = get() + + var state: GameState? = null + projectionBus.subscribe { + repo.getLast(aggregateId).also { + state = it + } + } + + eventHandler + .handle(aggregateId) { NewPlayerEvent(aggregateId = aggregateId, player = player1, version = it) } + .also { + eventually(1.seconds) { + assertNotNull(state).players.isNotEmpty() shouldBeEqual true + assertNotNull(state).players shouldBeEqual setOf(player1) + } + } + + eventHandler + .handle(aggregateId) { NewPlayerEvent(aggregateId = aggregateId, player = player2, version = it) } + .also { + eventually(1.seconds) { + assertNotNull(repo.getLast(aggregateId)).also { + assertNotNull(it.players) shouldBeEqual setOf(player1, player2) + } + } + } + } + } + } + + test("getUntil should build the state until the event") { + withLogLevel( + GameCommandHandler::class.java.name to Level.ERROR, + ForgivingExceptionHandler::class.java.name to Level.OFF, + ProxyConnection::class.java.name to Level.OFF, + Logger.ROOT_LOGGER_NAME to Level.INFO, + ) { + repeat(10) { + val aggregateId = GameId() + testKoinApplicationWithConfig { + val repo = get() + val eventHandler = get() + + val event1 = + eventHandler + .handle(aggregateId) { NewPlayerEvent(aggregateId = aggregateId, player = player1, version = it) } + .also { event1 -> + assertNotNull(repo.getUntil(event1)).also { + assertNotNull(it.players) shouldBeEqual setOf(player1) + } + } - val event1 = eventHandler - .handle(aggregateId) { NewPlayerEvent(aggregateId = aggregateId, player = player1, version = it) } - .also { event1 -> + .handle(aggregateId) { NewPlayerEvent(aggregateId = aggregateId, player = player2, version = it) } + .also { event2 -> + assertNotNull(repo.getUntil(event2)).also { + assertNotNull(it.players) shouldBeEqual setOf(player1, player2) + } assertNotNull(repo.getUntil(event1)).also { assertNotNull(it.players) shouldBeEqual setOf(player1) } } - - eventHandler - .handle(aggregateId) { NewPlayerEvent(aggregateId = aggregateId, player = player2, version = it) } - .also { event2 -> - assertNotNull(repo.getUntil(event2)).also { - assertNotNull(it.players) shouldBeEqual setOf(player1, player2) - } - assertNotNull(repo.getUntil(event1)).also { - assertNotNull(it.players) shouldBeEqual setOf(player1) - } - } + } } } } test("getUntil should be concurrently secure").config(tags = setOf(Tag.Concurrence)) { - val aggregateId = GameId() - testKoinApplicationWithConfig { - val repo = get() - val eventHandler = get() + withLogLevel( + Logger.ROOT_LOGGER_NAME to Level.ERROR, + ForgivingExceptionHandler::class.java.name to Level.OFF, + ) { + val aggregateId = GameId() + testKoinApplicationWithConfig { + val repo = get() + val eventHandler = get() - (1..10) - .map { r -> - GlobalScope - .launch { - repeat(100) { r2 -> - val playerX = Player("player$r$r2") - eventHandler - .handle(aggregateId) { - NewPlayerEvent( - aggregateId = aggregateId, - player = playerX, - version = it, - ) - } + (1..10) + .map { r -> + GlobalScope + .launch { + repeat(20) { r2 -> + val playerX = Player("player$r$r2") + eventHandler + .handle(aggregateId) { + NewPlayerEvent( + aggregateId = aggregateId, + player = playerX, + version = it, + ) + } + } } - } - }.joinAll() + }.joinAll() - eventually( - eventuallyConfig { - duration = 10.seconds - interval = 1.seconds - includeFirst = false - }, - ) { - repo.getLast(aggregateId).run { - lastEventVersion shouldBeEqual 1000 - players shouldHaveSize 1000 + eventually( + eventuallyConfig { + duration = 10.seconds + interval = 1.seconds + includeFirst = false + }, + ) { + repo.getLast(aggregateId).run { + lastEventVersion shouldBeEqual 200 + players shouldHaveSize 200 + } + repo.count(aggregateId) shouldBe 39 } - repo.count(aggregateId) shouldBe 119 } } }