Skip to content

Commit

Permalink
Add test for Jackson statement repository
Browse files Browse the repository at this point in the history
  • Loading branch information
smaugfm committed Nov 27, 2023
1 parent 98a26d3 commit 69c0558
Show file tree
Hide file tree
Showing 12 changed files with 86 additions and 29 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ out/

settings*.json
settings*.yml
retries.json
docker-compose.yml
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ dependencies {
implementation("com.github.elbekD:kt-telegram-bot:2.2.0")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:$jackson")
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:$jackson")
implementation("de.brudaswen.kotlinx.serialization:kotlinx-serialization-csv:2.0.0")
implementation("com.charleskorn.kaml:kaml:0.55.0")
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.1")
Expand Down
7 changes: 4 additions & 3 deletions src/main/kotlin/io/github/smaugfm/monobudget/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,10 @@ fun main() {
val monoWebhookUrl = URI(env["MONO_WEBHOOK_URL"]!!)
val webhookPort = env["WEBHOOK_PORT"]?.toInt() ?: DEFAULT_HTTP_PORT
val settings = Settings.load(Paths.get(env["SETTINGS_FILE"] ?: "settings.yml"))
val jsonRetryRepository = JacksonFileStatementRetryRepository(
Paths.get(env["RETRIES_FILE"] ?: "retries.json")
)
val jsonRetryRepository =
JacksonFileStatementRetryRepository(
Paths.get(env["RETRIES_FILE"] ?: "retries.json"),
)
val budgetBackend = settings.budgetBackend
val webhookSettings = MonoWebhookSettings(setWebhook, monoWebhookUrl, webhookPort)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,5 @@ class StatementProcessingContext(
return map.getOrPut(key) { lazyValue() as Any } as T
}

fun incrementAttempt(): StatementProcessingContext =
StatementProcessingContext(item, map, attempt + 1)
fun incrementAttempt(): StatementProcessingContext = StatementProcessingContext(item, map, attempt + 1)
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
package io.github.smaugfm.monobudget.common.model.financial

import com.fasterxml.jackson.annotation.JsonTypeInfo
import kotlinx.datetime.Instant
import java.util.Currency

@JsonTypeInfo(
use = JsonTypeInfo.Id.MINIMAL_CLASS,
include = JsonTypeInfo.As.PROPERTY,
)
interface StatementItem {
val id: String
val accountId: BankAccountId
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,32 @@
package io.github.smaugfm.monobudget.common.retry

import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.fasterxml.jackson.databind.SerializationFeature
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
import com.fasterxml.jackson.module.kotlin.jsonMapper
import com.fasterxml.jackson.module.kotlin.kotlinModule
import io.github.smaugfm.monobudget.common.lifecycle.StatementProcessingContext
import java.nio.file.Path
import java.nio.file.StandardOpenOption
import java.util.UUID
import kotlin.io.path.exists
import kotlin.io.path.readText
import kotlin.io.path.writeText
import kotlin.time.Duration

class JacksonFileStatementRetryRepository(
private val path: Path
private val path: Path,
) : StatementRetryRepository {

private val objectMapper = jacksonObjectMapper()
val objectMapper =
jsonMapper {
enable(SerializationFeature.INDENT_OUTPUT)
addModule(kotlinModule())
addModule(JavaTimeModule())
}

override suspend fun addRetryRequest(
ctx: StatementProcessingContext,
retryWaitDuration: Duration
retryWaitDuration: Duration,
) = StatementRetryRequest(UUID.randomUUID().toString(), ctx, retryWaitDuration)
.also {
save(getAllRequests() + it)
Expand All @@ -28,11 +37,20 @@ class JacksonFileStatementRetryRepository(
}

override suspend fun getAllRequests(): List<StatementRetryRequest> =
objectMapper.readValue(
path.readText(), object : TypeReference<List<StatementRetryRequest>>() {}
)
if (path.exists()) {
objectMapper.readValue(
path.readText(),
object : TypeReference<List<StatementRetryRequest>>() {},
)
} else {
emptyList()
}

private fun save(list: List<StatementRetryRequest>) {
path.writeText(objectMapper.writeValueAsString(list))
path.writeText(
objectMapper.writeValueAsString(list),
Charsets.UTF_8,
StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE
)
}
}
4 changes: 2 additions & 2 deletions src/test/kotlin/io/github/smaugfm/monobudget/TestBase.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ import java.util.Currency
@ExtendWith(MockKExtension::class)
@Suppress("MagicNumber")
open class TestBase : KoinTest {
open fun KoinApplication.testKoinApplication() {
open fun testKoinApplication(app: KoinApplication) {
}

@Suppress("unused")
@JvmField
@RegisterExtension
val koinTestExtension =
KoinTestExtension.create {
testKoinApplication()
testKoinApplication(this@create)
}

@BeforeEach
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ class TransferDetectorTest : TestBase() {
cache,
)

override fun KoinApplication.testKoinApplication() {
modules(
override fun testKoinApplication(app: KoinApplication) {
app.modules(
module {
scope<StatementProcessingScopeComponent> {
scoped { TestDetector(get(), get()) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ abstract class IntegrationTestBase : TestBase(), CoroutineScope {
@MockK
lateinit var budgetSettingsVerifier: BudgetSettingsVerifier

override fun KoinApplication.testKoinApplication() {
override fun testKoinApplication(app: KoinApplication) {
coEvery { webhookListener.prepare() } just runs
coEvery { webhookListener.statements() } returns webhookStatementsFlow

Expand All @@ -89,7 +89,7 @@ abstract class IntegrationTestBase : TestBase(), CoroutineScope {
} returns TestData.categories
coEvery { budgetSettingsVerifier.verify() } just runs

setupKoinModules(
app.setupKoinModules(
this@IntegrationTestBase,
InMemoryStatementRetryRepository(),
Settings.load(
Expand All @@ -99,7 +99,7 @@ abstract class IntegrationTestBase : TestBase(), CoroutineScope {
),
MonoWebhookSettings(false, URI.create(""), 0),
)
modules(
app.modules(
module {
single { lunchmoneyMock }
single { webhookListener } bind MonoWebhookListener::class bind StatementSource::class
Expand Down Expand Up @@ -175,7 +175,7 @@ abstract class IntegrationTestBase : TestBase(), CoroutineScope {
}
val updateTracker =
FailTrackerTransformation<LunchmoneyUpdateTransactionResponse>(
fails.filterIsInstance<IntegrationFailConfig.Update>()
fails.filterIsInstance<IntegrationFailConfig.Update>(),
)
every {
lunchmoneyMock.updateTransaction(any(), any(), any(), any(), any())
Expand All @@ -184,7 +184,9 @@ abstract class IntegrationTestBase : TestBase(), CoroutineScope {
.transformDeferred(updateTracker)
}
val createTransactionGroupTracker =
FailTrackerTransformation<Long>(fails.filterIsInstance<IntegrationFailConfig.CreateTransactionGroup>())
FailTrackerTransformation<Long>(
fails.filterIsInstance<IntegrationFailConfig.CreateTransactionGroup>(),
)
every {
lunchmoneyMock.createTransactionGroup(any(), any(), any(), any(), any(), any())
} answers {
Expand Down Expand Up @@ -222,7 +224,9 @@ abstract class IntegrationTestBase : TestBase(), CoroutineScope {
.transformDeferred(insertTracker)
}
val singleTracker =
FailTrackerTransformation<LunchmoneyTransaction>(fails.filterIsInstance<IntegrationFailConfig.GetSingle>())
FailTrackerTransformation<LunchmoneyTransaction>(
fails.filterIsInstance<IntegrationFailConfig.GetSingle>(),
)
every { lunchmoneyMock.getSingleTransaction(newTransactionId, any()) } answers {
Mono.just(
LunchmoneyTransaction(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package io.github.smaugfm.monobudget.integration

import io.github.smaugfm.monobudget.common.retry.JacksonFileStatementRetryRepository
import io.github.smaugfm.monobudget.common.retry.StatementRetryRepository
import org.junit.jupiter.api.BeforeEach
import org.koin.core.KoinApplication
import org.koin.dsl.bind
import org.koin.dsl.module
import java.nio.file.Files
import java.nio.file.Paths

class JacksonRepositoryRetriesTest : RetriesTest() {
private val repo = JacksonFileStatementRetryRepository(Paths.get("retries.json"))

override fun testKoinApplication(app: KoinApplication) {
super.testKoinApplication(app)
app.modules(
module {
single { repo } bind StatementRetryRepository::class
},
)
}

@BeforeEach
fun deleteFile() {
Files.deleteIfExists(Paths.get("retries.json"))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ import java.math.BigDecimal
import java.util.UUID

@Suppress("LongMethod")
class RetriesTest : IntegrationTestBase() {
open class RetriesTest : IntegrationTestBase() {
@Test
fun `When lunchmoney fails and then recovers transfer transaction is processed correctly`() {
open fun `When lunchmoney fails and then recovers transfer transaction is processed correctly`() {
val (newTransactionId, newTransactionId2) =
setupTransferMocks(
listOf(
Expand Down Expand Up @@ -129,7 +129,7 @@ class RetriesTest : IntegrationTestBase() {
}

@Test
fun `When lunchmoney fails and then recovers successful method calls are not retried`() {
open fun `When lunchmoney fails and then recovers successful method calls are not retried`() {
val newTransactionId =
setupSingleTransactionMocks(
listOf(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ import java.time.LocalDate
import java.util.Currency

class LunchmoneyTransactionCreatorTest : TestBase() {
override fun KoinApplication.testKoinApplication() {
modules(
override fun testKoinApplication(app: KoinApplication) {
app.modules(
module {
single { InMemoryStatementRetryRepository() } bind StatementRetryRepository::class
scope<StatementProcessingScopeComponent> {
Expand Down

0 comments on commit 69c0558

Please sign in to comment.