diff --git a/.editorconfig b/.editorconfig index 24bf808..b6d6f38 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,10 +9,10 @@ insert_final_newline = true max_line_length = 120 tab_width = 4 -[*.{json,md,txt,xml,yaml,yml}] +[*.{http,json,md,txt,xml,yaml,yml}] max_line_length = 1024 -[*.{json,xml,yaml,yml}] +[*.{http,json,xml,yaml,yml}] indent_size = 2 tab_width = 2 diff --git a/http/account.http b/http/account.http index 5754455..e866a7a 100644 --- a/http/account.http +++ b/http/account.http @@ -6,3 +6,6 @@ Content-Type: application/json "name": "account name", "amount": -1.11 } + +### Create Account +GET {{url}}/balance/account-00000000-0000-0000-0000-000000000000 diff --git a/src/main/kotlin/ltd/lulz/controller/AccountController.kt b/src/main/kotlin/ltd/lulz/controller/AccountController.kt index f34e060..90601bb 100644 --- a/src/main/kotlin/ltd/lulz/controller/AccountController.kt +++ b/src/main/kotlin/ltd/lulz/controller/AccountController.kt @@ -1,18 +1,26 @@ package ltd.lulz.controller +import io.github.oshai.kotlinlogging.KotlinLogging import jakarta.validation.Valid +import java.util.UUID import ltd.lulz.model.Account import ltd.lulz.service.AccountService import ltd.lulz.util.toEntity import ltd.lulz.util.toResponse import org.springframework.http.HttpStatus.CREATED +import org.springframework.http.HttpStatus.NOT_FOUND import org.springframework.validation.annotation.Validated +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.ResponseStatus import org.springframework.web.bind.annotation.RestController +import org.springframework.web.server.ResponseStatusException import reactor.core.publisher.Mono +private val log = KotlinLogging.logger {} + @RestController @Validated class AccountController( @@ -25,4 +33,12 @@ class AccountController( @Valid @RequestBody request: Account.Request, ): Mono = accountService.create(request.toEntity()) .map { it.toResponse() } + + @GetMapping("/balance/account-{account}") + fun balance( + @PathVariable account: UUID, + ): Mono = accountService.getById(account) + .map { it.toResponse() } + .switchIfEmpty(Mono.error(ResponseStatusException(NOT_FOUND))) + .doOnError { log.debug { "account $account not found for balance" } } } diff --git a/src/test/kotlin/ltd/lulz/controller/AccountControllerTest.kt b/src/test/kotlin/ltd/lulz/controller/AccountControllerTest.kt index 3f06e0a..0fd0811 100644 --- a/src/test/kotlin/ltd/lulz/controller/AccountControllerTest.kt +++ b/src/test/kotlin/ltd/lulz/controller/AccountControllerTest.kt @@ -8,12 +8,13 @@ import ltd.lulz.model.Account import ltd.lulz.model.AccountEntity import ltd.lulz.service.AccountService import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test import org.springframework.http.MediaType.APPLICATION_JSON import org.springframework.test.web.reactive.server.WebTestClient import reactor.core.publisher.Mono -@Suppress("MayBeConstant") +@Suppress("MayBeConstant", "ReactiveStreamsUnusedPublisher") class AccountControllerTest { companion object { @@ -30,59 +31,101 @@ class AccountControllerTest { webTestClient = WebTestClient.bindToController(AccountController(accountService)).build() } - @Test - fun `create account success`() { - // given - val request = Account.Request(name, amount) + @Nested + inner class CreateAccount { - every { accountService.create(any()) } returns Mono.just( - AccountEntity(id = uuid, name = name, amount = amount), - ) + @Test + fun `create account success`() { + // given + val request = Account.Request(name, amount) - // when - val result = webTestClient.post() - .uri("/account") - .contentType(APPLICATION_JSON) - .bodyValue(request) - .exchange() + every { accountService.create(any()) } returns Mono.just( + AccountEntity(id = uuid, name = name, amount = amount), + ) - // then - result.expectStatus().isCreated - .expectBody() - .jsonPath("$.id").isEqualTo(uuid.toString()) - .jsonPath("$.name").isEqualTo(name) - .jsonPath("$.amount").isEqualTo(amount.toString()) + // when + val result = webTestClient.post() + .uri("/account") + .contentType(APPLICATION_JSON) + .bodyValue(request) + .exchange() + + // then + result.expectStatus().isCreated + .expectBody() + .jsonPath("$.id").isEqualTo(uuid.toString()) + .jsonPath("$.name").isEqualTo(name) + .jsonPath("$.amount").isEqualTo(amount.toString()) + } + + @Test + fun `create account fail no name`() { + // given + val request = Account.Request("", amount) + + // when + val result = webTestClient.post() + .uri("/account") + .contentType(APPLICATION_JSON) + .bodyValue(request) + .exchange() + + // then + result.expectStatus().isBadRequest + } + + @Test + fun `create account fail zero or less amount`() { + // given + val request = Account.Request("name", BigDecimal.valueOf(0)) + + // when + val result = webTestClient.post() + .uri("/account") + .contentType(APPLICATION_JSON) + .bodyValue(request) + .exchange() + + // then + result.expectStatus().isBadRequest + } } - @Test - fun `create account fail no name`() { - // given - val request = Account.Request("", amount) + @Nested + inner class AccountBalance { - // when - val result = webTestClient.post() - .uri("/account") - .contentType(APPLICATION_JSON) - .bodyValue(request) - .exchange() + @Test + fun `account balance success`() { + // given + every { accountService.getById(any()) } returns Mono.just( + AccountEntity(id = uuid, name = name, amount = amount), + ) - // then - result.expectStatus().isBadRequest - } + // when + val result = webTestClient.get() + .uri("/balance/account-$uuid") + .exchange() - @Test - fun `create account fail zero or less amount`() { - // given - val request = Account.Request("name", BigDecimal.valueOf(0)) + // then + result.expectStatus().isOk + .expectBody() + .jsonPath("$.id").isEqualTo(uuid.toString()) + .jsonPath("$.name").isEqualTo(name) + .jsonPath("$.amount").isEqualTo(amount.toString()) + } - // when - val result = webTestClient.post() - .uri("/account") - .contentType(APPLICATION_JSON) - .bodyValue(request) - .exchange() + @Test + fun `account balance fail`() { + // given + every { accountService.getById(any()) } returns Mono.empty() - // then - result.expectStatus().isBadRequest + // when + val result = webTestClient.get() + .uri("/balance/account-$uuid") + .exchange() + + // then + result.expectStatus().isNotFound + } } }