Skip to content

Commit

Permalink
introduced kotest assertions
Browse files Browse the repository at this point in the history
  • Loading branch information
Rodolfo committed Dec 6, 2024
1 parent 31fc64a commit c0f1731
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 51 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ So far, just an experiment

* [The Aggregate is dead. Long live the Aggregate! - Sara Pellegrini & Milan Savić. - The main motivation for Crablet](https://www.youtube.com/watch?v=MpalYQaKKd4)
* [Event Sourcing You are doing it wrong by David Schmitz. - Very good advices. I will try events as plain JSON.](https://www.youtube.com/watch?v=GzrZworHpIk)
* [Json-values: I guess it's a perfect library for using events as plain JSON. Crablet is agnostic about it, but I will try it in Crablet examples.](https://github.com/imrafaelmerino/json-values) by [Rafael Merino](https://github.com/imrafaelmerino)
* [Json-values: I guess it's a perfect library for using events as plain JSON. Crablet is agnostic about it, but I will try it in Crablet examples.](https://github.com/imrafaelmerino/json-values)
by [Rafael Merino](https://github.com/imrafaelmerino)
* [My previous event sourcing experiment: Crabzilla. I learned a lot but it ended as a framework. Crablet hopefully will be just a library.](https://github.com/crabzilla/crabzilla)
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@
<version>1.19.8</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.kotest</groupId>
<artifactId>kotest-assertions-core-jvm</artifactId>
<version>5.9.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.imrafaelmerino</groupId>
<artifactId>json-values</artifactId>
Expand Down
4 changes: 2 additions & 2 deletions src/main/kotlin/crablet/Crablet.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ data class DomainIdentifier(val name: StateName, val id: StateId) {

data class StreamQuery(val identifiers: List<DomainIdentifier>, val eventTypes: List<EventName>)

// write

data class AppendCondition(val query: StreamQuery, val maximumEventSequence: SequenceNumber)

// write

interface EventsAppender {
fun appendIf(events: List<JsonObject>, appendCondition: AppendCondition): Future<SequenceNumber>
}
Expand Down
7 changes: 3 additions & 4 deletions src/main/kotlin/crablet/postgres/CrabletEventsAppender.kt
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,9 @@ class CrabletEventsAppender(private val client: Pool) : EventsAppender {
connection.preparedQuery(functionCall)
.execute(params)
}.onSuccess { rowSet ->
// Extract the result (last_sequence_id) from the first row
val latestSequenceId = rowSet.first().getLong("last_sequence_id")
if (latestSequenceId != null) {
promise.complete(SequenceNumber(latestSequenceId))
if (rowSet.rowCount() == 1 && rowSet.first().getLong("last_sequence_id") != null) {
// Extract the result (last_sequence_id) from the first row
promise.complete(SequenceNumber(rowSet.first().getLong("last_sequence_id")))
} else {
promise.fail("No last_sequence_id returned from append_events function")
}
Expand Down
4 changes: 2 additions & 2 deletions src/main/resources/ddl/1-events_table.sql
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ CREATE TABLE events

CREATE INDEX domain_ids_gin_index ON events USING gin (domain_ids);

CREATE INDEX idx_events_event_type ON events(event_type);
CREATE INDEX idx_events_event_type ON events (event_type);

CREATE INDEX idx_events_correlation_id ON events(correlation_id);
CREATE INDEX idx_events_correlation_id ON events (correlation_id);
85 changes: 43 additions & 42 deletions src/test/kotlin/crablet/postgres/AccountTransferScenarioTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import crablet.SequenceNumber
import crablet.StateId
import crablet.StateName
import crablet.StreamQuery
import io.kotest.matchers.ints.shouldBeExactly
import io.kotest.matchers.longs.shouldBeExactly
import io.kotest.matchers.shouldBe
import io.vertx.core.json.JsonObject
import io.vertx.junit5.VertxExtension
import io.vertx.junit5.VertxTestContext
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.MethodOrderer
import org.junit.jupiter.api.Order
Expand All @@ -31,7 +33,7 @@ class AccountTransferScenarioTest : AbstractCrabletTest() {
)
val appendCondition = AppendCondition(query = streamQuery, maximumEventSequence = SequenceNumber(0))
val eventsToAppend = listOf(
JsonObject().put("type", "AccountOpened").put("id", "1"),
JsonObject().put("type", "AccountOpened").put("id", 1),
JsonObject().put("type", "AmountDeposited").put("amount", 100)
)
eventsAppender.appendIf(eventsToAppend, appendCondition)
Expand All @@ -43,9 +45,9 @@ class AccountTransferScenarioTest : AbstractCrabletTest() {
}
.onSuccess { (state, sequence): Pair<Account, SequenceNumber> ->
testContext.verify {
assertEquals(2, sequence.value)
assertEquals("1", state.id)
assertEquals(100, state.balance)
sequence.value shouldBeExactly 2L
state.id shouldBe 1
state.balance shouldBeExactly 100
}
testContext.completeNow()
}
Expand All @@ -64,8 +66,7 @@ class AccountTransferScenarioTest : AbstractCrabletTest() {
)
val appendCondition = AppendCondition(query = streamQuery, maximumEventSequence = SequenceNumber(0))
val eventsToAppend = listOf(
JsonObject().put("type", "AccountOpened").put("id", "2"),
JsonObject().put("type", "AmountDeposited").put("amount", 0)
JsonObject().put("type", "AccountOpened").put("id", 2)
)
eventsAppender.appendIf(eventsToAppend, appendCondition)
.compose {
Expand All @@ -76,9 +77,9 @@ class AccountTransferScenarioTest : AbstractCrabletTest() {
}
.onSuccess { (state, sequence): Pair<Account, SequenceNumber> ->
testContext.verify {
assertEquals(4, sequence.value)
assertEquals("2", state.id)
assertEquals(0, state.balance)
sequence.value shouldBeExactly 3L
state.id shouldBe 2
state.balance shouldBeExactly 0
}
testContext.completeNow()
}
Expand All @@ -98,7 +99,7 @@ class AccountTransferScenarioTest : AbstractCrabletTest() {
identifiers = domainIdentifiers,
eventTypes = eventTypes
)
val appendCondition = AppendCondition(query = streamQuery, maximumEventSequence = SequenceNumber(4))
val appendCondition = AppendCondition(query = streamQuery, maximumEventSequence = SequenceNumber(3))
val eventsToAppend = listOf(
JsonObject().put("type", "AmountTransferred").put("fromAcct", 1).put("toAcct", 2).put("amount", 30)
)
Expand All @@ -115,9 +116,9 @@ class AccountTransferScenarioTest : AbstractCrabletTest() {
stateBuilder.buildFor(streamQueryAcct1)
.onSuccess { (state, sequence) ->
testContext.verify {
assertEquals(5, sequence.value)
assertEquals("1", state.id)
assertEquals(70, state.balance)
sequence.value shouldBeExactly 4L
state.id shouldBe 1
state.balance shouldBeExactly 70
}
}
.onFailure {
Expand All @@ -133,9 +134,9 @@ class AccountTransferScenarioTest : AbstractCrabletTest() {
stateBuilder.buildFor(streamQueryAcct2)
.onSuccess { (state, sequence) ->
testContext.verify {
assertEquals(5, sequence.value)
assertEquals("2", state.id)
assertEquals(30, state.balance)
sequence.value shouldBeExactly 4L
state.id shouldBe 2
state.balance shouldBeExactly 30
}
}
.onFailure {
Expand All @@ -161,7 +162,7 @@ class AccountTransferScenarioTest : AbstractCrabletTest() {
identifiers = domainIdentifiers,
eventTypes = eventTypes
)
val appendCondition = AppendCondition(query = streamQuery, maximumEventSequence = SequenceNumber(5))
val appendCondition = AppendCondition(query = streamQuery, maximumEventSequence = SequenceNumber(4))
val eventsToAppend = listOf(
JsonObject().put("type", "AmountTransferred").put("fromAcct", 2).put("toAcct", 1).put("amount", 10)
)
Expand All @@ -178,9 +179,9 @@ class AccountTransferScenarioTest : AbstractCrabletTest() {
stateBuilder.buildFor(streamQueryAcct1)
.onSuccess { (state, sequence) ->
testContext.verify {
assertEquals(6, sequence.value)
assertEquals("1", state.id)
assertEquals(80, state.balance)
sequence.value shouldBeExactly 5L
state.id shouldBe 1
state.balance shouldBeExactly 80
}
}
.onFailure {
Expand All @@ -196,9 +197,9 @@ class AccountTransferScenarioTest : AbstractCrabletTest() {
stateBuilder.buildFor(streamQueryAcct2)
.onSuccess { (state, sequence) ->
testContext.verify {
assertEquals(6, sequence.value)
assertEquals("2", state.id)
assertEquals(20, state.balance)
sequence.value shouldBeExactly 5L
state.id shouldBe 2
state.balance shouldBeExactly 20
}
}
.onFailure {
Expand All @@ -224,7 +225,7 @@ class AccountTransferScenarioTest : AbstractCrabletTest() {
identifiers = domainIdentifiers,
eventTypes = eventTypes
)
val appendCondition = AppendCondition(query = streamQuery, maximumEventSequence = SequenceNumber(6))
val appendCondition = AppendCondition(query = streamQuery, maximumEventSequence = SequenceNumber(5))
val eventsToAppend = listOf(
JsonObject().put("type", "AmountTransferred").put("fromAcct", 2).put("toAcct", 1).put("amount", 1)
)
Expand All @@ -241,9 +242,9 @@ class AccountTransferScenarioTest : AbstractCrabletTest() {
stateBuilder.buildFor(streamQueryAcct1)
.onSuccess { (state, sequence) ->
testContext.verify {
assertEquals(7, sequence.value)
assertEquals("1", state.id)
assertEquals(81, state.balance)
sequence.value shouldBeExactly 6L
state.id shouldBe 1
state.balance shouldBeExactly 81
}
}
.onFailure {
Expand All @@ -259,9 +260,9 @@ class AccountTransferScenarioTest : AbstractCrabletTest() {
stateBuilder.buildFor(streamQueryAcct2)
.onSuccess { (state, sequence) ->
testContext.verify {
assertEquals(7, sequence.value)
assertEquals("2", state.id)
assertEquals(19, state.balance)
sequence.value shouldBeExactly 6L
state.id shouldBe 2
state.balance shouldBeExactly 19
}
}
.onFailure {
Expand All @@ -287,7 +288,7 @@ class AccountTransferScenarioTest : AbstractCrabletTest() {
identifiers = domainIdentifiers,
eventTypes = eventTypes
)
val appendCondition = AppendCondition(query = streamQuery, maximumEventSequence = SequenceNumber(7))
val appendCondition = AppendCondition(query = streamQuery, maximumEventSequence = SequenceNumber(6))
val eventsToAppend = listOf(
JsonObject().put("type", "AmountTransferred").put("fromAcct", 1).put("toAcct", 2).put("amount", 1)
)
Expand All @@ -304,9 +305,9 @@ class AccountTransferScenarioTest : AbstractCrabletTest() {
stateBuilder.buildFor(streamQueryAcct1)
.onSuccess { (state, sequence) ->
testContext.verify {
assertEquals(8, sequence.value)
assertEquals("1", state.id)
assertEquals(80, state.balance)
sequence.value shouldBeExactly 7L
state.id shouldBe 1
state.balance shouldBeExactly 80
}
}
.onFailure {
Expand All @@ -322,9 +323,9 @@ class AccountTransferScenarioTest : AbstractCrabletTest() {
stateBuilder.buildFor(streamQueryAcct2)
.onSuccess { (state, sequence) ->
testContext.verify {
assertEquals(8, sequence.value)
assertEquals("2", state.id)
assertEquals(20, state.balance)
sequence.value shouldBeExactly 7L
state.id shouldBe 2
state.balance shouldBeExactly 20
}
}
.onFailure {
Expand All @@ -343,7 +344,7 @@ class AccountTransferScenarioTest : AbstractCrabletTest() {
lateinit var eventsAppender: CrabletEventsAppender
lateinit var stateBuilder: CrabletStateBuilder<Account>

data class Account(val id: String? = null, val balance: Int = 0)
data class Account(val id: Int? = null, val balance: Int = 0)

val eventTypes = listOf("AccountOpened", "AmountDeposited", "AmountTransferred").map { EventName(it) }

Expand All @@ -356,17 +357,17 @@ class AccountTransferScenarioTest : AbstractCrabletTest() {
initialState = Account(),
evolveFunction = { state, event ->
when (event.getString("type")) {
"AccountOpened" -> state.copy(id = event.getString("id"))
"AccountOpened" -> state.copy(id = event.getInteger("id"))
"AmountDeposited" -> state.copy(balance = state.balance.plus(event.getInteger("amount")))
"AmountTransferred" -> {
when {
event.getString("fromAcct") == state.id -> state.copy(
event.getInteger("fromAcct") == state.id -> state.copy(
balance = state.balance.minus(
event.getInteger("amount")
)
)

event.getString("toAcct") == state.id -> state.copy(
event.getInteger("toAcct") == state.id -> state.copy(
balance = state.balance.plus(
event.getInteger(
"amount"
Expand Down

0 comments on commit c0f1731

Please sign in to comment.