create GameStateRepositoryInRedis

This commit is contained in:
2025-03-25 02:04:02 +01:00
parent 9670a000f0
commit 22792a0427
14 changed files with 136 additions and 57 deletions

View File

@@ -9,53 +9,57 @@ import eventDemo.business.event.projection.projectionListener.ReactionListener
import eventDemo.business.notification.CommandSuccessNotification
import eventDemo.business.notification.Notification
import eventDemo.business.notification.WelcomeToTheGameNotification
import eventDemo.configuration.injection.Configuration
import eventDemo.configuration.injection.appKoinModule
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.collections.shouldContain
import io.kotest.matchers.equals.shouldBeEqual
import io.mockk.mockk
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.trySendBlocking
import kotlinx.coroutines.launch
import kotlinx.coroutines.withTimeout
import org.koin.dsl.koinApplication
import kotlin.test.assertIs
import kotlin.time.Duration.Companion.seconds
@OptIn(DelicateCoroutinesApi::class)
class GameCommandHandlerTest :
FunSpec({
test("handle a command should execute the command") {
koinApplication { modules(appKoinModule(mockk(relaxed = true))) }.koin.apply {
val commandHandler by inject<GameCommandHandler>()
val notificationListener by inject<PlayerNotificationListener>()
val gameId = GameId()
val player = Player("Tesla")
val channelCommand = Channel<GameCommand>(Channel.BUFFERED)
val channelNotification = Channel<Notification>(Channel.BUFFERED)
ReactionListener(get(), get()).init()
notificationListener.startListening(
player,
gameId,
) { channelNotification.trySendBlocking(it) }
GlobalScope.launch {
commandHandler.handle(
withTimeout(1.seconds) {
koinApplication { modules(appKoinModule(Configuration("redis://localhost:6379"))) }.koin.apply {
val commandHandler by inject<GameCommandHandler>()
val notificationListener by inject<PlayerNotificationListener>()
val gameId = GameId()
val player = Player("Tesla")
val channelCommand = Channel<GameCommand>(Channel.BUFFERED)
val channelNotification = Channel<Notification>(Channel.BUFFERED)
ReactionListener(get(), get()).init()
notificationListener.startListening(
player,
gameId,
channelCommand,
channelNotification,
)
}
) { channelNotification.trySendBlocking(it) }
IWantToJoinTheGameCommand(IWantToJoinTheGameCommand.Payload(gameId, player)).also { sendCommand ->
channelCommand.send(sendCommand)
channelNotification.receive().let {
assertIs<CommandSuccessNotification>(it).commandId shouldBeEqual sendCommand.id
GlobalScope.launch {
commandHandler.handle(
player,
gameId,
channelCommand,
channelNotification,
)
}
IWantToJoinTheGameCommand(IWantToJoinTheGameCommand.Payload(gameId, player)).also { sendCommand ->
channelCommand.send(sendCommand)
channelNotification.receive().let {
assertIs<CommandSuccessNotification>(it).commandId shouldBeEqual sendCommand.id
}
}
assertIs<WelcomeToTheGameNotification>(channelNotification.receive()).let {
it.players shouldContain player
}
}
assertIs<WelcomeToTheGameNotification>(channelNotification.receive()).let {
it.players shouldContain player
}
}
}

View File

@@ -5,11 +5,11 @@ import eventDemo.business.entity.Player
import eventDemo.business.event.GameEventHandler
import eventDemo.business.event.event.NewPlayerEvent
import eventDemo.business.event.projection.gameState.GameStateRepository
import eventDemo.configuration.injection.Configuration
import eventDemo.configuration.injection.appKoinModule
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.collections.shouldHaveSize
import io.kotest.matchers.equals.shouldBeEqual
import io.mockk.mockk
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.joinAll
@@ -26,7 +26,7 @@ class GameStateRepositoryTest :
test("GameStateRepository should build the projection when a new event occurs") {
val aggregateId = GameId()
koinApplication { modules(appKoinModule(mockk(relaxed = true))) }.koin.apply {
koinApplication { modules(appKoinModule(Configuration("redis://localhost:6379"))) }.koin.apply {
val repo = get<GameStateRepository>()
val eventHandler = get<GameEventHandler>()
eventHandler
@@ -45,7 +45,7 @@ class GameStateRepositoryTest :
test("get should build the last version of the state") {
val aggregateId = GameId()
koinApplication { modules(appKoinModule(mockk(relaxed = true))) }.koin.apply {
koinApplication { modules(appKoinModule(Configuration("redis://localhost:6379"))) }.koin.apply {
val repo = get<GameStateRepository>()
val eventHandler = get<GameEventHandler>()
@@ -70,7 +70,7 @@ class GameStateRepositoryTest :
test("getUntil should build the state until the event") {
repeat(10) {
val aggregateId = GameId()
koinApplication { modules(appKoinModule(mockk(relaxed = true))) }.koin.apply {
koinApplication { modules(appKoinModule(Configuration("redis://localhost:6379"))) }.koin.apply {
val repo = get<GameStateRepository>()
val eventHandler = get<GameEventHandler>()
@@ -99,7 +99,7 @@ class GameStateRepositoryTest :
test("getUntil should be concurrently secure") {
val aggregateId = GameId()
koinApplication { modules(appKoinModule(mockk(relaxed = true))) }.koin.apply {
koinApplication { modules(appKoinModule(Configuration("redis://localhost:6379"))) }.koin.apply {
val repo = get<GameStateRepository>()
val eventHandler = get<GameEventHandler>()