From 4304dbde1dd01724040ba76a13e6e0eda2805b33 Mon Sep 17 00:00:00 2001 From: Swordsteel Date: Thu, 11 Sep 2025 18:49:16 +0200 Subject: [PATCH] add account not found exception - update balance in AccountController with onErrorResume - update AccountService - update getForUpdateById with switchIfEmpty - update getById with switchIfEmpty - add AccountNotFoundException --- .../ltd/lulz/controller/AccountController.kt | 2 +- .../exception/AccountNotFoundException.kt | 10 +++++++ .../kotlin/ltd/lulz/service/AccountService.kt | 19 ++++++++++--- .../lulz/controller/AccountControllerTest.kt | 3 +- .../ltd/lulz/service/AccountServiceTest.kt | 28 +++++++++++++++++++ 5 files changed, 56 insertions(+), 6 deletions(-) create mode 100644 src/main/kotlin/ltd/lulz/exception/AccountNotFoundException.kt diff --git a/src/main/kotlin/ltd/lulz/controller/AccountController.kt b/src/main/kotlin/ltd/lulz/controller/AccountController.kt index 90601bb..543593e 100644 --- a/src/main/kotlin/ltd/lulz/controller/AccountController.kt +++ b/src/main/kotlin/ltd/lulz/controller/AccountController.kt @@ -39,6 +39,6 @@ class AccountController( @PathVariable account: UUID, ): Mono = accountService.getById(account) .map { it.toResponse() } - .switchIfEmpty(Mono.error(ResponseStatusException(NOT_FOUND))) + .onErrorResume { Mono.error(ResponseStatusException(NOT_FOUND)) } .doOnError { log.debug { "account $account not found for balance" } } } diff --git a/src/main/kotlin/ltd/lulz/exception/AccountNotFoundException.kt b/src/main/kotlin/ltd/lulz/exception/AccountNotFoundException.kt new file mode 100644 index 0000000..ed29bfa --- /dev/null +++ b/src/main/kotlin/ltd/lulz/exception/AccountNotFoundException.kt @@ -0,0 +1,10 @@ +package ltd.lulz.exception + +@Suppress("unused") +class AccountNotFoundException : RuntimeException { + + constructor() : super() + constructor(message: String?) : super(message) + constructor(message: String?, cause: Throwable?) : super(message, cause) + constructor(cause: Throwable?) : super(cause) +} diff --git a/src/main/kotlin/ltd/lulz/service/AccountService.kt b/src/main/kotlin/ltd/lulz/service/AccountService.kt index c80e4e9..a6a6c88 100644 --- a/src/main/kotlin/ltd/lulz/service/AccountService.kt +++ b/src/main/kotlin/ltd/lulz/service/AccountService.kt @@ -2,6 +2,7 @@ package ltd.lulz.service import io.github.oshai.kotlinlogging.KotlinLogging import java.util.UUID +import ltd.lulz.exception.AccountNotFoundException import ltd.lulz.model.AccountEntity import ltd.lulz.repository.AccountRepository import org.springframework.stereotype.Service @@ -15,18 +16,28 @@ class AccountService( private val accountRepository: AccountRepository, ) { - fun create(entity: AccountEntity): Mono = accountRepository + fun create( + entity: AccountEntity, + ): Mono = accountRepository .save(entity) .doOnNext { log.debug { "account created with id: ${it.id}" } } - fun getById(id: UUID): Mono = accountRepository.findById(id) + fun getById( + id: UUID, + ): Mono = accountRepository.findById(id) .doOnNext { log.debug { "found account by id: ${it.id}" } } + .switchIfEmpty(Mono.error(AccountNotFoundException())) @Transactional - fun getForUpdateById(id: UUID): Mono = accountRepository.findByIdForUpdate(id) + fun getForUpdateById( + id: UUID, + ): Mono = accountRepository.findByIdForUpdate(id) .doOnNext { log.trace { "account with id: ${it.id} locked for update" } } + .switchIfEmpty(Mono.error(AccountNotFoundException())) @Transactional - fun save(entity: AccountEntity): Mono = accountRepository.save(entity) + fun save( + entity: AccountEntity, + ): Mono = accountRepository.save(entity) .doOnNext { log.trace { "account with id: ${it.id} saved" } } } diff --git a/src/test/kotlin/ltd/lulz/controller/AccountControllerTest.kt b/src/test/kotlin/ltd/lulz/controller/AccountControllerTest.kt index 0fd0811..4ba8212 100644 --- a/src/test/kotlin/ltd/lulz/controller/AccountControllerTest.kt +++ b/src/test/kotlin/ltd/lulz/controller/AccountControllerTest.kt @@ -4,6 +4,7 @@ import io.mockk.every import io.mockk.mockk import java.math.BigDecimal import java.util.UUID +import ltd.lulz.exception.AccountNotFoundException import ltd.lulz.model.Account import ltd.lulz.model.AccountEntity import ltd.lulz.service.AccountService @@ -117,7 +118,7 @@ class AccountControllerTest { @Test fun `account balance fail`() { // given - every { accountService.getById(any()) } returns Mono.empty() + every { accountService.getById(any()) } returns Mono.error(AccountNotFoundException()) // when val result = webTestClient.get() diff --git a/src/test/kotlin/ltd/lulz/service/AccountServiceTest.kt b/src/test/kotlin/ltd/lulz/service/AccountServiceTest.kt index 956f0ed..82f2565 100644 --- a/src/test/kotlin/ltd/lulz/service/AccountServiceTest.kt +++ b/src/test/kotlin/ltd/lulz/service/AccountServiceTest.kt @@ -6,6 +6,7 @@ import io.mockk.slot import io.mockk.verify import java.math.BigDecimal import java.util.UUID +import ltd.lulz.exception.AccountNotFoundException import ltd.lulz.model.AccountEntity import ltd.lulz.repository.AccountRepository import org.assertj.core.api.Assertions.assertThat @@ -70,6 +71,19 @@ class AccountServiceTest { verify { repository.findById(any(UUID::class)) } } + @Test + fun `get by id - fail`() { + // given + every { repository.findById(any(UUID::class)) } returns Mono.empty() + + // when stepped + StepVerifier.create(service.getById(uuid)) + .expectError(AccountNotFoundException::class.java) + .verify() + + verify { repository.findById(any(UUID::class)) } + } + @Test fun `get for update by id`() { // given @@ -89,6 +103,20 @@ class AccountServiceTest { verify { repository.findByIdForUpdate(any(UUID::class)) } } + @Test + fun `get for update by id - fail`() { + // given + + every { repository.findByIdForUpdate(any(UUID::class)) } returns Mono.empty() + + // when stepped + StepVerifier.create(service.getForUpdateById(uuid)) + .expectError(AccountNotFoundException::class.java) + .verify() + + verify { repository.findByIdForUpdate(any(UUID::class)) } + } + @Test fun `save change`() { // given