CommandStreamChannel block the duplicate call
add GameCommandHandlerTest Create a CommandStreamChannelBuilder to inject maxCacheTime Add missing empty disabled test fix EventStreamInMemory.readAll
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
package eventDemo.app.command
|
||||
|
||||
import eventDemo.app.command.command.GameCommand
|
||||
import eventDemo.app.command.command.IWantToJoinTheGameCommand
|
||||
import eventDemo.app.entity.GameId
|
||||
import eventDemo.app.entity.Player
|
||||
import eventDemo.app.eventListener.GameEventPlayerNotificationListener
|
||||
import eventDemo.app.eventListener.GameEventReactionListener
|
||||
import eventDemo.app.notification.Notification
|
||||
import eventDemo.app.notification.WelcomeToTheGameNotification
|
||||
import eventDemo.configuration.appKoinModule
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
import io.kotest.matchers.collections.shouldContain
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.dsl.koinApplication
|
||||
import kotlin.test.assertIs
|
||||
|
||||
class GameCommandHandlerTest :
|
||||
FunSpec({
|
||||
test("handle a command should execute the command") {
|
||||
koinApplication { modules(appKoinModule) }.koin.apply {
|
||||
val commandHandler by inject<GameCommandHandler>()
|
||||
val notificationListener by inject<GameEventPlayerNotificationListener>()
|
||||
val gameId = GameId()
|
||||
val player = Player("Tesla")
|
||||
val channelCommand = Channel<GameCommand>(Channel.BUFFERED)
|
||||
val channelNotification = Channel<Notification>(Channel.BUFFERED)
|
||||
GameEventReactionListener(get(), get(), get()).init()
|
||||
notificationListener.startListening(channelNotification, player)
|
||||
|
||||
GlobalScope.launch {
|
||||
commandHandler.handle(player, channelCommand, channelNotification)
|
||||
}
|
||||
|
||||
channelCommand.send(IWantToJoinTheGameCommand(IWantToJoinTheGameCommand.Payload(gameId, player)))
|
||||
assertIs<WelcomeToTheGameNotification>(channelNotification.receive()).let {
|
||||
it.players shouldContain player
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,9 @@
|
||||
package eventDemo.app.command.command
|
||||
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
|
||||
class ICantPlayCommandTest :
|
||||
FunSpec({
|
||||
|
||||
xtest("run should publish the event") { }
|
||||
})
|
||||
@@ -0,0 +1,9 @@
|
||||
package eventDemo.app.command.command
|
||||
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
|
||||
class IWantToJoinTheGameCommandTest :
|
||||
FunSpec({
|
||||
|
||||
xtest("run should publish the event") { }
|
||||
})
|
||||
@@ -0,0 +1,9 @@
|
||||
package eventDemo.app.command.command
|
||||
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
|
||||
class IWantToPlayCardCommandTest :
|
||||
FunSpec({
|
||||
|
||||
xtest("run should publish the event") { }
|
||||
})
|
||||
@@ -0,0 +1,9 @@
|
||||
package eventDemo.app.command.command
|
||||
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
|
||||
class IamReadyToPlayCommandTest :
|
||||
FunSpec({
|
||||
|
||||
xtest("run should publish the event") { }
|
||||
})
|
||||
@@ -24,7 +24,7 @@ class DeckTest :
|
||||
deck.allCards().map { it.id }.shouldBeUnique()
|
||||
}
|
||||
|
||||
test("initHands") {
|
||||
test("initHands should be generate the hands of all players from the stack") {
|
||||
// Given
|
||||
val playerNumbers = 4
|
||||
val players = (1..playerNumbers).map { Player(name = "name $it") }.toSet()
|
||||
@@ -41,7 +41,7 @@ class DeckTest :
|
||||
initDeck.allCardCount() shouldBeExactly totalCardsNumber
|
||||
}
|
||||
|
||||
test("takeOneCardFromStackTo") {
|
||||
test("takeOneCardFromStackTo player") {
|
||||
// Given
|
||||
val playerNumbers = 4
|
||||
val players = (1..playerNumbers).map { Player(name = "name $it") }.toSet()
|
||||
@@ -89,7 +89,6 @@ class DeckTest :
|
||||
val playerNumbers = 4
|
||||
val players = (1..playerNumbers).map { Player(name = "name $it") }.toSet()
|
||||
val deck = Deck.newWithoutPlayers().initHands(players)
|
||||
val firstPlayer = players.first()
|
||||
|
||||
// When
|
||||
val modifiedDeck = deck.placeFirstCardOnDiscard()
|
||||
|
||||
15
src/test/kotlin/eventDemo/app/entity/PlayersHandsTest.kt
Normal file
15
src/test/kotlin/eventDemo/app/entity/PlayersHandsTest.kt
Normal file
@@ -0,0 +1,15 @@
|
||||
package eventDemo.app.entity
|
||||
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
|
||||
class PlayersHandsTest :
|
||||
FunSpec({
|
||||
|
||||
xtest("getHand should return the hand of the player") { }
|
||||
|
||||
xtest("removeCard should remove the card") { }
|
||||
|
||||
xtest("addCard should add the card to the correct hand") { }
|
||||
|
||||
xtest("toPlayersHands should build object from map") { }
|
||||
})
|
||||
10
src/test/kotlin/eventDemo/app/event/GameEventHandlerTest.kt
Normal file
10
src/test/kotlin/eventDemo/app/event/GameEventHandlerTest.kt
Normal file
@@ -0,0 +1,10 @@
|
||||
package eventDemo.app.event
|
||||
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
|
||||
class GameEventHandlerTest :
|
||||
FunSpec({
|
||||
xtest("handle event should publish the event to the stream") { }
|
||||
xtest("handle event should build the registered projection") { }
|
||||
xtest("handle event should publish the event to the bus") { }
|
||||
})
|
||||
@@ -0,0 +1,16 @@
|
||||
package eventDemo.app.event.projection
|
||||
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
|
||||
class GameStateRepositoryTest :
|
||||
FunSpec({
|
||||
xtest("GameStateRepository should build the projection when a new event occurs") { }
|
||||
|
||||
xtest("get should build the last version of the state") { }
|
||||
xtest("get should be concurrently secure") { }
|
||||
xtest("get should be concurrently secure") { }
|
||||
|
||||
xtest("getUntil should build the state until the event") { }
|
||||
xtest("call getUntil twice should get the state from the cache") { }
|
||||
xtest("getUntil should be concurrently secure") { }
|
||||
})
|
||||
@@ -0,0 +1,15 @@
|
||||
package eventDemo.app.event.projection
|
||||
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
|
||||
class GameStateTest :
|
||||
FunSpec({
|
||||
xtest("isReady") { }
|
||||
xtest("nextPlayer") { }
|
||||
xtest("nextPlayerTurn") { }
|
||||
xtest("playerDiffIndex") { }
|
||||
xtest("cardOnBoardIsForYou") { }
|
||||
xtest("playableCards") { }
|
||||
xtest("playerHasNoCardLeft") { }
|
||||
xtest("canBePlayThisCard") { }
|
||||
})
|
||||
@@ -50,7 +50,7 @@ class GameStateRouteTest :
|
||||
}.apply {
|
||||
assertEquals(HttpStatusCode.OK, status, message = bodyAsText())
|
||||
val state = call.body<GameState>()
|
||||
assertEquals(id, state.gameId)
|
||||
id shouldBeEqual state.gameId
|
||||
state.players shouldHaveSize 0
|
||||
state.isStarted shouldBeEqual false
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package eventDemo.app.query
|
||||
|
||||
import eventDemo.app.command.GameCommandHandler
|
||||
import eventDemo.app.command.command.GameCommand
|
||||
import eventDemo.app.command.command.IWantToJoinTheGameCommand
|
||||
import eventDemo.app.command.command.IWantToPlayCardCommand
|
||||
import eventDemo.app.command.command.IamReadyToPlayCommand
|
||||
@@ -14,20 +15,16 @@ import eventDemo.app.event.projection.buildStateFromEventStream
|
||||
import eventDemo.app.eventListener.GameEventPlayerNotificationListener
|
||||
import eventDemo.app.eventListener.GameEventReactionListener
|
||||
import eventDemo.app.notification.ItsTheTurnOfNotification
|
||||
import eventDemo.app.notification.Notification
|
||||
import eventDemo.app.notification.PlayerAsJoinTheGameNotification
|
||||
import eventDemo.app.notification.PlayerAsPlayACardNotification
|
||||
import eventDemo.app.notification.PlayerWasReadyNotification
|
||||
import eventDemo.app.notification.TheGameWasStartedNotification
|
||||
import eventDemo.app.notification.WelcomeToTheGameNotification
|
||||
import eventDemo.configuration.appKoinModule
|
||||
import eventDemo.libs.fromFrameChannel
|
||||
import eventDemo.libs.toObjectChannel
|
||||
import eventDemo.shared.toFrame
|
||||
import eventDemo.shared.toNotification
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
import io.kotest.matchers.collections.shouldHaveSize
|
||||
import io.kotest.matchers.equals.shouldBeEqual
|
||||
import io.ktor.websocket.Frame
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
@@ -48,46 +45,46 @@ class GameStateTest :
|
||||
val id = GameId()
|
||||
val player1 = Player(name = "Nikola")
|
||||
val player2 = Player(name = "Einstein")
|
||||
val channelCommand1 = Channel<Frame>(Channel.BUFFERED)
|
||||
val channelCommand2 = Channel<Frame>(Channel.BUFFERED)
|
||||
val channelNotification1 = Channel<Frame>(Channel.BUFFERED)
|
||||
val channelNotification2 = Channel<Frame>(Channel.BUFFERED)
|
||||
val channelCommand1 = Channel<GameCommand>(Channel.BUFFERED)
|
||||
val channelCommand2 = Channel<GameCommand>(Channel.BUFFERED)
|
||||
val channelNotification1 = Channel<Notification>(Channel.BUFFERED)
|
||||
val channelNotification2 = Channel<Notification>(Channel.BUFFERED)
|
||||
|
||||
var playedCard1: Card? = null
|
||||
var playedCard2: Card? = null
|
||||
|
||||
val player1Job =
|
||||
launch {
|
||||
channelCommand1.send(IWantToJoinTheGameCommand(IWantToJoinTheGameCommand.Payload(id, player1)).toFrame())
|
||||
channelNotification1.receive().toNotification().let {
|
||||
channelCommand1.send(IWantToJoinTheGameCommand(IWantToJoinTheGameCommand.Payload(id, player1)))
|
||||
channelNotification1.receive().let {
|
||||
assertIs<WelcomeToTheGameNotification>(it).players shouldBeEqual setOf(player1)
|
||||
}
|
||||
channelNotification1.receive().toNotification().let {
|
||||
channelNotification1.receive().let {
|
||||
assertIs<PlayerAsJoinTheGameNotification>(it).player shouldBeEqual player2
|
||||
}
|
||||
channelCommand1.send(IamReadyToPlayCommand(IamReadyToPlayCommand.Payload(id, player1)).toFrame())
|
||||
channelNotification1.receive().toNotification().let {
|
||||
channelCommand1.send(IamReadyToPlayCommand(IamReadyToPlayCommand.Payload(id, player1)))
|
||||
channelNotification1.receive().let {
|
||||
assertIs<PlayerWasReadyNotification>(it).player shouldBeEqual player2
|
||||
}
|
||||
val player1Hand =
|
||||
channelNotification1.receive().toNotification().let {
|
||||
channelNotification1.receive().let {
|
||||
assertIs<TheGameWasStartedNotification>(it).hand shouldHaveSize 7
|
||||
}
|
||||
playedCard1 = player1Hand.first()
|
||||
channelNotification1.receive().toNotification().let {
|
||||
channelNotification1.receive().let {
|
||||
assertIs<ItsTheTurnOfNotification>(it).apply {
|
||||
player shouldBeEqual player1
|
||||
}
|
||||
}
|
||||
channelCommand1.send(IWantToPlayCardCommand(IWantToPlayCardCommand.Payload(id, player1, player1Hand.first())).toFrame())
|
||||
channelCommand1.send(IWantToPlayCardCommand(IWantToPlayCardCommand.Payload(id, player1, player1Hand.first())))
|
||||
|
||||
channelNotification1.receive().toNotification().let {
|
||||
channelNotification1.receive().let {
|
||||
assertIs<ItsTheTurnOfNotification>(it).apply {
|
||||
player shouldBeEqual player2
|
||||
}
|
||||
}
|
||||
|
||||
channelNotification1.receive().toNotification().let {
|
||||
channelNotification1.receive().let {
|
||||
assertIs<PlayerAsPlayACardNotification>(it).apply {
|
||||
player shouldBeEqual player2
|
||||
card shouldBeEqual assertNotNull(playedCard2)
|
||||
@@ -98,24 +95,24 @@ class GameStateTest :
|
||||
val player2Job =
|
||||
launch {
|
||||
delay(100)
|
||||
channelCommand2.send(IWantToJoinTheGameCommand(IWantToJoinTheGameCommand.Payload(id, player2)).toFrame())
|
||||
channelNotification2.receive().toNotification().let {
|
||||
channelCommand2.send(IWantToJoinTheGameCommand(IWantToJoinTheGameCommand.Payload(id, player2)))
|
||||
channelNotification2.receive().let {
|
||||
assertIs<WelcomeToTheGameNotification>(it).players shouldBeEqual setOf(player1, player2)
|
||||
}
|
||||
channelNotification2.receive().toNotification().let {
|
||||
channelNotification2.receive().let {
|
||||
assertIs<PlayerWasReadyNotification>(it).player shouldBeEqual player1
|
||||
}
|
||||
channelCommand2.send(IamReadyToPlayCommand(IamReadyToPlayCommand.Payload(id, player2)).toFrame())
|
||||
channelCommand2.send(IamReadyToPlayCommand(IamReadyToPlayCommand.Payload(id, player2)))
|
||||
val player2Hand =
|
||||
channelNotification2.receive().toNotification().let {
|
||||
channelNotification2.receive().let {
|
||||
assertIs<TheGameWasStartedNotification>(it).hand shouldHaveSize 7
|
||||
}
|
||||
channelNotification2.receive().toNotification().let {
|
||||
channelNotification2.receive().let {
|
||||
assertIs<ItsTheTurnOfNotification>(it).apply {
|
||||
player shouldBeEqual player1
|
||||
}
|
||||
}
|
||||
channelNotification2.receive().toNotification().let {
|
||||
channelNotification2.receive().let {
|
||||
assertIs<PlayerAsPlayACardNotification>(it).apply {
|
||||
player shouldBeEqual player1
|
||||
card shouldBeEqual assertNotNull(playedCard1)
|
||||
@@ -123,12 +120,12 @@ class GameStateTest :
|
||||
}
|
||||
playedCard2 = player2Hand.first()
|
||||
|
||||
channelNotification2.receive().toNotification().let {
|
||||
channelNotification2.receive().let {
|
||||
assertIs<ItsTheTurnOfNotification>(it).apply {
|
||||
player shouldBeEqual player2
|
||||
}
|
||||
}
|
||||
channelCommand2.send(IWantToPlayCardCommand(IWantToPlayCardCommand.Payload(id, player2, player2Hand.first())).toFrame())
|
||||
channelCommand2.send(IWantToPlayCardCommand(IWantToPlayCardCommand.Payload(id, player2, player2Hand.first())))
|
||||
}
|
||||
|
||||
koinApplication { modules(appKoinModule) }.koin.apply {
|
||||
@@ -140,10 +137,10 @@ class GameStateTest :
|
||||
playerNotificationListener.startListening(channelNotification2, player2)
|
||||
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
commandHandler.handle(player1, toObjectChannel(channelCommand1), fromFrameChannel(channelNotification1))
|
||||
commandHandler.handle(player1, channelCommand1, channelNotification1)
|
||||
}
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
commandHandler.handle(player2, toObjectChannel(channelCommand2), fromFrameChannel(channelNotification2))
|
||||
commandHandler.handle(player2, channelCommand2, channelNotification2)
|
||||
}
|
||||
|
||||
joinAll(player1Job, player2Job)
|
||||
|
||||
10
src/test/kotlin/eventDemo/libs/event/EventBusInMemoryTest.kt
Normal file
10
src/test/kotlin/eventDemo/libs/event/EventBusInMemoryTest.kt
Normal file
@@ -0,0 +1,10 @@
|
||||
package eventDemo.libs.event
|
||||
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
|
||||
class EventBusInMemoryTest :
|
||||
FunSpec({
|
||||
|
||||
xtest("publish should call the subscribed functions") { }
|
||||
xtest("publish should call the subscribed functions on the priority order") { }
|
||||
})
|
||||
@@ -0,0 +1,16 @@
|
||||
package eventDemo.libs.event
|
||||
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
|
||||
class EventStreamInMemoryTest :
|
||||
FunSpec({
|
||||
|
||||
xtest("publish should be concurrently secure") { }
|
||||
|
||||
xtest("readLast should only return the event of aggregate") { }
|
||||
xtest("readLast should return the last event of the aggregate") { }
|
||||
|
||||
xtest("readLastOf should return the last event of the aggregate of the type") { }
|
||||
|
||||
xtest("readAll should only return the event of aggregate") { }
|
||||
})
|
||||
Reference in New Issue
Block a user