package ltd.lulz.controller import io.mockk.every import io.mockk.mockk import java.math.BigDecimal import java.util.UUID import ltd.lulz.controller.AccountControllerTest.Companion.name import ltd.lulz.exception.AccountNotFoundException import ltd.lulz.exception.InsufficientFundsException import ltd.lulz.model.AccountEntity import ltd.lulz.model.Transaction import ltd.lulz.model.Transfer import ltd.lulz.service.TransactionService import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.springframework.http.HttpStatus.NOT_ACCEPTABLE import org.springframework.http.MediaType.APPLICATION_JSON import org.springframework.test.web.reactive.server.WebTestClient import reactor.core.publisher.Mono @Suppress("ReactiveStreamsUnusedPublisher") class TransactionControllerTest { companion object { val amount: BigDecimal = BigDecimal.valueOf(0.01) val uuid: UUID = UUID.fromString("00000000-0000-0000-0000-000000000000") val receiver = UUID.fromString("00000000-0000-0000-0000-000000000001") } private val transactionService: TransactionService = mockk() private lateinit var webTestClient: WebTestClient @BeforeEach fun setUp() { webTestClient = WebTestClient.bindToController(TransactionController(transactionService)).build() } @Test fun `deposit success`() { // given val request = Transaction.Request(uuid, amount) every { transactionService.deposit(any(), any()) } returns Mono.just( AccountEntity(id = uuid, name = name, amount = amount), ) // when val result = webTestClient.post() .uri("/deposit") .contentType(APPLICATION_JSON) .bodyValue(request) .exchange() // then result.expectStatus().isCreated } @Test fun `deposit fail amount to small`() { // given val request = Transaction.Request(uuid, BigDecimal.valueOf(0.009)) // when val result = webTestClient.post() .uri("/deposit") .contentType(APPLICATION_JSON) .bodyValue(request) .exchange() // then result.expectStatus().isBadRequest } @Test fun `deposit default error`() { // given val request = Transaction.Request(uuid, amount) every { transactionService.deposit(any(), any()) } returns Mono.error(RuntimeException()) // when val result = webTestClient.post() .uri("/deposit") .contentType(APPLICATION_JSON) .bodyValue(request) .exchange() // then result.expectStatus().is5xxServerError } @Test fun `deposit account not found`() { // given val request = Transaction.Request(uuid, amount) every { transactionService.deposit(any(), any()) } returns Mono.error(AccountNotFoundException()) // when val result = webTestClient.post() .uri("/deposit") .contentType(APPLICATION_JSON) .bodyValue(request) .exchange() // then result.expectStatus().isNotFound } @Test fun `withdrawal success`() { // given val request = Transaction.Request(uuid, amount) every { transactionService.withdrawal(any(), any()) } returns Mono.just( AccountEntity(id = uuid, name = name, amount = amount), ) // when val result = webTestClient.post() .uri("/withdrawal") .contentType(APPLICATION_JSON) .bodyValue(request) .exchange() // then result.expectStatus().isCreated } @Test fun `withdrawal fail amount to small`() { // given val request = Transaction.Request(uuid, BigDecimal.valueOf(0.009)) // when val result = webTestClient.post() .uri("/withdrawal") .contentType(APPLICATION_JSON) .bodyValue(request) .exchange() // then result.expectStatus().isBadRequest } @Test fun `withdrawal insufficient Funds`() { // given val request = Transaction.Request(uuid, amount) every { transactionService.withdrawal(any(), any()) } returns Mono.error(InsufficientFundsException()) // when val result = webTestClient.post() .uri("/withdrawal") .contentType(APPLICATION_JSON) .bodyValue(request) .exchange() // then result.expectStatus().isEqualTo(NOT_ACCEPTABLE) } @Test fun `withdrawal account not found`() { // given val request = Transaction.Request(uuid, amount) every { transactionService.withdrawal(any(), any()) } returns Mono.error(AccountNotFoundException()) // when val result = webTestClient.post() .uri("/withdrawal") .contentType(APPLICATION_JSON) .bodyValue(request) .exchange() // then result.expectStatus().isNotFound } @Test fun `withdrawal default error`() { // given val request = Transaction.Request(uuid, amount) every { transactionService.withdrawal(any(), any()) } returns Mono.error(RuntimeException()) // when val result = webTestClient.post() .uri("/withdrawal") .contentType(APPLICATION_JSON) .bodyValue(request) .exchange() // then result.expectStatus().is5xxServerError } @Test fun `transfer success`() { // given val request = Transfer.Request(uuid, receiver, amount) every { transactionService.transfer(any(), any(), any()) } returns Mono.empty() // when val result = webTestClient.post() .uri("/transfer") .contentType(APPLICATION_JSON) .bodyValue(request) .exchange() // then result.expectStatus().isCreated } @Test fun `transfer fail same accounts`() { // given val request = Transfer.Request(uuid, uuid, amount) every { transactionService.transfer(any(), any(), any()) } returns Mono.empty() // when val result = webTestClient.post() .uri("/transfer") .contentType(APPLICATION_JSON) .bodyValue(request) .exchange() // then result.expectStatus().isBadRequest } @Test fun `transfer fail amount to small`() { // given val request = Transfer.Request(uuid, receiver, BigDecimal.valueOf(0.009)) // when val result = webTestClient.post() .uri("/transfer") .contentType(APPLICATION_JSON) .bodyValue(request) .exchange() // then result.expectStatus().isBadRequest } @Test fun `transfer insufficient Funds`() { // given val request = Transfer.Request(uuid, receiver, amount) every { transactionService.transfer(any(), any(), any()) } returns Mono.error(InsufficientFundsException()) // when val result = webTestClient.post() .uri("/transfer") .contentType(APPLICATION_JSON) .bodyValue(request) .exchange() // then result.expectStatus().isEqualTo(NOT_ACCEPTABLE) } @Test fun `transfer account not found`() { // given val request = Transfer.Request(uuid, receiver, amount) every { transactionService.transfer(any(), any(), any()) } returns Mono.error(AccountNotFoundException()) // when val result = webTestClient.post() .uri("/transfer") .contentType(APPLICATION_JSON) .bodyValue(request) .exchange() // then result.expectStatus().isNotFound } @Test fun `transfer default error`() { // given val request = Transfer.Request(uuid, receiver, amount) every { transactionService.transfer(any(), any(), any()) } returns Mono.error(RuntimeException()) // when val result = webTestClient.post() .uri("/transfer") .contentType(APPLICATION_JSON) .bodyValue(request) .exchange() // then result.expectStatus().is5xxServerError } }