update ktlint rules
This commit is contained in:
@@ -3,8 +3,10 @@ package eventDemo
|
||||
import eventDemo.app.entity.Card
|
||||
import eventDemo.app.entity.Deck
|
||||
|
||||
fun Deck.allCardCount(): Int = stack.size + discard.size + playersHands.values.flatten().size
|
||||
fun Deck.allCardCount(): Int =
|
||||
stack.size + discard.size + playersHands.values.flatten().size
|
||||
|
||||
fun Deck.allCards(): Set<Card> = stack + discard + playersHands.values.flatten()
|
||||
fun Deck.allCards(): Set<Card> =
|
||||
stack + discard + playersHands.values.flatten()
|
||||
|
||||
// suspend fun SendChannel<Frame>.send(command: GameCommand) = send(Frame.Text(Json.encodeToString(command)))
|
||||
|
||||
@@ -20,26 +20,26 @@ import kotlin.test.assertIs
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
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<PlayerNotificationEventListener>()
|
||||
val gameId = GameId()
|
||||
val player = Player("Tesla")
|
||||
val channelCommand = Channel<GameCommand>(Channel.BUFFERED)
|
||||
val channelNotification = Channel<Notification>(Channel.BUFFERED)
|
||||
ReactionEventListener(get(), get(), get()).init()
|
||||
notificationListener.startListening(channelNotification, player)
|
||||
FunSpec({
|
||||
test("handle a command should execute the command") {
|
||||
koinApplication { modules(appKoinModule) }.koin.apply {
|
||||
val commandHandler by inject<GameCommandHandler>()
|
||||
val notificationListener by inject<PlayerNotificationEventListener>()
|
||||
val gameId = GameId()
|
||||
val player = Player("Tesla")
|
||||
val channelCommand = Channel<GameCommand>(Channel.BUFFERED)
|
||||
val channelNotification = Channel<Notification>(Channel.BUFFERED)
|
||||
ReactionEventListener(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
|
||||
}
|
||||
}
|
||||
GlobalScope.launch {
|
||||
commandHandler.handle(player, channelCommand, channelNotification)
|
||||
}
|
||||
})
|
||||
|
||||
channelCommand.send(IWantToJoinTheGameCommand(IWantToJoinTheGameCommand.Payload(gameId, player)))
|
||||
assertIs<WelcomeToTheGameNotification>(channelNotification.receive()).let {
|
||||
it.players shouldContain player
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -3,6 +3,6 @@ package eventDemo.app.command
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
|
||||
class GameCommandRunnerTest :
|
||||
FunSpec({
|
||||
test("run should run the correct command") { }
|
||||
})
|
||||
FunSpec({
|
||||
test("run should run the correct command") { }
|
||||
})
|
||||
|
||||
@@ -3,7 +3,7 @@ package eventDemo.app.command.command
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
|
||||
class ICantPlayCommandTest :
|
||||
FunSpec({
|
||||
FunSpec({
|
||||
|
||||
xtest("run should publish the event") { }
|
||||
})
|
||||
xtest("run should publish the event") { }
|
||||
})
|
||||
|
||||
@@ -3,7 +3,7 @@ package eventDemo.app.command.command
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
|
||||
class IWantToJoinTheGameCommandTest :
|
||||
FunSpec({
|
||||
FunSpec({
|
||||
|
||||
xtest("run should publish the event") { }
|
||||
})
|
||||
xtest("run should publish the event") { }
|
||||
})
|
||||
|
||||
@@ -3,7 +3,7 @@ package eventDemo.app.command.command
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
|
||||
class IWantToPlayCardCommandTest :
|
||||
FunSpec({
|
||||
FunSpec({
|
||||
|
||||
xtest("run should publish the event") { }
|
||||
})
|
||||
xtest("run should publish the event") { }
|
||||
})
|
||||
|
||||
@@ -3,7 +3,7 @@ package eventDemo.app.command.command
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
|
||||
class IamReadyToPlayCommandTest :
|
||||
FunSpec({
|
||||
FunSpec({
|
||||
|
||||
xtest("run should publish the event") { }
|
||||
})
|
||||
xtest("run should publish the event") { }
|
||||
})
|
||||
|
||||
@@ -8,97 +8,97 @@ import io.kotest.matchers.ints.shouldBeExactly
|
||||
import kotlin.test.assertNotNull
|
||||
|
||||
class DeckTest :
|
||||
FunSpec({
|
||||
val totalCardsNumber = 104
|
||||
test("newWithoutPlayers") {
|
||||
// When
|
||||
val deck = Deck.newWithoutPlayers()
|
||||
FunSpec({
|
||||
val totalCardsNumber = 104
|
||||
test("newWithoutPlayers") {
|
||||
// When
|
||||
val deck = Deck.newWithoutPlayers()
|
||||
|
||||
// Then
|
||||
deck.stack.size shouldBeExactly totalCardsNumber
|
||||
deck.discard.size shouldBeExactly 0
|
||||
deck.playersHands.size shouldBeExactly 0
|
||||
// Then
|
||||
deck.stack.size shouldBeExactly totalCardsNumber
|
||||
deck.discard.size shouldBeExactly 0
|
||||
deck.playersHands.size shouldBeExactly 0
|
||||
|
||||
deck.allCardCount() shouldBeExactly totalCardsNumber
|
||||
deck.allCards().shouldBeUnique()
|
||||
deck.allCards().map { it.id }.shouldBeUnique()
|
||||
}
|
||||
deck.allCardCount() shouldBeExactly totalCardsNumber
|
||||
deck.allCards().shouldBeUnique()
|
||||
deck.allCards().map { it.id }.shouldBeUnique()
|
||||
}
|
||||
|
||||
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()
|
||||
val deck = Deck.newWithoutPlayers()
|
||||
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()
|
||||
val deck = Deck.newWithoutPlayers()
|
||||
|
||||
// When
|
||||
val initDeck = deck.initHands(players)
|
||||
// When
|
||||
val initDeck = deck.initHands(players)
|
||||
|
||||
// Then
|
||||
initDeck.stack.size shouldBeExactly totalCardsNumber - (playerNumbers * 7)
|
||||
initDeck.discard.size shouldBeExactly 0
|
||||
initDeck.playersHands.size shouldBeExactly playerNumbers
|
||||
initDeck.playersHands.forEach { (_, cards) -> cards.size shouldBeExactly 7 }
|
||||
initDeck.allCardCount() shouldBeExactly totalCardsNumber
|
||||
}
|
||||
// Then
|
||||
initDeck.stack.size shouldBeExactly totalCardsNumber - (playerNumbers * 7)
|
||||
initDeck.discard.size shouldBeExactly 0
|
||||
initDeck.playersHands.size shouldBeExactly playerNumbers
|
||||
initDeck.playersHands.forEach { (_, cards) -> cards.size shouldBeExactly 7 }
|
||||
initDeck.allCardCount() shouldBeExactly totalCardsNumber
|
||||
}
|
||||
|
||||
test("takeOneCardFromStackTo player") {
|
||||
// Given
|
||||
val playerNumbers = 4
|
||||
val players = (1..playerNumbers).map { Player(name = "name $it") }.toSet()
|
||||
val deck = Deck.newWithoutPlayers().initHands(players)
|
||||
val firstPlayer = players.first()
|
||||
test("takeOneCardFromStackTo player") {
|
||||
// Given
|
||||
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.takeOneCardFromStackTo(firstPlayer)
|
||||
// When
|
||||
val modifiedDeck = deck.takeOneCardFromStackTo(firstPlayer)
|
||||
|
||||
// Then
|
||||
modifiedDeck.discard.size shouldBeExactly 0
|
||||
modifiedDeck.stack.size shouldBeExactly totalCardsNumber - (playerNumbers * 7) - 1
|
||||
modifiedDeck.playersHands.size shouldBeExactly playerNumbers
|
||||
assertNotNull(modifiedDeck.playersHands.getHand(firstPlayer)).size shouldBeExactly 7 + 1
|
||||
modifiedDeck.playersHands
|
||||
.filterKeys { it != firstPlayer.id }
|
||||
.forEach { (_, cards) -> cards.size shouldBeExactly 7 }
|
||||
modifiedDeck.allCardCount() shouldBeExactly totalCardsNumber
|
||||
}
|
||||
// Then
|
||||
modifiedDeck.discard.size shouldBeExactly 0
|
||||
modifiedDeck.stack.size shouldBeExactly totalCardsNumber - (playerNumbers * 7) - 1
|
||||
modifiedDeck.playersHands.size shouldBeExactly playerNumbers
|
||||
assertNotNull(modifiedDeck.playersHands.getHand(firstPlayer)).size shouldBeExactly 7 + 1
|
||||
modifiedDeck.playersHands
|
||||
.filterKeys { it != firstPlayer.id }
|
||||
.forEach { (_, cards) -> cards.size shouldBeExactly 7 }
|
||||
modifiedDeck.allCardCount() shouldBeExactly totalCardsNumber
|
||||
}
|
||||
|
||||
test("putOneCardFromHand") {
|
||||
// Given
|
||||
val playerNumbers = 4
|
||||
val players = (1..playerNumbers).map { Player(name = "name $it") }.toSet()
|
||||
val deck = Deck.newWithoutPlayers().initHands(players)
|
||||
val firstPlayer = players.first()
|
||||
test("putOneCardFromHand") {
|
||||
// Given
|
||||
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 card = deck.playersHands.getHand(firstPlayer)!!.first()
|
||||
val modifiedDeck = deck.putOneCardFromHand(firstPlayer, card)
|
||||
// When
|
||||
val card = deck.playersHands.getHand(firstPlayer)!!.first()
|
||||
val modifiedDeck = deck.putOneCardFromHand(firstPlayer, card)
|
||||
|
||||
// Then
|
||||
modifiedDeck.discard.size shouldBeExactly 1
|
||||
modifiedDeck.stack.size shouldBeExactly totalCardsNumber - (playerNumbers * 7)
|
||||
modifiedDeck.playersHands.size shouldBeExactly playerNumbers
|
||||
assertNotNull(modifiedDeck.playersHands.getHand(firstPlayer)).size shouldBeExactly 6
|
||||
modifiedDeck.playersHands
|
||||
.filterKeys { it != firstPlayer.id }
|
||||
.forEach { (_, cards) -> cards.size shouldBeExactly 7 }
|
||||
modifiedDeck.allCardCount() shouldBeExactly totalCardsNumber
|
||||
}
|
||||
// Then
|
||||
modifiedDeck.discard.size shouldBeExactly 1
|
||||
modifiedDeck.stack.size shouldBeExactly totalCardsNumber - (playerNumbers * 7)
|
||||
modifiedDeck.playersHands.size shouldBeExactly playerNumbers
|
||||
assertNotNull(modifiedDeck.playersHands.getHand(firstPlayer)).size shouldBeExactly 6
|
||||
modifiedDeck.playersHands
|
||||
.filterKeys { it != firstPlayer.id }
|
||||
.forEach { (_, cards) -> cards.size shouldBeExactly 7 }
|
||||
modifiedDeck.allCardCount() shouldBeExactly totalCardsNumber
|
||||
}
|
||||
|
||||
test("placeFirstCardOnDiscard") {
|
||||
// Given
|
||||
val playerNumbers = 4
|
||||
val players = (1..playerNumbers).map { Player(name = "name $it") }.toSet()
|
||||
val deck = Deck.newWithoutPlayers().initHands(players)
|
||||
test("placeFirstCardOnDiscard") {
|
||||
// Given
|
||||
val playerNumbers = 4
|
||||
val players = (1..playerNumbers).map { Player(name = "name $it") }.toSet()
|
||||
val deck = Deck.newWithoutPlayers().initHands(players)
|
||||
|
||||
// When
|
||||
val modifiedDeck = deck.placeFirstCardOnDiscard()
|
||||
// When
|
||||
val modifiedDeck = deck.placeFirstCardOnDiscard()
|
||||
|
||||
// Then
|
||||
modifiedDeck.discard.size shouldBeExactly 1
|
||||
modifiedDeck.stack.size shouldBeExactly totalCardsNumber - (playerNumbers * 7) - 1
|
||||
modifiedDeck.playersHands.size shouldBeExactly playerNumbers
|
||||
modifiedDeck.playersHands
|
||||
.forEach { (_, cards) -> cards.size shouldBeExactly 7 }
|
||||
modifiedDeck.allCardCount() shouldBeExactly totalCardsNumber
|
||||
}
|
||||
})
|
||||
// Then
|
||||
modifiedDeck.discard.size shouldBeExactly 1
|
||||
modifiedDeck.stack.size shouldBeExactly totalCardsNumber - (playerNumbers * 7) - 1
|
||||
modifiedDeck.playersHands.size shouldBeExactly playerNumbers
|
||||
modifiedDeck.playersHands
|
||||
.forEach { (_, cards) -> cards.size shouldBeExactly 7 }
|
||||
modifiedDeck.allCardCount() shouldBeExactly totalCardsNumber
|
||||
}
|
||||
})
|
||||
|
||||
@@ -5,37 +5,37 @@ import io.kotest.matchers.ints.shouldBeExactly
|
||||
import kotlin.test.assertNotNull
|
||||
|
||||
class PlayerHandKtTest :
|
||||
FunSpec({
|
||||
test("addCards") {
|
||||
// Given
|
||||
val playerNumbers = 4
|
||||
val players = (1..playerNumbers).map { Player(name = "name $it") }.toSet()
|
||||
val firstPlayer = players.first()
|
||||
val playersHands = PlayersHands(players)
|
||||
val card = Card.NumericCard(0, Card.Color.Red)
|
||||
FunSpec({
|
||||
test("addCards") {
|
||||
// Given
|
||||
val playerNumbers = 4
|
||||
val players = (1..playerNumbers).map { Player(name = "name $it") }.toSet()
|
||||
val firstPlayer = players.first()
|
||||
val playersHands = PlayersHands(players)
|
||||
val card = Card.NumericCard(0, Card.Color.Red)
|
||||
|
||||
// When
|
||||
val newHands: PlayersHands = playersHands.addCards(firstPlayer, listOf(card))
|
||||
// When
|
||||
val newHands: PlayersHands = playersHands.addCards(firstPlayer, listOf(card))
|
||||
|
||||
assertNotNull(newHands.getHand(firstPlayer)).size shouldBeExactly 1
|
||||
assertNotNull(newHands.getHand(players.last())).size shouldBeExactly 0
|
||||
}
|
||||
assertNotNull(newHands.getHand(firstPlayer)).size shouldBeExactly 1
|
||||
assertNotNull(newHands.getHand(players.last())).size shouldBeExactly 0
|
||||
}
|
||||
|
||||
test("removeCard") {
|
||||
// Given
|
||||
val playerNumbers = 4
|
||||
val players = (1..playerNumbers).map { Player(name = "name $it") }.toSet()
|
||||
val firstPlayer = players.first()
|
||||
val card1 = Card.NumericCard(1, Card.Color.Red)
|
||||
val card2 = Card.NumericCard(2, Card.Color.Red)
|
||||
val playersHands: PlayersHands =
|
||||
PlayersHands(players)
|
||||
.addCards(firstPlayer, listOf(card1, card2))
|
||||
test("removeCard") {
|
||||
// Given
|
||||
val playerNumbers = 4
|
||||
val players = (1..playerNumbers).map { Player(name = "name $it") }.toSet()
|
||||
val firstPlayer = players.first()
|
||||
val card1 = Card.NumericCard(1, Card.Color.Red)
|
||||
val card2 = Card.NumericCard(2, Card.Color.Red)
|
||||
val playersHands: PlayersHands =
|
||||
PlayersHands(players)
|
||||
.addCards(firstPlayer, listOf(card1, card2))
|
||||
|
||||
// When
|
||||
val newHands: PlayersHands = playersHands.removeCard(firstPlayer, card1)
|
||||
// When
|
||||
val newHands: PlayersHands = playersHands.removeCard(firstPlayer, card1)
|
||||
|
||||
assertNotNull(newHands.getHand(firstPlayer)).size shouldBeExactly 1
|
||||
assertNotNull(newHands.getHand(players.last())).size shouldBeExactly 0
|
||||
}
|
||||
})
|
||||
assertNotNull(newHands.getHand(firstPlayer)).size shouldBeExactly 1
|
||||
assertNotNull(newHands.getHand(players.last())).size shouldBeExactly 0
|
||||
}
|
||||
})
|
||||
|
||||
@@ -3,13 +3,13 @@ package eventDemo.app.entity
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
|
||||
class PlayersHandsTest :
|
||||
FunSpec({
|
||||
FunSpec({
|
||||
|
||||
xtest("getHand should return the hand of the player") { }
|
||||
xtest("getHand should return the hand of the player") { }
|
||||
|
||||
xtest("removeCard should remove the card") { }
|
||||
xtest("removeCard should remove the card") { }
|
||||
|
||||
xtest("addCard should add the card to the correct hand") { }
|
||||
xtest("addCard should add the card to the correct hand") { }
|
||||
|
||||
xtest("toPlayersHands should build object from map") { }
|
||||
})
|
||||
xtest("toPlayersHands should build object from map") { }
|
||||
})
|
||||
|
||||
@@ -3,8 +3,8 @@ 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") { }
|
||||
})
|
||||
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") { }
|
||||
})
|
||||
|
||||
@@ -15,112 +15,112 @@ import kotlin.test.assertIs
|
||||
import kotlin.test.assertNotNull
|
||||
|
||||
class GameStateBuilderTest :
|
||||
FunSpec({
|
||||
test("apply") {
|
||||
disableShuffleDeck()
|
||||
val versionBuilder = VersionBuilderLocal()
|
||||
val gameId = GameId()
|
||||
val player1 = Player(name = "Nikola")
|
||||
val player2 = Player(name = "Einstein")
|
||||
FunSpec({
|
||||
test("apply") {
|
||||
disableShuffleDeck()
|
||||
val versionBuilder = VersionBuilderLocal()
|
||||
val gameId = GameId()
|
||||
val player1 = Player(name = "Nikola")
|
||||
val player2 = Player(name = "Einstein")
|
||||
|
||||
GameState(gameId)
|
||||
.run {
|
||||
val event =
|
||||
NewPlayerEvent(
|
||||
aggregateId = gameId,
|
||||
player = player1,
|
||||
version = versionBuilder.buildNextVersion(gameId),
|
||||
)
|
||||
apply(event).also { state ->
|
||||
state.aggregateId shouldBeEqual gameId
|
||||
state.isReady shouldBeEqual false
|
||||
state.isStarted shouldBeEqual false
|
||||
}
|
||||
}.run {
|
||||
val event =
|
||||
NewPlayerEvent(
|
||||
aggregateId = gameId,
|
||||
player = player2,
|
||||
version = versionBuilder.buildNextVersion(gameId),
|
||||
)
|
||||
apply(event).also { state ->
|
||||
state.aggregateId shouldBeEqual gameId
|
||||
state.players shouldBeEqual setOf(player1, player2)
|
||||
}
|
||||
}.run {
|
||||
val event =
|
||||
PlayerReadyEvent(
|
||||
aggregateId = gameId,
|
||||
player = player1,
|
||||
version = versionBuilder.buildNextVersion(gameId),
|
||||
)
|
||||
apply(event).also { state ->
|
||||
state.aggregateId shouldBeEqual gameId
|
||||
state.readyPlayers shouldBeEqual setOf(player1)
|
||||
}
|
||||
}.run {
|
||||
val event =
|
||||
PlayerReadyEvent(
|
||||
aggregateId = gameId,
|
||||
player = player2,
|
||||
version = versionBuilder.buildNextVersion(gameId),
|
||||
)
|
||||
apply(event).also { state ->
|
||||
state.aggregateId shouldBeEqual gameId
|
||||
state.readyPlayers shouldBeEqual setOf(player1, player2)
|
||||
state.isReady shouldBeEqual true
|
||||
state.isStarted shouldBeEqual false
|
||||
}
|
||||
}.run {
|
||||
val event =
|
||||
GameStartedEvent.new(
|
||||
id = gameId,
|
||||
players = setOf(player1, player2),
|
||||
shuffleIsDisabled = true,
|
||||
version = versionBuilder.buildNextVersion(gameId),
|
||||
)
|
||||
apply(event).also { state ->
|
||||
state.aggregateId shouldBeEqual gameId
|
||||
state.isStarted shouldBeEqual true
|
||||
assertIs<Card.NumericCard>(state.deck.stack.first()).let {
|
||||
it.number shouldBeEqual 6
|
||||
it.color shouldBeEqual Card.Color.Red
|
||||
}
|
||||
}
|
||||
}.run {
|
||||
val playedCard = playableCards(player1)[0]
|
||||
val event =
|
||||
CardIsPlayedEvent(
|
||||
aggregateId = gameId,
|
||||
card = playedCard,
|
||||
player = player1,
|
||||
version = versionBuilder.buildNextVersion(gameId),
|
||||
)
|
||||
apply(event).also { state ->
|
||||
state.aggregateId shouldBeEqual gameId
|
||||
assertNotNull(state.cardOnCurrentStack).card shouldBeEqual playedCard
|
||||
assertIs<Card.NumericCard>(playedCard).let {
|
||||
it.number shouldBeEqual 0
|
||||
it.color shouldBeEqual Card.Color.Red
|
||||
}
|
||||
}
|
||||
}.run {
|
||||
val playedCard = playableCards(player2)[0]
|
||||
val event =
|
||||
CardIsPlayedEvent(
|
||||
aggregateId = gameId,
|
||||
card = playedCard,
|
||||
player = player2,
|
||||
version = versionBuilder.buildNextVersion(gameId),
|
||||
)
|
||||
apply(event).also { state ->
|
||||
state.aggregateId shouldBeEqual gameId
|
||||
assertNotNull(state.cardOnCurrentStack).card shouldBeEqual playedCard
|
||||
assertIs<Card.NumericCard>(playedCard).let {
|
||||
it.number shouldBeEqual 7
|
||||
it.color shouldBeEqual Card.Color.Red
|
||||
}
|
||||
}
|
||||
}
|
||||
GameState(gameId)
|
||||
.run {
|
||||
val event =
|
||||
NewPlayerEvent(
|
||||
aggregateId = gameId,
|
||||
player = player1,
|
||||
version = versionBuilder.buildNextVersion(gameId),
|
||||
)
|
||||
apply(event).also { state ->
|
||||
state.aggregateId shouldBeEqual gameId
|
||||
state.isReady shouldBeEqual false
|
||||
state.isStarted shouldBeEqual false
|
||||
}
|
||||
}.run {
|
||||
val event =
|
||||
NewPlayerEvent(
|
||||
aggregateId = gameId,
|
||||
player = player2,
|
||||
version = versionBuilder.buildNextVersion(gameId),
|
||||
)
|
||||
apply(event).also { state ->
|
||||
state.aggregateId shouldBeEqual gameId
|
||||
state.players shouldBeEqual setOf(player1, player2)
|
||||
}
|
||||
}.run {
|
||||
val event =
|
||||
PlayerReadyEvent(
|
||||
aggregateId = gameId,
|
||||
player = player1,
|
||||
version = versionBuilder.buildNextVersion(gameId),
|
||||
)
|
||||
apply(event).also { state ->
|
||||
state.aggregateId shouldBeEqual gameId
|
||||
state.readyPlayers shouldBeEqual setOf(player1)
|
||||
}
|
||||
}.run {
|
||||
val event =
|
||||
PlayerReadyEvent(
|
||||
aggregateId = gameId,
|
||||
player = player2,
|
||||
version = versionBuilder.buildNextVersion(gameId),
|
||||
)
|
||||
apply(event).also { state ->
|
||||
state.aggregateId shouldBeEqual gameId
|
||||
state.readyPlayers shouldBeEqual setOf(player1, player2)
|
||||
state.isReady shouldBeEqual true
|
||||
state.isStarted shouldBeEqual false
|
||||
}
|
||||
}.run {
|
||||
val event =
|
||||
GameStartedEvent.new(
|
||||
id = gameId,
|
||||
players = setOf(player1, player2),
|
||||
shuffleIsDisabled = true,
|
||||
version = versionBuilder.buildNextVersion(gameId),
|
||||
)
|
||||
apply(event).also { state ->
|
||||
state.aggregateId shouldBeEqual gameId
|
||||
state.isStarted shouldBeEqual true
|
||||
assertIs<Card.NumericCard>(state.deck.stack.first()).let {
|
||||
it.number shouldBeEqual 6
|
||||
it.color shouldBeEqual Card.Color.Red
|
||||
}
|
||||
}
|
||||
}.run {
|
||||
val playedCard = playableCards(player1)[0]
|
||||
val event =
|
||||
CardIsPlayedEvent(
|
||||
aggregateId = gameId,
|
||||
card = playedCard,
|
||||
player = player1,
|
||||
version = versionBuilder.buildNextVersion(gameId),
|
||||
)
|
||||
apply(event).also { state ->
|
||||
state.aggregateId shouldBeEqual gameId
|
||||
assertNotNull(state.cardOnCurrentStack).card shouldBeEqual playedCard
|
||||
assertIs<Card.NumericCard>(playedCard).let {
|
||||
it.number shouldBeEqual 0
|
||||
it.color shouldBeEqual Card.Color.Red
|
||||
}
|
||||
}
|
||||
}.run {
|
||||
val playedCard = playableCards(player2)[0]
|
||||
val event =
|
||||
CardIsPlayedEvent(
|
||||
aggregateId = gameId,
|
||||
card = playedCard,
|
||||
player = player2,
|
||||
version = versionBuilder.buildNextVersion(gameId),
|
||||
)
|
||||
apply(event).also { state ->
|
||||
state.aggregateId shouldBeEqual gameId
|
||||
assertNotNull(state.cardOnCurrentStack).card shouldBeEqual playedCard
|
||||
assertIs<Card.NumericCard>(playedCard).let {
|
||||
it.number shouldBeEqual 7
|
||||
it.color shouldBeEqual Card.Color.Red
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -18,113 +18,113 @@ import kotlin.test.assertNotNull
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
class GameStateRepositoryTest :
|
||||
FunSpec({
|
||||
val player1 = Player("Tesla")
|
||||
val player2 = Player(name = "Einstein")
|
||||
FunSpec({
|
||||
val player1 = Player("Tesla")
|
||||
val player2 = Player(name = "Einstein")
|
||||
|
||||
test("GameStateRepository should build the projection when a new event occurs") {
|
||||
val aggregateId = GameId()
|
||||
koinApplication { modules(appKoinModule) }.koin.apply {
|
||||
val repo = get<GameStateRepository>()
|
||||
val eventHandler = get<GameEventHandler>()
|
||||
eventHandler
|
||||
.handle(aggregateId) { NewPlayerEvent(aggregateId = aggregateId, player = player1, version = it) }
|
||||
.also { event ->
|
||||
assertNotNull(repo.getUntil(event)).also {
|
||||
assertNotNull(it.players) shouldBeEqual setOf(player1)
|
||||
}
|
||||
assertNotNull(repo.getLast(aggregateId)).also {
|
||||
assertNotNull(it.players) shouldBeEqual setOf(player1)
|
||||
}
|
||||
}
|
||||
test("GameStateRepository should build the projection when a new event occurs") {
|
||||
val aggregateId = GameId()
|
||||
koinApplication { modules(appKoinModule) }.koin.apply {
|
||||
val repo = get<GameStateRepository>()
|
||||
val eventHandler = get<GameEventHandler>()
|
||||
eventHandler
|
||||
.handle(aggregateId) { NewPlayerEvent(aggregateId = aggregateId, player = player1, version = it) }
|
||||
.also { event ->
|
||||
assertNotNull(repo.getUntil(event)).also {
|
||||
assertNotNull(it.players) shouldBeEqual setOf(player1)
|
||||
}
|
||||
stopKoin()
|
||||
}
|
||||
|
||||
test("get should build the last version of the state") {
|
||||
val aggregateId = GameId()
|
||||
koinApplication { modules(appKoinModule) }.koin.apply {
|
||||
val repo = get<GameStateRepository>()
|
||||
val eventHandler = get<GameEventHandler>()
|
||||
|
||||
eventHandler
|
||||
.handle(aggregateId) { NewPlayerEvent(aggregateId = aggregateId, player = player1, version = it) }
|
||||
.also {
|
||||
assertNotNull(repo.getLast(aggregateId)).also {
|
||||
assertNotNull(it.players) shouldBeEqual setOf(player1)
|
||||
}
|
||||
}
|
||||
|
||||
eventHandler
|
||||
.handle(aggregateId) { NewPlayerEvent(aggregateId = aggregateId, player = player2, version = it) }
|
||||
.also {
|
||||
assertNotNull(repo.getLast(aggregateId)).also {
|
||||
assertNotNull(it.players) shouldBeEqual setOf(player1, player2)
|
||||
}
|
||||
}
|
||||
assertNotNull(repo.getLast(aggregateId)).also {
|
||||
assertNotNull(it.players) shouldBeEqual setOf(player1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stopKoin()
|
||||
}
|
||||
|
||||
test("getUntil should build the state until the event") {
|
||||
repeat(10) {
|
||||
val aggregateId = GameId()
|
||||
koinApplication { modules(appKoinModule) }.koin.apply {
|
||||
val repo = get<GameStateRepository>()
|
||||
val eventHandler = get<GameEventHandler>()
|
||||
test("get should build the last version of the state") {
|
||||
val aggregateId = GameId()
|
||||
koinApplication { modules(appKoinModule) }.koin.apply {
|
||||
val repo = get<GameStateRepository>()
|
||||
val eventHandler = get<GameEventHandler>()
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
eventHandler
|
||||
.handle(aggregateId) { NewPlayerEvent(aggregateId = aggregateId, player = player1, version = it) }
|
||||
.also {
|
||||
assertNotNull(repo.getLast(aggregateId)).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)
|
||||
}
|
||||
}
|
||||
eventHandler
|
||||
.handle(aggregateId) { NewPlayerEvent(aggregateId = aggregateId, player = player2, version = it) }
|
||||
.also {
|
||||
assertNotNull(repo.getLast(aggregateId)).also {
|
||||
assertNotNull(it.players) shouldBeEqual setOf(player1, player2)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test("getUntil should build the state until the event") {
|
||||
repeat(10) {
|
||||
val aggregateId = GameId()
|
||||
koinApplication { modules(appKoinModule) }.koin.apply {
|
||||
val repo = get<GameStateRepository>()
|
||||
val eventHandler = get<GameEventHandler>()
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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") {
|
||||
val aggregateId = GameId()
|
||||
koinApplication { modules(appKoinModule) }.koin.apply {
|
||||
val repo = get<GameStateRepository>()
|
||||
val eventHandler = get<GameEventHandler>()
|
||||
test("getUntil should be concurrently secure") {
|
||||
val aggregateId = GameId()
|
||||
koinApplication { modules(appKoinModule) }.koin.apply {
|
||||
val repo = get<GameStateRepository>()
|
||||
val eventHandler = get<GameEventHandler>()
|
||||
|
||||
(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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}.joinAll()
|
||||
|
||||
repo.getLast(aggregateId).run {
|
||||
lastEventVersion shouldBeEqual 1000
|
||||
players shouldHaveSize 1000
|
||||
(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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}.joinAll()
|
||||
|
||||
xtest("get should be concurrently secure") { }
|
||||
})
|
||||
repo.getLast(aggregateId).run {
|
||||
lastEventVersion shouldBeEqual 1000
|
||||
players shouldHaveSize 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
xtest("get should be concurrently secure") { }
|
||||
})
|
||||
|
||||
@@ -3,13 +3,13 @@ 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") { }
|
||||
})
|
||||
FunSpec({
|
||||
xtest("isReady") { }
|
||||
xtest("nextPlayer") { }
|
||||
xtest("nextPlayerTurn") { }
|
||||
xtest("playerDiffIndex") { }
|
||||
xtest("cardOnBoardIsForYou") { }
|
||||
xtest("playableCards") { }
|
||||
xtest("playerHasNoCardLeft") { }
|
||||
xtest("canBePlayThisCard") { }
|
||||
})
|
||||
|
||||
@@ -20,151 +20,151 @@ import kotlin.test.assertNotNull
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
class ProjectionSnapshotRepositoryInMemoryTest :
|
||||
FunSpec({
|
||||
FunSpec({
|
||||
|
||||
test("when call applyAndPutToCache, the getUntil method must be use the built projection cache") {
|
||||
val eventStore: EventStore<TestEvents, IdTest> = EventStoreInMemory()
|
||||
val repo = getSnapshotRepoTest(eventStore)
|
||||
val aggregateId = IdTest()
|
||||
test("when call applyAndPutToCache, the getUntil method must be use the built projection cache") {
|
||||
val eventStore: EventStore<TestEvents, IdTest> = EventStoreInMemory()
|
||||
val repo = getSnapshotRepoTest(eventStore)
|
||||
val aggregateId = IdTest()
|
||||
|
||||
val eventOther = Event2Test(value2 = "valOther", version = 1, aggregateId = IdTest())
|
||||
eventStore.publish(eventOther)
|
||||
repo.applyAndPutToCache(eventOther)
|
||||
assertNotNull(repo.getUntil(eventOther)).also {
|
||||
assertNotNull(it.value) shouldBeEqual "valOther"
|
||||
}
|
||||
val eventOther = Event2Test(value2 = "valOther", version = 1, aggregateId = IdTest())
|
||||
eventStore.publish(eventOther)
|
||||
repo.applyAndPutToCache(eventOther)
|
||||
assertNotNull(repo.getUntil(eventOther)).also {
|
||||
assertNotNull(it.value) shouldBeEqual "valOther"
|
||||
}
|
||||
|
||||
val event1 = Event1Test(value1 = "val1", version = 1, aggregateId = aggregateId)
|
||||
eventStore.publish(event1)
|
||||
repo.applyAndPutToCache(event1)
|
||||
assertNotNull(repo.getLast(event1.aggregateId)).also {
|
||||
assertNotNull(it.value) shouldBeEqual "val1"
|
||||
}
|
||||
assertNotNull(repo.getUntil(event1)).also {
|
||||
assertNotNull(it.value) shouldBeEqual "val1"
|
||||
}
|
||||
val event1 = Event1Test(value1 = "val1", version = 1, aggregateId = aggregateId)
|
||||
eventStore.publish(event1)
|
||||
repo.applyAndPutToCache(event1)
|
||||
assertNotNull(repo.getLast(event1.aggregateId)).also {
|
||||
assertNotNull(it.value) shouldBeEqual "val1"
|
||||
}
|
||||
assertNotNull(repo.getUntil(event1)).also {
|
||||
assertNotNull(it.value) shouldBeEqual "val1"
|
||||
}
|
||||
|
||||
val event2 = Event2Test(value2 = "val2", version = 2, aggregateId = aggregateId)
|
||||
eventStore.publish(event2)
|
||||
repo.applyAndPutToCache(event2)
|
||||
assertNotNull(repo.getLast(event2.aggregateId)).also {
|
||||
assertNotNull(it.value) shouldBeEqual "val1val2"
|
||||
}
|
||||
assertNotNull(repo.getUntil(event1)).also {
|
||||
assertNotNull(it.value) shouldBeEqual "val1"
|
||||
}
|
||||
assertNotNull(repo.getUntil(event2)).also {
|
||||
assertNotNull(it.value) shouldBeEqual "val1val2"
|
||||
}
|
||||
}
|
||||
val event2 = Event2Test(value2 = "val2", version = 2, aggregateId = aggregateId)
|
||||
eventStore.publish(event2)
|
||||
repo.applyAndPutToCache(event2)
|
||||
assertNotNull(repo.getLast(event2.aggregateId)).also {
|
||||
assertNotNull(it.value) shouldBeEqual "val1val2"
|
||||
}
|
||||
assertNotNull(repo.getUntil(event1)).also {
|
||||
assertNotNull(it.value) shouldBeEqual "val1"
|
||||
}
|
||||
assertNotNull(repo.getUntil(event2)).also {
|
||||
assertNotNull(it.value) shouldBeEqual "val1val2"
|
||||
}
|
||||
}
|
||||
|
||||
test("ProjectionSnapshotRepositoryInMemory should be thread safe") {
|
||||
val eventStore: EventStore<TestEvents, IdTest> = EventStoreInMemory()
|
||||
val repo = getSnapshotRepoTest(eventStore)
|
||||
val aggregateId = IdTest()
|
||||
val versionBuilder = VersionBuilderLocal()
|
||||
val lock = ReentrantLock()
|
||||
(0..9)
|
||||
.map {
|
||||
GlobalScope.launch {
|
||||
(1..10).map {
|
||||
val eventX =
|
||||
lock.withLock {
|
||||
EventXTest(num = 1, version = versionBuilder.buildNextVersion(aggregateId), aggregateId = aggregateId)
|
||||
.also { eventStore.publish(it) }
|
||||
}
|
||||
repo.applyAndPutToCache(eventX)
|
||||
}
|
||||
}
|
||||
}.joinAll()
|
||||
assertNotNull(repo.getLast(aggregateId)).num shouldBeEqual 100
|
||||
}
|
||||
|
||||
test("removeOldSnapshot") {
|
||||
val versionBuilder = VersionBuilderLocal()
|
||||
val eventStore: EventStore<TestEvents, IdTest> = EventStoreInMemory()
|
||||
val repo = getSnapshotRepoTest(eventStore, SnapshotConfig(2))
|
||||
val aggregateId = IdTest()
|
||||
|
||||
fun buildEndSendEventX() {
|
||||
EventXTest(num = 1, version = versionBuilder.buildNextVersion(aggregateId), aggregateId = aggregateId)
|
||||
test("ProjectionSnapshotRepositoryInMemory should be thread safe") {
|
||||
val eventStore: EventStore<TestEvents, IdTest> = EventStoreInMemory()
|
||||
val repo = getSnapshotRepoTest(eventStore)
|
||||
val aggregateId = IdTest()
|
||||
val versionBuilder = VersionBuilderLocal()
|
||||
val lock = ReentrantLock()
|
||||
(0..9)
|
||||
.map {
|
||||
GlobalScope.launch {
|
||||
(1..10).map {
|
||||
val eventX =
|
||||
lock.withLock {
|
||||
EventXTest(num = 1, version = versionBuilder.buildNextVersion(aggregateId), aggregateId = aggregateId)
|
||||
.also { eventStore.publish(it) }
|
||||
.also { repo.applyAndPutToCache(it) }
|
||||
}
|
||||
repo.applyAndPutToCache(eventX)
|
||||
}
|
||||
}
|
||||
}.joinAll()
|
||||
assertNotNull(repo.getLast(aggregateId)).num shouldBeEqual 100
|
||||
}
|
||||
|
||||
buildEndSendEventX()
|
||||
repo.getLast(aggregateId).num shouldBeEqual 1
|
||||
buildEndSendEventX()
|
||||
repo.getLast(aggregateId).num shouldBeEqual 2
|
||||
buildEndSendEventX()
|
||||
repo.getLast(aggregateId).num shouldBeEqual 3
|
||||
buildEndSendEventX()
|
||||
repo.getLast(aggregateId).num shouldBeEqual 4
|
||||
}
|
||||
})
|
||||
test("removeOldSnapshot") {
|
||||
val versionBuilder = VersionBuilderLocal()
|
||||
val eventStore: EventStore<TestEvents, IdTest> = EventStoreInMemory()
|
||||
val repo = getSnapshotRepoTest(eventStore, SnapshotConfig(2))
|
||||
val aggregateId = IdTest()
|
||||
|
||||
fun buildEndSendEventX() {
|
||||
EventXTest(num = 1, version = versionBuilder.buildNextVersion(aggregateId), aggregateId = aggregateId)
|
||||
.also { eventStore.publish(it) }
|
||||
.also { repo.applyAndPutToCache(it) }
|
||||
}
|
||||
|
||||
buildEndSendEventX()
|
||||
repo.getLast(aggregateId).num shouldBeEqual 1
|
||||
buildEndSendEventX()
|
||||
repo.getLast(aggregateId).num shouldBeEqual 2
|
||||
buildEndSendEventX()
|
||||
repo.getLast(aggregateId).num shouldBeEqual 3
|
||||
buildEndSendEventX()
|
||||
repo.getLast(aggregateId).num shouldBeEqual 4
|
||||
}
|
||||
})
|
||||
|
||||
@JvmInline
|
||||
private value class IdTest(
|
||||
override val id: UUID = UUID.randomUUID(),
|
||||
override val id: UUID = UUID.randomUUID(),
|
||||
) : AggregateId
|
||||
|
||||
private data class ProjectionTest(
|
||||
override val aggregateId: IdTest,
|
||||
override val lastEventVersion: Int = 0,
|
||||
var value: String? = null,
|
||||
var num: Int = 0,
|
||||
override val aggregateId: IdTest,
|
||||
override val lastEventVersion: Int = 0,
|
||||
var value: String? = null,
|
||||
var num: Int = 0,
|
||||
) : Projection<IdTest>
|
||||
|
||||
private sealed interface TestEvents : Event<IdTest>
|
||||
|
||||
private data class Event1Test(
|
||||
override val eventId: UUID = UUID.randomUUID(),
|
||||
override val aggregateId: IdTest,
|
||||
override val createdAt: Instant = Clock.System.now(),
|
||||
override val version: Int,
|
||||
val value1: String,
|
||||
override val eventId: UUID = UUID.randomUUID(),
|
||||
override val aggregateId: IdTest,
|
||||
override val createdAt: Instant = Clock.System.now(),
|
||||
override val version: Int,
|
||||
val value1: String,
|
||||
) : TestEvents
|
||||
|
||||
private data class Event2Test(
|
||||
override val eventId: UUID = UUID.randomUUID(),
|
||||
override val aggregateId: IdTest,
|
||||
override val createdAt: Instant = Clock.System.now(),
|
||||
override val version: Int,
|
||||
val value2: String,
|
||||
override val eventId: UUID = UUID.randomUUID(),
|
||||
override val aggregateId: IdTest,
|
||||
override val createdAt: Instant = Clock.System.now(),
|
||||
override val version: Int,
|
||||
val value2: String,
|
||||
) : TestEvents
|
||||
|
||||
private data class EventXTest(
|
||||
override val eventId: UUID = UUID.randomUUID(),
|
||||
override val aggregateId: IdTest,
|
||||
override val createdAt: Instant = Clock.System.now(),
|
||||
override val version: Int,
|
||||
val num: Int,
|
||||
override val eventId: UUID = UUID.randomUUID(),
|
||||
override val aggregateId: IdTest,
|
||||
override val createdAt: Instant = Clock.System.now(),
|
||||
override val version: Int,
|
||||
val num: Int,
|
||||
) : TestEvents
|
||||
|
||||
private fun getSnapshotRepoTest(
|
||||
eventStore: EventStore<TestEvents, IdTest>,
|
||||
snapshotConfig: SnapshotConfig = SnapshotConfig(2000),
|
||||
eventStore: EventStore<TestEvents, IdTest>,
|
||||
snapshotConfig: SnapshotConfig = SnapshotConfig(2000),
|
||||
): ProjectionSnapshotRepositoryInMemory<TestEvents, ProjectionTest, IdTest> =
|
||||
ProjectionSnapshotRepositoryInMemory(
|
||||
eventStore = eventStore,
|
||||
initialStateBuilder = { aggregateId: IdTest -> ProjectionTest(aggregateId) },
|
||||
snapshotCacheConfig = snapshotConfig,
|
||||
) { event ->
|
||||
this.let { projection ->
|
||||
when (event) {
|
||||
is Event1Test -> {
|
||||
projection.copy(value = (projection.value ?: "") + event.value1)
|
||||
}
|
||||
|
||||
is Event2Test -> {
|
||||
projection.copy(value = (projection.value ?: "") + event.value2)
|
||||
}
|
||||
|
||||
is EventXTest -> {
|
||||
projection.copy(num = projection.num + event.num)
|
||||
}
|
||||
}.copy(
|
||||
lastEventVersion = event.version,
|
||||
)
|
||||
ProjectionSnapshotRepositoryInMemory(
|
||||
eventStore = eventStore,
|
||||
initialStateBuilder = { aggregateId: IdTest -> ProjectionTest(aggregateId) },
|
||||
snapshotCacheConfig = snapshotConfig,
|
||||
) { event ->
|
||||
this.let { projection ->
|
||||
when (event) {
|
||||
is Event1Test -> {
|
||||
projection.copy(value = (projection.value ?: "") + event.value1)
|
||||
}
|
||||
|
||||
is Event2Test -> {
|
||||
projection.copy(value = (projection.value ?: "") + event.value2)
|
||||
}
|
||||
|
||||
is EventXTest -> {
|
||||
projection.copy(num = projection.num + event.num)
|
||||
}
|
||||
}.copy(
|
||||
lastEventVersion = event.version,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,89 +33,89 @@ import kotlin.test.assertIs
|
||||
import kotlin.test.assertNotNull
|
||||
|
||||
class GameStateRouteTest :
|
||||
FunSpec({
|
||||
test("/game/{id}/state on empty game") {
|
||||
testApplication {
|
||||
val id = GameId()
|
||||
val player1 = Player(name = "Nikola")
|
||||
application {
|
||||
stopKoin()
|
||||
configure()
|
||||
}
|
||||
|
||||
httpClient()
|
||||
.get("/game/$id/state") {
|
||||
withAuth(player1)
|
||||
accept(ContentType.Application.Json)
|
||||
}.apply {
|
||||
assertEquals(HttpStatusCode.OK, status, message = bodyAsText())
|
||||
val state = call.body<GameState>()
|
||||
id shouldBeEqual state.aggregateId
|
||||
state.players shouldHaveSize 0
|
||||
state.isStarted shouldBeEqual false
|
||||
}
|
||||
}
|
||||
FunSpec({
|
||||
test("/game/{id}/state on empty game") {
|
||||
testApplication {
|
||||
val id = GameId()
|
||||
val player1 = Player(name = "Nikola")
|
||||
application {
|
||||
stopKoin()
|
||||
configure()
|
||||
}
|
||||
|
||||
test("/game/{id}/card/last") {
|
||||
testApplication {
|
||||
val gameId = GameId()
|
||||
val player1 = Player(name = "Nikola")
|
||||
val player2 = Player(name = "Einstein")
|
||||
var lastPlayedCard: Card? = null
|
||||
httpClient()
|
||||
.get("/game/$id/state") {
|
||||
withAuth(player1)
|
||||
accept(ContentType.Application.Json)
|
||||
}.apply {
|
||||
assertEquals(HttpStatusCode.OK, status, message = bodyAsText())
|
||||
val state = call.body<GameState>()
|
||||
id shouldBeEqual state.aggregateId
|
||||
state.players shouldHaveSize 0
|
||||
state.isStarted shouldBeEqual false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
application {
|
||||
stopKoin()
|
||||
configure()
|
||||
test("/game/{id}/card/last") {
|
||||
testApplication {
|
||||
val gameId = GameId()
|
||||
val player1 = Player(name = "Nikola")
|
||||
val player2 = Player(name = "Einstein")
|
||||
var lastPlayedCard: Card? = null
|
||||
|
||||
val eventHandler by inject<GameEventHandler>()
|
||||
val stateRepo by inject<GameStateRepository>()
|
||||
runBlocking {
|
||||
eventHandler.handle(gameId) { NewPlayerEvent(gameId, player1, it) }
|
||||
eventHandler.handle(gameId) { NewPlayerEvent(gameId, player2, it) }
|
||||
eventHandler.handle(gameId) { PlayerReadyEvent(gameId, player1, it) }
|
||||
eventHandler.handle(gameId) { PlayerReadyEvent(gameId, player2, it) }
|
||||
eventHandler.handle(gameId) {
|
||||
GameStartedEvent.new(
|
||||
gameId,
|
||||
setOf(player1, player2),
|
||||
shuffleIsDisabled = true,
|
||||
it,
|
||||
)
|
||||
}
|
||||
delay(100)
|
||||
lastPlayedCard = stateRepo.getLast(gameId).playableCards(player1).first()
|
||||
assertNotNull(lastPlayedCard)
|
||||
.let { assertIs<Card.NumericCard>(lastPlayedCard) }
|
||||
.let {
|
||||
it.number shouldBeEqual 0
|
||||
it.color shouldBeEqual Card.Color.Red
|
||||
}
|
||||
delay(100)
|
||||
eventHandler.handle(gameId) {
|
||||
CardIsPlayedEvent(
|
||||
gameId,
|
||||
assertNotNull(lastPlayedCard),
|
||||
player1,
|
||||
it,
|
||||
)
|
||||
}
|
||||
delay(100)
|
||||
}
|
||||
}
|
||||
application {
|
||||
stopKoin()
|
||||
configure()
|
||||
|
||||
httpClient()
|
||||
.get("/game/$gameId/card/last") {
|
||||
withAuth(player1)
|
||||
accept(ContentType.Application.Json)
|
||||
}.apply {
|
||||
assertEquals(HttpStatusCode.OK, status, message = bodyAsText())
|
||||
assertEquals(assertNotNull(lastPlayedCard), call.body<Card>())
|
||||
}
|
||||
val eventHandler by inject<GameEventHandler>()
|
||||
val stateRepo by inject<GameStateRepository>()
|
||||
runBlocking {
|
||||
eventHandler.handle(gameId) { NewPlayerEvent(gameId, player1, it) }
|
||||
eventHandler.handle(gameId) { NewPlayerEvent(gameId, player2, it) }
|
||||
eventHandler.handle(gameId) { PlayerReadyEvent(gameId, player1, it) }
|
||||
eventHandler.handle(gameId) { PlayerReadyEvent(gameId, player2, it) }
|
||||
eventHandler.handle(gameId) {
|
||||
GameStartedEvent.new(
|
||||
gameId,
|
||||
setOf(player1, player2),
|
||||
shuffleIsDisabled = true,
|
||||
it,
|
||||
)
|
||||
}
|
||||
delay(100)
|
||||
lastPlayedCard = stateRepo.getLast(gameId).playableCards(player1).first()
|
||||
assertNotNull(lastPlayedCard)
|
||||
.let { assertIs<Card.NumericCard>(lastPlayedCard) }
|
||||
.let {
|
||||
it.number shouldBeEqual 0
|
||||
it.color shouldBeEqual Card.Color.Red
|
||||
}
|
||||
delay(100)
|
||||
eventHandler.handle(gameId) {
|
||||
CardIsPlayedEvent(
|
||||
gameId,
|
||||
assertNotNull(lastPlayedCard),
|
||||
player1,
|
||||
it,
|
||||
)
|
||||
}
|
||||
delay(100)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
httpClient()
|
||||
.get("/game/$gameId/card/last") {
|
||||
withAuth(player1)
|
||||
accept(ContentType.Application.Json)
|
||||
}.apply {
|
||||
assertEquals(HttpStatusCode.OK, status, message = bodyAsText())
|
||||
assertEquals(assertNotNull(lastPlayedCard), call.body<Card>())
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
private fun HttpRequestBuilder.withAuth(player: Player) {
|
||||
header("Authorization", "Bearer ${player.makeJwt()}")
|
||||
header("Authorization", "Bearer ${player.makeJwt()}")
|
||||
}
|
||||
|
||||
@@ -42,127 +42,127 @@ import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
@DelicateCoroutinesApi
|
||||
class GameStateTest :
|
||||
FunSpec({
|
||||
test("Simulation of a game") {
|
||||
withTimeout(2.seconds) {
|
||||
disableShuffleDeck()
|
||||
val id = GameId()
|
||||
val player1 = Player(name = "Nikola")
|
||||
val player2 = Player(name = "Einstein")
|
||||
val channelCommand1 = Channel<GameCommand>(Channel.BUFFERED)
|
||||
val channelCommand2 = Channel<GameCommand>(Channel.BUFFERED)
|
||||
val channelNotification1 = Channel<Notification>(Channel.BUFFERED)
|
||||
val channelNotification2 = Channel<Notification>(Channel.BUFFERED)
|
||||
FunSpec({
|
||||
test("Simulation of a game") {
|
||||
withTimeout(2.seconds) {
|
||||
disableShuffleDeck()
|
||||
val id = GameId()
|
||||
val player1 = Player(name = "Nikola")
|
||||
val player2 = Player(name = "Einstein")
|
||||
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
|
||||
var playedCard1: Card? = null
|
||||
var playedCard2: Card? = null
|
||||
|
||||
val player1Job =
|
||||
launch {
|
||||
channelCommand1.send(IWantToJoinTheGameCommand(IWantToJoinTheGameCommand.Payload(id, player1)))
|
||||
channelNotification1.receive().let {
|
||||
assertIs<WelcomeToTheGameNotification>(it).players shouldBeEqual setOf(player1)
|
||||
}
|
||||
channelNotification1.receive().let {
|
||||
assertIs<PlayerAsJoinTheGameNotification>(it).player shouldBeEqual player2
|
||||
}
|
||||
channelCommand1.send(IamReadyToPlayCommand(IamReadyToPlayCommand.Payload(id, player1)))
|
||||
channelNotification1.receive().let {
|
||||
assertIs<PlayerWasReadyNotification>(it).player shouldBeEqual player2
|
||||
}
|
||||
val player1Hand =
|
||||
channelNotification1.receive().let {
|
||||
assertIs<TheGameWasStartedNotification>(it).hand shouldHaveSize 7
|
||||
}
|
||||
playedCard1 = player1Hand.first()
|
||||
channelNotification1.receive().let {
|
||||
assertIs<ItsTheTurnOfNotification>(it).apply {
|
||||
player shouldBeEqual player1
|
||||
}
|
||||
}
|
||||
channelCommand1.send(IWantToPlayCardCommand(IWantToPlayCardCommand.Payload(id, player1, player1Hand.first())))
|
||||
|
||||
channelNotification1.receive().let {
|
||||
assertIs<ItsTheTurnOfNotification>(it).apply {
|
||||
player shouldBeEqual player2
|
||||
}
|
||||
}
|
||||
|
||||
channelNotification1.receive().let {
|
||||
assertIs<PlayerAsPlayACardNotification>(it).apply {
|
||||
player shouldBeEqual player2
|
||||
card shouldBeEqual assertNotNull(playedCard2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val player2Job =
|
||||
launch {
|
||||
delay(100)
|
||||
channelCommand2.send(IWantToJoinTheGameCommand(IWantToJoinTheGameCommand.Payload(id, player2)))
|
||||
channelNotification2.receive().let {
|
||||
assertIs<WelcomeToTheGameNotification>(it).players shouldBeEqual setOf(player1, player2)
|
||||
}
|
||||
channelNotification2.receive().let {
|
||||
assertIs<PlayerWasReadyNotification>(it).player shouldBeEqual player1
|
||||
}
|
||||
channelCommand2.send(IamReadyToPlayCommand(IamReadyToPlayCommand.Payload(id, player2)))
|
||||
val player2Hand =
|
||||
channelNotification2.receive().let {
|
||||
assertIs<TheGameWasStartedNotification>(it).hand shouldHaveSize 7
|
||||
}
|
||||
channelNotification2.receive().let {
|
||||
assertIs<ItsTheTurnOfNotification>(it).apply {
|
||||
player shouldBeEqual player1
|
||||
}
|
||||
}
|
||||
channelNotification2.receive().let {
|
||||
assertIs<PlayerAsPlayACardNotification>(it).apply {
|
||||
player shouldBeEqual player1
|
||||
card shouldBeEqual assertNotNull(playedCard1)
|
||||
}
|
||||
}
|
||||
playedCard2 = player2Hand.first()
|
||||
|
||||
channelNotification2.receive().let {
|
||||
assertIs<ItsTheTurnOfNotification>(it).apply {
|
||||
player shouldBeEqual player2
|
||||
}
|
||||
}
|
||||
channelCommand2.send(IWantToPlayCardCommand(IWantToPlayCardCommand.Payload(id, player2, player2Hand.first())))
|
||||
}
|
||||
|
||||
koinApplication { modules(appKoinModule) }.koin.apply {
|
||||
val commandHandler by inject<GameCommandHandler>()
|
||||
val eventStore by inject<GameEventStore>()
|
||||
val playerNotificationListener by inject<PlayerNotificationEventListener>()
|
||||
ReactionEventListener(get(), get(), get()).init()
|
||||
playerNotificationListener.startListening(channelNotification1, player1)
|
||||
playerNotificationListener.startListening(channelNotification2, player2)
|
||||
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
commandHandler.handle(player1, channelCommand1, channelNotification1)
|
||||
}
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
commandHandler.handle(player2, channelCommand2, channelNotification2)
|
||||
}
|
||||
|
||||
joinAll(player1Job, player2Job)
|
||||
|
||||
val state =
|
||||
ProjectionSnapshotRepositoryInMemory(
|
||||
eventStore = eventStore,
|
||||
initialStateBuilder = { aggregateId: GameId -> GameState(aggregateId) },
|
||||
applyToProjection = GameState::apply,
|
||||
).getLast(id)
|
||||
|
||||
state.aggregateId shouldBeEqual id
|
||||
assertTrue(state.isStarted)
|
||||
state.players shouldBeEqual setOf(player1, player2)
|
||||
state.readyPlayers shouldBeEqual setOf(player1, player2)
|
||||
state.direction shouldBeEqual GameState.Direction.CLOCKWISE
|
||||
assertNotNull(state.cardOnCurrentStack) shouldBeEqual GameState.LastCard(assertNotNull(playedCard2), player2)
|
||||
}
|
||||
val player1Job =
|
||||
launch {
|
||||
channelCommand1.send(IWantToJoinTheGameCommand(IWantToJoinTheGameCommand.Payload(id, player1)))
|
||||
channelNotification1.receive().let {
|
||||
assertIs<WelcomeToTheGameNotification>(it).players shouldBeEqual setOf(player1)
|
||||
}
|
||||
channelNotification1.receive().let {
|
||||
assertIs<PlayerAsJoinTheGameNotification>(it).player shouldBeEqual player2
|
||||
}
|
||||
channelCommand1.send(IamReadyToPlayCommand(IamReadyToPlayCommand.Payload(id, player1)))
|
||||
channelNotification1.receive().let {
|
||||
assertIs<PlayerWasReadyNotification>(it).player shouldBeEqual player2
|
||||
}
|
||||
val player1Hand =
|
||||
channelNotification1.receive().let {
|
||||
assertIs<TheGameWasStartedNotification>(it).hand shouldHaveSize 7
|
||||
}
|
||||
playedCard1 = player1Hand.first()
|
||||
channelNotification1.receive().let {
|
||||
assertIs<ItsTheTurnOfNotification>(it).apply {
|
||||
player shouldBeEqual player1
|
||||
}
|
||||
}
|
||||
channelCommand1.send(IWantToPlayCardCommand(IWantToPlayCardCommand.Payload(id, player1, player1Hand.first())))
|
||||
|
||||
channelNotification1.receive().let {
|
||||
assertIs<ItsTheTurnOfNotification>(it).apply {
|
||||
player shouldBeEqual player2
|
||||
}
|
||||
}
|
||||
|
||||
channelNotification1.receive().let {
|
||||
assertIs<PlayerAsPlayACardNotification>(it).apply {
|
||||
player shouldBeEqual player2
|
||||
card shouldBeEqual assertNotNull(playedCard2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val player2Job =
|
||||
launch {
|
||||
delay(100)
|
||||
channelCommand2.send(IWantToJoinTheGameCommand(IWantToJoinTheGameCommand.Payload(id, player2)))
|
||||
channelNotification2.receive().let {
|
||||
assertIs<WelcomeToTheGameNotification>(it).players shouldBeEqual setOf(player1, player2)
|
||||
}
|
||||
channelNotification2.receive().let {
|
||||
assertIs<PlayerWasReadyNotification>(it).player shouldBeEqual player1
|
||||
}
|
||||
channelCommand2.send(IamReadyToPlayCommand(IamReadyToPlayCommand.Payload(id, player2)))
|
||||
val player2Hand =
|
||||
channelNotification2.receive().let {
|
||||
assertIs<TheGameWasStartedNotification>(it).hand shouldHaveSize 7
|
||||
}
|
||||
channelNotification2.receive().let {
|
||||
assertIs<ItsTheTurnOfNotification>(it).apply {
|
||||
player shouldBeEqual player1
|
||||
}
|
||||
}
|
||||
channelNotification2.receive().let {
|
||||
assertIs<PlayerAsPlayACardNotification>(it).apply {
|
||||
player shouldBeEqual player1
|
||||
card shouldBeEqual assertNotNull(playedCard1)
|
||||
}
|
||||
}
|
||||
playedCard2 = player2Hand.first()
|
||||
|
||||
channelNotification2.receive().let {
|
||||
assertIs<ItsTheTurnOfNotification>(it).apply {
|
||||
player shouldBeEqual player2
|
||||
}
|
||||
}
|
||||
channelCommand2.send(IWantToPlayCardCommand(IWantToPlayCardCommand.Payload(id, player2, player2Hand.first())))
|
||||
}
|
||||
|
||||
koinApplication { modules(appKoinModule) }.koin.apply {
|
||||
val commandHandler by inject<GameCommandHandler>()
|
||||
val eventStore by inject<GameEventStore>()
|
||||
val playerNotificationListener by inject<PlayerNotificationEventListener>()
|
||||
ReactionEventListener(get(), get(), get()).init()
|
||||
playerNotificationListener.startListening(channelNotification1, player1)
|
||||
playerNotificationListener.startListening(channelNotification2, player2)
|
||||
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
commandHandler.handle(player1, channelCommand1, channelNotification1)
|
||||
}
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
commandHandler.handle(player2, channelCommand2, channelNotification2)
|
||||
}
|
||||
|
||||
joinAll(player1Job, player2Job)
|
||||
|
||||
val state =
|
||||
ProjectionSnapshotRepositoryInMemory(
|
||||
eventStore = eventStore,
|
||||
initialStateBuilder = { aggregateId: GameId -> GameState(aggregateId) },
|
||||
applyToProjection = GameState::apply,
|
||||
).getLast(id)
|
||||
|
||||
state.aggregateId shouldBeEqual id
|
||||
assertTrue(state.isStarted)
|
||||
state.players shouldBeEqual setOf(player1, player2)
|
||||
state.readyPlayers shouldBeEqual setOf(player1, player2)
|
||||
state.direction shouldBeEqual GameState.Direction.CLOCKWISE
|
||||
assertNotNull(state.cardOnCurrentStack) shouldBeEqual GameState.LastCard(assertNotNull(playedCard2), player2)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -6,10 +6,10 @@ import io.ktor.serialization.kotlinx.json.json
|
||||
import io.ktor.server.testing.ApplicationTestBuilder
|
||||
|
||||
fun ApplicationTestBuilder.httpClient(): HttpClient =
|
||||
createClient {
|
||||
install(ContentNegotiation) {
|
||||
json(
|
||||
defaultJsonSerializer(),
|
||||
)
|
||||
}
|
||||
createClient {
|
||||
install(ContentNegotiation) {
|
||||
json(
|
||||
defaultJsonSerializer(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,42 +14,42 @@ import kotlin.test.assertIs
|
||||
|
||||
@Serializable
|
||||
data class CommandTest(
|
||||
override val id: CommandId,
|
||||
override val id: CommandId,
|
||||
) : Command
|
||||
|
||||
class FrameChannelConverterTest :
|
||||
FunSpec({
|
||||
FunSpec({
|
||||
|
||||
test("toObjectChannel") {
|
||||
val uuid = "d737c631-76af-406e-bc29-f3e5b97226a5"
|
||||
val id = CommandId(UUID.fromString(uuid))
|
||||
val jsonCommand = """{"id":"$uuid"}"""
|
||||
test("toObjectChannel") {
|
||||
val uuid = "d737c631-76af-406e-bc29-f3e5b97226a5"
|
||||
val id = CommandId(UUID.fromString(uuid))
|
||||
val jsonCommand = """{"id":"$uuid"}"""
|
||||
|
||||
val channel = Channel<Frame>()
|
||||
val channel = Channel<Frame>()
|
||||
|
||||
launch {
|
||||
val commandChannel = toObjectChannel<CommandTest>(channel)
|
||||
commandChannel.receive().id shouldBeEqual id
|
||||
channel.close()
|
||||
}
|
||||
launch {
|
||||
val commandChannel = toObjectChannel<CommandTest>(channel)
|
||||
commandChannel.receive().id shouldBeEqual id
|
||||
channel.close()
|
||||
}
|
||||
|
||||
channel.send(Frame.Text(jsonCommand))
|
||||
}
|
||||
channel.send(Frame.Text(jsonCommand))
|
||||
}
|
||||
|
||||
test("fromFrameChannel") {
|
||||
val uuid = "d737c631-76af-406e-bc29-f3e5b97226a5"
|
||||
val id = CommandId(UUID.fromString(uuid))
|
||||
val command = CommandTest(id)
|
||||
val jsonCommand = """{"id":"$uuid"}"""
|
||||
test("fromFrameChannel") {
|
||||
val uuid = "d737c631-76af-406e-bc29-f3e5b97226a5"
|
||||
val id = CommandId(UUID.fromString(uuid))
|
||||
val command = CommandTest(id)
|
||||
val jsonCommand = """{"id":"$uuid"}"""
|
||||
|
||||
val channel = Channel<Frame>()
|
||||
val channel = Channel<Frame>()
|
||||
|
||||
launch {
|
||||
val commandChannel = fromFrameChannel<CommandTest>(channel)
|
||||
commandChannel.send(command)
|
||||
commandChannel.close()
|
||||
}
|
||||
launch {
|
||||
val commandChannel = fromFrameChannel<CommandTest>(channel)
|
||||
commandChannel.send(command)
|
||||
commandChannel.close()
|
||||
}
|
||||
|
||||
assertIs<Frame.Text>(channel.receive()).readText() shouldBeEqual jsonCommand
|
||||
}
|
||||
})
|
||||
assertIs<Frame.Text>(channel.receive()).readText() shouldBeEqual jsonCommand
|
||||
}
|
||||
})
|
||||
|
||||
@@ -8,26 +8,26 @@ import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
class CommandTest(
|
||||
override val id: CommandId,
|
||||
override val id: CommandId,
|
||||
) : Command
|
||||
|
||||
class CommandStreamChannelTest :
|
||||
FunSpec({
|
||||
FunSpec({
|
||||
|
||||
test("send and receive") {
|
||||
val command = CommandTest(CommandId())
|
||||
test("send and receive") {
|
||||
val command = CommandTest(CommandId())
|
||||
|
||||
val channel = Channel<CommandTest>()
|
||||
val stream =
|
||||
CommandStreamChannel(channel)
|
||||
val channel = Channel<CommandTest>()
|
||||
val stream =
|
||||
CommandStreamChannel(channel)
|
||||
|
||||
val spyCall: () -> Unit = mockk(relaxed = true)
|
||||
val spyCall: () -> Unit = mockk(relaxed = true)
|
||||
|
||||
stream.blockAndProcess {
|
||||
println("In action ${it.id}")
|
||||
spyCall()
|
||||
}
|
||||
channel.send(command)
|
||||
verify(exactly = 1) { spyCall() }
|
||||
}
|
||||
})
|
||||
stream.blockAndProcess {
|
||||
println("In action ${it.id}")
|
||||
spyCall()
|
||||
}
|
||||
channel.send(command)
|
||||
verify(exactly = 1) { spyCall() }
|
||||
}
|
||||
})
|
||||
|
||||
@@ -3,8 +3,8 @@ package eventDemo.libs.event
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
|
||||
class EventBusInMemoryTest :
|
||||
FunSpec({
|
||||
FunSpec({
|
||||
|
||||
xtest("publish should call the subscribed functions") { }
|
||||
xtest("publish should call the subscribed functions on the priority order") { }
|
||||
})
|
||||
xtest("publish should call the subscribed functions") { }
|
||||
xtest("publish should call the subscribed functions on the priority order") { }
|
||||
})
|
||||
|
||||
@@ -3,14 +3,14 @@ package eventDemo.libs.event
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
|
||||
class EventStreamInMemoryTest :
|
||||
FunSpec({
|
||||
FunSpec({
|
||||
|
||||
xtest("publish should be concurrently secure") { }
|
||||
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("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("readLastOf should return the last event of the aggregate of the type") { }
|
||||
|
||||
xtest("readAll should only return the event of aggregate") { }
|
||||
})
|
||||
xtest("readAll should only return the event of aggregate") { }
|
||||
})
|
||||
|
||||
@@ -10,43 +10,43 @@ import java.util.UUID
|
||||
|
||||
@JvmInline
|
||||
private value class IdTest(
|
||||
override val id: UUID = UUID.randomUUID(),
|
||||
override val id: UUID = UUID.randomUUID(),
|
||||
) : AggregateId
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
class VersionBuilderLocalTest :
|
||||
FunSpec({
|
||||
FunSpec({
|
||||
|
||||
test("buildNextVersion") {
|
||||
VersionBuilderLocal().run {
|
||||
val id = IdTest()
|
||||
buildNextVersion(id) shouldBeEqual 1
|
||||
buildNextVersion(id) shouldBeEqual 2
|
||||
buildNextVersion(IdTest()) shouldBeEqual 1
|
||||
buildNextVersion(id) shouldBeEqual 3
|
||||
test("buildNextVersion") {
|
||||
VersionBuilderLocal().run {
|
||||
val id = IdTest()
|
||||
buildNextVersion(id) shouldBeEqual 1
|
||||
buildNextVersion(id) shouldBeEqual 2
|
||||
buildNextVersion(IdTest()) shouldBeEqual 1
|
||||
buildNextVersion(id) shouldBeEqual 3
|
||||
}
|
||||
}
|
||||
|
||||
test("buildNextVersion concurrently") {
|
||||
val versionBuilder = VersionBuilderLocal()
|
||||
val id = IdTest()
|
||||
(1..20)
|
||||
.map {
|
||||
GlobalScope.launch {
|
||||
(1..1000).map {
|
||||
versionBuilder.buildNextVersion(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}.joinAll()
|
||||
versionBuilder.getLastVersion(id) shouldBeEqual 20 * 1000
|
||||
}
|
||||
|
||||
test("buildNextVersion concurrently") {
|
||||
val versionBuilder = VersionBuilderLocal()
|
||||
val id = IdTest()
|
||||
(1..20)
|
||||
.map {
|
||||
GlobalScope.launch {
|
||||
(1..1000).map {
|
||||
versionBuilder.buildNextVersion(id)
|
||||
}
|
||||
}
|
||||
}.joinAll()
|
||||
versionBuilder.getLastVersion(id) shouldBeEqual 20 * 1000
|
||||
}
|
||||
|
||||
test("getLastVersion") {
|
||||
VersionBuilderLocal().run {
|
||||
val id = IdTest()
|
||||
getLastVersion(id) shouldBeEqual 0
|
||||
getLastVersion(id) shouldBeEqual 0
|
||||
getLastVersion(id) shouldBeEqual 0
|
||||
}
|
||||
}
|
||||
})
|
||||
test("getLastVersion") {
|
||||
VersionBuilderLocal().run {
|
||||
val id = IdTest()
|
||||
getLastVersion(id) shouldBeEqual 0
|
||||
getLastVersion(id) shouldBeEqual 0
|
||||
getLastVersion(id) shouldBeEqual 0
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user