diff --git a/demo-transactions/pom.xml b/demo-transactions/pom.xml index 44189cb..3edae55 100644 --- a/demo-transactions/pom.xml +++ b/demo-transactions/pom.xml @@ -73,9 +73,9 @@ test - com.nhaarman.mockitokotlin2 - mockito-kotlin - ${mockito-kotlin.version} + io.mockk + mockk-jvm + ${mockk.version} test @@ -251,7 +251,6 @@ - org.apache.maven.plugins maven-compiler-plugin @@ -296,6 +295,32 @@ com.mysql.jdbc.Driver + + + org.apache.maven.plugins + maven-failsafe-plugin + ${maven-failsafe-plugin.version} + + + -Dspring.profiles.active=test + + ${project.build.outputDirectory} + + + ${basedir}/target/classes + + + + + + integration-test + verify + + + + \ No newline at end of file diff --git a/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/adapter/GlobalExceptionHandler.kt b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/adapter/GlobalExceptionHandler.kt new file mode 100644 index 0000000..e5ba1e1 --- /dev/null +++ b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/adapter/GlobalExceptionHandler.kt @@ -0,0 +1,23 @@ +package io.holixon.cqrshexagonaldemo.demoparent.transactions.adapter + +import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.exception.AccountNotFoundException +import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.exception.InvalidInputException +import jakarta.servlet.http.HttpServletRequest +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.ExceptionHandler +import org.springframework.web.bind.annotation.RestControllerAdvice + +@RestControllerAdvice +class GlobalExceptionHandler { + + @ExceptionHandler(AccountNotFoundException::class) + fun handleException(request: HttpServletRequest, exception: AccountNotFoundException): ResponseEntity { + return ResponseEntity.notFound().build() + } + + @ExceptionHandler(InvalidInputException::class) + fun handleException(request: HttpServletRequest, exception: InvalidInputException): ResponseEntity { + return ResponseEntity.badRequest().build() + } + +} diff --git a/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/adapter/inbound/account/CreateAccountRestInAdapter.kt b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/adapter/inbound/account/AccountRestInAdapter.kt similarity index 59% rename from demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/adapter/inbound/account/CreateAccountRestInAdapter.kt rename to demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/adapter/inbound/account/AccountRestInAdapter.kt index 443718a..305bac2 100644 --- a/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/adapter/inbound/account/CreateAccountRestInAdapter.kt +++ b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/adapter/inbound/account/AccountRestInAdapter.kt @@ -4,17 +4,24 @@ import io.holixon.cqrshexagonaldemo.demoparent.transactions.adapter.inbound.Acco import io.holixon.cqrshexagonaldemo.demoparent.transactions.adapter.inbound.account.mapper.toAccountCreatedResponseDto import io.holixon.cqrshexagonaldemo.demoparent.transactions.adapter.inbound.dto.AccountCreatedResponseDto import io.holixon.cqrshexagonaldemo.demoparent.transactions.adapter.inbound.dto.CreateAccountRequestDto +import io.holixon.cqrshexagonaldemo.demoparent.transactions.adapter.inbound.dto.DepositRequestDto import io.holixon.cqrshexagonaldemo.demoparent.transactions.application.port.inbound.account.CreateAccountInPort +import io.holixon.cqrshexagonaldemo.demoparent.transactions.application.port.inbound.account.DepositAccountInPort +import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.account.Amount +import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.account.Iban import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.customer.CustomerNumber import io.holixon.cqrshexagonaldemo.demoparent.transactions.framework.InAdapter +import jakarta.transaction.Transactional import mu.KLogging import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.RestController +import java.math.BigDecimal @RestController @InAdapter -class CreateAccountRestInAdapter( - private val createAccountInPort: CreateAccountInPort +open class AccountRestInAdapter( + private val createAccountInPort: CreateAccountInPort, + private val depositAccountInPort: DepositAccountInPort ) : AccountApiDelegate { companion object : KLogging() @@ -23,4 +30,11 @@ class CreateAccountRestInAdapter( val createdAccount = createAccountInPort.createAccount(CustomerNumber(createAccountRequestDto.customerNumber)) return ResponseEntity.ok(createdAccount.toAccountCreatedResponseDto()) } + + @Transactional + override fun deposit(depositRequestDto: DepositRequestDto): ResponseEntity { + depositAccountInPort.deposit( + Iban(depositRequestDto.iban), Amount(BigDecimal.valueOf(depositRequestDto.amount))) + return ResponseEntity.noContent().build() + } } diff --git a/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/adapter/outbound/account/jpa/AccountOutAdapter.kt b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/adapter/outbound/account/jpa/AccountOutAdapter.kt index 0db6c50..cdacb81 100644 --- a/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/adapter/outbound/account/jpa/AccountOutAdapter.kt +++ b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/adapter/outbound/account/jpa/AccountOutAdapter.kt @@ -2,9 +2,12 @@ package io.holixon.cqrshexagonaldemo.demoparent.transactions.adapter.outbound.ac import io.holixon.cqrshexagonaldemo.demoparent.transactions.adapter.outbound.account.jpa.mapper.AccountEntityMapper import io.holixon.cqrshexagonaldemo.demoparent.transactions.application.port.outbound.account.AccountOutPort +import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.exception.AccountNotFoundException import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.account.Account +import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.account.Amount import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.account.Iban import io.holixon.cqrshexagonaldemo.demoparent.transactions.framework.OutAdapter +import mu.KLogging @OutAdapter class AccountOutAdapter( @@ -12,18 +15,30 @@ class AccountOutAdapter( private val accountEntityMapper: AccountEntityMapper ) : AccountOutPort { - override fun findAccount(iban: Iban): Account? { - val entity = jpaAccountOutAdapter.findById(iban.value) - if (!entity.isPresent) return null + companion object : KLogging() - return accountEntityMapper.toDomain(entity.get()) + override fun findAccount(iban: Iban): Account { + val entity = jpaAccountOutAdapter.findById(iban.value).orElseThrow { + AccountNotFoundException("Account not found for Iban: ${iban.value}") + } + + return accountEntityMapper.toDomain(entity) } override fun createAccount(account: Account): Account { val toEntity = accountEntityMapper.toEntity(account) -// toEntity.updated = Instant.now() val savedAccount = jpaAccountOutAdapter.save(toEntity) return accountEntityMapper.toDomain(savedAccount) } + + override fun deposit(account: Account, amount: Amount): Account { + account.deposit(amount) + + jpaAccountOutAdapter.save(accountEntityMapper.toEntity(account)) + + + return account + } + } diff --git a/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/adapter/outbound/account/jpa/entity/AccountEntity.kt b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/adapter/outbound/account/jpa/entity/AccountEntity.kt index c12b226..0c02b44 100644 --- a/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/adapter/outbound/account/jpa/entity/AccountEntity.kt +++ b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/adapter/outbound/account/jpa/entity/AccountEntity.kt @@ -6,13 +6,10 @@ import jakarta.persistence.Table import java.math.BigDecimal @Entity -@Table( - name = "account", - schema = "transactions" -) +@Table(name = "account") class AccountEntity( - @Id - var iban: String = "", - var customerNumber: String = "", - var balance: BigDecimal = BigDecimal.ZERO + @Id + var iban: String = "", + var customerNumber: String = "", + var balance: BigDecimal = BigDecimal.ZERO ) diff --git a/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/adapter/outbound/account/jpa/mapper/AccountEntityMapper.kt b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/adapter/outbound/account/jpa/mapper/AccountEntityMapper.kt index 6bd89e8..135b276 100644 --- a/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/adapter/outbound/account/jpa/mapper/AccountEntityMapper.kt +++ b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/adapter/outbound/account/jpa/mapper/AccountEntityMapper.kt @@ -2,6 +2,7 @@ package io.holixon.cqrshexagonaldemo.demoparent.transactions.adapter.outbound.ac import io.holixon.cqrshexagonaldemo.demoparent.transactions.adapter.outbound.account.jpa.entity.AccountEntity import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.account.Account +import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.account.Amount import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.account.Iban import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.account.Money import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.customer.CustomerNumber @@ -13,7 +14,7 @@ class AccountEntityMapper { return AccountEntity( customerNumber = account.customerNumber.value, iban = account.iban.value, - balance = account.balance.amount + balance = account.balance.amount.value ) } @@ -21,7 +22,7 @@ class AccountEntityMapper { return Account( customerNumber = CustomerNumber(accountEntity.customerNumber), iban = Iban(accountEntity.iban), - balance = Money(accountEntity.balance) + balance = Money(Amount(accountEntity.balance)) ) } } diff --git a/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/adapter/outbound/customer/entity/CustomerEntity.kt b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/adapter/outbound/customer/entity/CustomerEntity.kt index d326888..9de4efa 100644 --- a/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/adapter/outbound/customer/entity/CustomerEntity.kt +++ b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/adapter/outbound/customer/entity/CustomerEntity.kt @@ -6,12 +6,9 @@ import jakarta.persistence.Table @Entity -@Table( - name = "customer", - schema = "transactions" -) +@Table(name = "customer") class CustomerEntity( - @Id - var customerNumber: String = "", //Default constructor needed for JPA - var customerName: String = "" + @Id + var customerNumber: String = "", //Default constructor needed for JPA + var customerName: String = "" ) \ No newline at end of file diff --git a/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/application/port/inbound/account/DepositAccountInPort.kt b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/application/port/inbound/account/DepositAccountInPort.kt new file mode 100644 index 0000000..555dca7 --- /dev/null +++ b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/application/port/inbound/account/DepositAccountInPort.kt @@ -0,0 +1,8 @@ +package io.holixon.cqrshexagonaldemo.demoparent.transactions.application.port.inbound.account + +import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.account.Amount +import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.account.Iban + +interface DepositAccountInPort { + fun deposit(iban: Iban, amount: Amount) +} \ No newline at end of file diff --git a/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/application/port/outbound/account/AccountOutPort.kt b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/application/port/outbound/account/AccountOutPort.kt index dd386bc..1754d87 100644 --- a/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/application/port/outbound/account/AccountOutPort.kt +++ b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/application/port/outbound/account/AccountOutPort.kt @@ -1,9 +1,11 @@ package io.holixon.cqrshexagonaldemo.demoparent.transactions.application.port.outbound.account import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.account.Account +import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.account.Amount import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.account.Iban interface AccountOutPort { - fun findAccount(iban: Iban): Account? + fun findAccount(iban: Iban): Account fun createAccount(account: Account): Account + fun deposit(account: Account, amount: Amount): Account } diff --git a/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/application/usecase/CreateAccountUsecase.kt b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/application/usecase/CreateAccountUsecase.kt index 41047fc..3a6bfa9 100644 --- a/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/application/usecase/CreateAccountUsecase.kt +++ b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/application/usecase/CreateAccountUsecase.kt @@ -11,6 +11,7 @@ import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.event.A import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.service.CustomerAccountVerificationService import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.service.IbanCreationService import io.holixon.cqrshexagonaldemo.demoparent.transactions.framework.Usecase +import mu.KLogging @Usecase open class CreateAccountUsecase( @@ -21,7 +22,10 @@ open class CreateAccountUsecase( private val eventingOutAdapter: EventingOutAdapter ) : CreateAccountInPort { + companion object : KLogging() + override fun createAccount(customerNumber: CustomerNumber): Account { + logger().info { "create new account for customer $customerNumber" } val customer = customerOutPort.findCustomer(customerNumber) ?: throw RuntimeException("no customer") @@ -40,6 +44,7 @@ open class CreateAccountUsecase( val accountCreatedEvent = AccountCreatedEvent(customerNumber, createdAccount.iban) eventingOutAdapter.publishEvent(accountCreatedEvent) + logger().info { "newly created account: $createdAccount" } return createdAccount } } diff --git a/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/application/usecase/CreateCustomerUsecase.kt b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/application/usecase/CreateCustomerUsecase.kt index 016389e..7b9aba2 100644 --- a/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/application/usecase/CreateCustomerUsecase.kt +++ b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/application/usecase/CreateCustomerUsecase.kt @@ -8,6 +8,7 @@ import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.custome import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.event.CustomerCreatedEvent import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.service.CustomerNumberCreationService import io.holixon.cqrshexagonaldemo.demoparent.transactions.framework.Usecase +import mu.KLogging @Usecase open class CreateCustomerUsecase( @@ -16,7 +17,10 @@ open class CreateCustomerUsecase( private val eventingOutAdapter: EventingOutAdapter ) : CreateCustomerInPort { + companion object : KLogging() + override fun createCustomer(customerName: Name): Customer { + logger().info { "register new customer ${customerName.value}" } val customer = Customer( customerNumber = customerNumberCreationService.generateNextCustomerNumber(), name = customerName) @@ -25,6 +29,7 @@ open class CreateCustomerUsecase( val customerCreatedEvent = CustomerCreatedEvent(customerName = customerName, customerNumber = createdCustomer.customerNumber) eventingOutAdapter.publishEvent(customerCreatedEvent) + logger().info { "newly registered customer: $createdCustomer" } return createdCustomer } diff --git a/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/application/usecase/DepositUsecase.kt b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/application/usecase/DepositUsecase.kt new file mode 100644 index 0000000..c1afa53 --- /dev/null +++ b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/application/usecase/DepositUsecase.kt @@ -0,0 +1,36 @@ +package io.holixon.cqrshexagonaldemo.demoparent.transactions.application.usecase + +import io.holixon.cqrshexagonaldemo.demoparent.transactions.application.port.inbound.account.DepositAccountInPort +import io.holixon.cqrshexagonaldemo.demoparent.transactions.application.port.outbound.account.AccountOutPort +import io.holixon.cqrshexagonaldemo.demoparent.transactions.application.port.outbound.eventing.EventingOutAdapter +import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.account.Amount +import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.account.Iban +import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.event.MoneyDepositedEvent +import io.holixon.cqrshexagonaldemo.demoparent.transactions.framework.Usecase +import mu.KLogging + +@Usecase +class DepositUsecase( + private val accountOutPort: AccountOutPort, + private val eventingOutAdapter: EventingOutAdapter +) : DepositAccountInPort { + + companion object : KLogging() + + override fun deposit(iban: Iban, amount: Amount) { + logger().info { "deposit $amount to account ${iban.value}" } + + val account = accountOutPort.findAccount(iban) + + val updatedAccount = accountOutPort.deposit(account, amount) + + eventingOutAdapter.publishEvent(MoneyDepositedEvent( + updatedAccount.iban, + updatedAccount.balance, + System.currentTimeMillis() + )) + + logger().info { "updated account $updatedAccount" } + } + +} diff --git a/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/domain/exception/AccountNotFoundException.kt b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/domain/exception/AccountNotFoundException.kt new file mode 100644 index 0000000..3269724 --- /dev/null +++ b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/domain/exception/AccountNotFoundException.kt @@ -0,0 +1,3 @@ +package io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.exception + +class AccountNotFoundException(message: String) : RuntimeException(message) \ No newline at end of file diff --git a/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/domain/exception/InvalidInputException.kt b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/domain/exception/InvalidInputException.kt new file mode 100644 index 0000000..6d0c1ab --- /dev/null +++ b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/domain/exception/InvalidInputException.kt @@ -0,0 +1,3 @@ +package io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.exception + +class InvalidInputException(message: String) : RuntimeException(message) diff --git a/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/domain/model/account/Account.kt b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/domain/model/account/Account.kt index 3af696e..16111f7 100644 --- a/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/domain/model/account/Account.kt +++ b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/domain/model/account/Account.kt @@ -6,4 +6,10 @@ data class Account( var customerNumber: CustomerNumber, var iban: Iban, var balance: Money -) +) { + fun deposit(amount: Amount) { + // TODO: better immutable? + this.balance.amount += amount + } + +} diff --git a/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/domain/model/account/Amount.kt b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/domain/model/account/Amount.kt new file mode 100644 index 0000000..432ab79 --- /dev/null +++ b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/domain/model/account/Amount.kt @@ -0,0 +1,23 @@ +package io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.account + +import java.math.BigDecimal + +/** + * For now this class can be value class in future when currency is introduced must be revised to support currency + */ +@JvmInline +value class Amount(val value: BigDecimal) { + init { + require(value >= BigDecimal.ZERO){ + "Amount must be positive" + } + } + + operator fun plus(value2: Amount) : Amount { + return Amount(this.value.plus(value2.value)) + } + + override fun toString(): String { + return value.toString() + } +} diff --git a/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/domain/model/account/Iban.kt b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/domain/model/account/Iban.kt index 0a7189a..471a5fb 100644 --- a/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/domain/model/account/Iban.kt +++ b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/domain/model/account/Iban.kt @@ -1,4 +1,9 @@ package io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.account @JvmInline -value class Iban(val value: String) +value class Iban(val value: String) { + + override fun toString(): String { + return value + } +} diff --git a/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/domain/model/account/Money.kt b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/domain/model/account/Money.kt index 832f23b..fbe6047 100644 --- a/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/domain/model/account/Money.kt +++ b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/domain/model/account/Money.kt @@ -2,8 +2,8 @@ package io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.accoun import java.math.BigDecimal -data class Money(var amount: BigDecimal) { +data class Money(var amount: Amount) { companion object { - val ZERO = Money(BigDecimal.ZERO) + val ZERO = Money(Amount(BigDecimal.ZERO)) } } diff --git a/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/domain/model/common/Name.kt b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/domain/model/common/Name.kt index deed333..0c0672b 100644 --- a/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/domain/model/common/Name.kt +++ b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/domain/model/common/Name.kt @@ -1,4 +1,8 @@ package io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.common @JvmInline -value class Name(val value: String) +value class Name(val value: String) { + override fun toString(): String { + return value + } +} diff --git a/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/domain/model/customer/CustomerNumber.kt b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/domain/model/customer/CustomerNumber.kt index f2df9c0..55ccf43 100644 --- a/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/domain/model/customer/CustomerNumber.kt +++ b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/domain/model/customer/CustomerNumber.kt @@ -1,4 +1,8 @@ package io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.customer @JvmInline -value class CustomerNumber(val value: String) +value class CustomerNumber(val value: String) { + override fun toString(): String { + return value + } +} diff --git a/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/domain/model/event/MoneyDepositedEvent.kt b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/domain/model/event/MoneyDepositedEvent.kt new file mode 100644 index 0000000..c141f41 --- /dev/null +++ b/demo-transactions/src/main/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/domain/model/event/MoneyDepositedEvent.kt @@ -0,0 +1,6 @@ +package io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.event + +import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.account.Iban +import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.account.Money + +data class MoneyDepositedEvent(val iban: Iban, val balance: Money, val timeStamp: Long) : Event diff --git a/demo-transactions/src/main/resources/api/api.yaml b/demo-transactions/src/main/resources/api/api.yaml index 797975f..689335e 100644 --- a/demo-transactions/src/main/resources/api/api.yaml +++ b/demo-transactions/src/main/resources/api/api.yaml @@ -72,6 +72,34 @@ paths: application/json: schema: $ref: '#/components/schemas/AccountCreatedResponse' + /api/v1/account/deposit: + post: + tags: + - account + summary: > + Deposit money + description: > + Deposit money for a specified account + operationId: deposit + requestBody: + required: true + content: + application/json: + schema: + properties: + iban: + type: string + amount: + type: number + format: double + required: + - iban + - amount + responses: + '204': + description: Money Deposited + '404': + description: No Account found components: schemas: AccountCreatedResponse: diff --git a/demo-transactions/src/main/resources/application-IT.yaml b/demo-transactions/src/main/resources/application-IT.yaml index adbab8c..2192af8 100644 --- a/demo-transactions/src/main/resources/application-IT.yaml +++ b/demo-transactions/src/main/resources/application-IT.yaml @@ -1,8 +1,4 @@ spring: - flyway: - user: SA - password: Aut0mat0rs! - url: jdbc:mysql://localhost:3306/transactions jpa: hibernate: ddl-auto: create-drop \ No newline at end of file diff --git a/demo-transactions/src/main/resources/application-local.yaml b/demo-transactions/src/main/resources/application-local.yaml index 33bf262..730c078 100644 --- a/demo-transactions/src/main/resources/application-local.yaml +++ b/demo-transactions/src/main/resources/application-local.yaml @@ -1,9 +1,5 @@ spring: datasource: - url: jdbc:mysql://localhost:3306/transactions + url: jdbc:mysql://localhost:3306/cqrs-meets-hexagonal username: SA password: Aut0mat0rs! - flyway: - user: SA - password: Aut0mat0rs! - url: jdbc:mysql://localhost:3306/transactions diff --git a/demo-transactions/src/main/resources/application.yaml b/demo-transactions/src/main/resources/application.yaml index 82fdcfb..eef4966 100644 --- a/demo-transactions/src/main/resources/application.yaml +++ b/demo-transactions/src/main/resources/application.yaml @@ -31,18 +31,11 @@ spring: hibernate: ddl-auto: none generate_statistics: true - database-platform: org.hibernate.dialect.MySQL8Dialect - properties: - hibernate: - default_schema: transactions flyway: enabled: true - user: ${FLYWAY_USER} - password: ${FLYWAY_PASSWORD} - url: ${FLYWAY_URL} - schemas: - - transactions - - query + user: ${spring.datasource.username} + password: ${spring.datasource.password} + url: ${spring.datasource.url} locations: - classpath:db diff --git a/demo-transactions/src/main/resources/db/V0_0_1__create_tables_account_customer.sql b/demo-transactions/src/main/resources/db/V0_0_1__create_tables_account_customer.sql index af09e9f..9e2006e 100644 --- a/demo-transactions/src/main/resources/db/V0_0_1__create_tables_account_customer.sql +++ b/demo-transactions/src/main/resources/db/V0_0_1__create_tables_account_customer.sql @@ -1,4 +1,4 @@ -CREATE TABLE transactions.customer +CREATE TABLE customer ( customer_number VARCHAR(255) NOT NULL, customer_name VARCHAR(255) NOT NULL, @@ -6,7 +6,7 @@ CREATE TABLE transactions.customer CONSTRAINT PK_CUSTOMER_ID PRIMARY KEY (customer_number) ); -CREATE TABLE transactions.account +CREATE TABLE account ( iban VARCHAR(255) NOT NULL, customer_number VARCHAR(255) NOT NULL, diff --git a/demo-transactions/src/main/resources/db/V0_0_2__add_balance_account.sql b/demo-transactions/src/main/resources/db/V0_0_2__add_balance_account.sql index 550c759..155d365 100644 --- a/demo-transactions/src/main/resources/db/V0_0_2__add_balance_account.sql +++ b/demo-transactions/src/main/resources/db/V0_0_2__add_balance_account.sql @@ -1,2 +1,2 @@ -ALTER TABLE transactions.account -ADD COLUMN balance DECIMAL NOT NULL DEFAULT 0; +ALTER TABLE account +ADD COLUMN balance DECIMAL(10, 2) NOT NULL DEFAULT 0; diff --git a/demo-transactions/src/test/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/application/usecase/CreateAccountUsecaseTest.kt b/demo-transactions/src/test/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/application/usecase/CreateAccountUsecaseTest.kt index ff9047f..43903e3 100644 --- a/demo-transactions/src/test/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/application/usecase/CreateAccountUsecaseTest.kt +++ b/demo-transactions/src/test/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/application/usecase/CreateAccountUsecaseTest.kt @@ -1,8 +1,5 @@ package io.holixon.cqrshexagonaldemo.demoparent.transactions.application.usecase -import com.nhaarman.mockitokotlin2.any -import com.nhaarman.mockitokotlin2.verify -import com.nhaarman.mockitokotlin2.whenever import io.holixon.cqrshexagonaldemo.demoparent.transactions.application.port.outbound.account.AccountOutPort import io.holixon.cqrshexagonaldemo.demoparent.transactions.application.port.outbound.customer.CustomerOutPort import io.holixon.cqrshexagonaldemo.demoparent.transactions.application.port.outbound.eventing.EventingOutAdapter @@ -15,34 +12,35 @@ import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.custome import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.event.AccountCreatedEvent import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.service.CustomerAccountVerificationService import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.service.IbanCreationService +import io.mockk.every +import io.mockk.impl.annotations.InjectMockKs +import io.mockk.impl.annotations.MockK +import io.mockk.impl.annotations.RelaxedMockK +import io.mockk.junit5.MockKExtension +import io.mockk.verify import org.assertj.core.api.Assertions import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith -import org.mockito.InjectMocks -import org.mockito.Mock -import org.mockito.Mockito -import org.mockito.junit.jupiter.MockitoExtension - -@ExtendWith(MockitoExtension::class) +@ExtendWith(MockKExtension::class) class CreateAccountUsecaseTest { - @Mock + @MockK private lateinit var accountOutPort: AccountOutPort - @Mock + @MockK private lateinit var customerOutPort: CustomerOutPort - @Mock + @MockK private lateinit var customerAccountVerificationService: CustomerAccountVerificationService - @Mock + @MockK private lateinit var ibanCreationService: IbanCreationService - @Mock + @RelaxedMockK private lateinit var eventingOutAdapter: EventingOutAdapter - @InjectMocks + @InjectMockKs private lateinit var createAccountUsecase: CreateAccountUsecase @Test @@ -50,21 +48,24 @@ class CreateAccountUsecaseTest { // given val customerNumber = CustomerNumber("123456789") val customer = Customer(customerNumber, Name("Dagobert Duck")) - whenever(customerOutPort.findCustomer(customerNumber)).thenReturn(customer) - whenever(customerAccountVerificationService.canAccountBeCreatedForCustomer(customer)).thenReturn(true) + every { customerOutPort.findCustomer(customerNumber) } returns customer + every { customerAccountVerificationService.canAccountBeCreatedForCustomer(customer) } returns true + val iban = Iban("DE00123456789") - whenever(ibanCreationService.generateNextIban()).thenReturn(iban) + + every { ibanCreationService.generateNextIban() } returns iban val balance = Money.ZERO val account = Account(customerNumber, iban, balance) - whenever(accountOutPort.createAccount(any())).thenReturn(account) + + every { accountOutPort.createAccount(this.any()) } returns account // when val createdAccount = createAccountUsecase.createAccount(customerNumber) // then Assertions.assertThat(createdAccount).isNotNull - verify(accountOutPort).createAccount(account) - Mockito.verify(eventingOutAdapter).publishEvent(AccountCreatedEvent(customerNumber, iban)) + verify { accountOutPort.createAccount(account) } + verify { eventingOutAdapter.publishEvent(AccountCreatedEvent(customerNumber, iban)) } } } diff --git a/demo-transactions/src/test/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/application/usecase/CreateCustomerUsecaseTest.kt b/demo-transactions/src/test/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/application/usecase/CreateCustomerUsecaseTest.kt index 9492ded..0ae712e 100644 --- a/demo-transactions/src/test/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/application/usecase/CreateCustomerUsecaseTest.kt +++ b/demo-transactions/src/test/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/application/usecase/CreateCustomerUsecaseTest.kt @@ -1,8 +1,5 @@ package io.holixon.cqrshexagonaldemo.demoparent.transactions.application.usecase -import com.nhaarman.mockitokotlin2.any -import com.nhaarman.mockitokotlin2.verify -import com.nhaarman.mockitokotlin2.whenever import io.holixon.cqrshexagonaldemo.demoparent.transactions.application.port.outbound.customer.CustomerOutPort import io.holixon.cqrshexagonaldemo.demoparent.transactions.application.port.outbound.eventing.EventingOutAdapter import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.common.Name @@ -10,43 +7,48 @@ import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.custome import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.customer.CustomerNumber import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.event.CustomerCreatedEvent import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.service.CustomerNumberCreationService +import io.mockk.every +import io.mockk.impl.annotations.InjectMockKs +import io.mockk.impl.annotations.MockK +import io.mockk.impl.annotations.RelaxedMockK +import io.mockk.junit5.MockKExtension +import io.mockk.verify import org.assertj.core.api.Assertions import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith -import org.mockito.InjectMocks -import org.mockito.Mock -import org.mockito.Mockito -import org.mockito.junit.jupiter.MockitoExtension -@ExtendWith(MockitoExtension::class) +@ExtendWith(MockKExtension::class) class CreateCustomerUsecaseTest { - @Mock + @MockK private lateinit var customerOutPort: CustomerOutPort - @Mock + + @MockK private lateinit var customerNumberCreationService: CustomerNumberCreationService - @Mock + + @RelaxedMockK private lateinit var eventingOutAdapter: EventingOutAdapter - @InjectMocks + @InjectMockKs private lateinit var createCustomerUsecase: CreateCustomerUsecase @Test fun `should create a new customer`() { - // angenommen + // angenommen val customerNumber = CustomerNumber("000123") - whenever(customerNumberCreationService.generateNextCustomerNumber()).thenReturn(customerNumber) + every { customerNumberCreationService.generateNextCustomerNumber() } returns customerNumber val customerName = Name("Richi Rich") val customer = Customer(customerNumber, customerName) - whenever(customerOutPort.createCustomer(any())).thenReturn(customer) - // wenn + every { customerOutPort.createCustomer(this.any()) } returns customer + + // wenn val createdCustomer = createCustomerUsecase.createCustomer(customerName) // dann Assertions.assertThat(createdCustomer).isNotNull - verify(customerOutPort).createCustomer(customer) - Mockito.verify(eventingOutAdapter).publishEvent(CustomerCreatedEvent(customerName, customerNumber)) + verify { customerOutPort.createCustomer(customer) } + verify { eventingOutAdapter.publishEvent(CustomerCreatedEvent(customerName, customerNumber)) } } } \ No newline at end of file diff --git a/demo-transactions/src/test/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/application/usecase/DepositUsecaseTest.kt b/demo-transactions/src/test/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/application/usecase/DepositUsecaseTest.kt new file mode 100644 index 0000000..6c385c1 --- /dev/null +++ b/demo-transactions/src/test/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/application/usecase/DepositUsecaseTest.kt @@ -0,0 +1,100 @@ +package io.holixon.cqrshexagonaldemo.demoparent.transactions.application.usecase + +import io.holixon.cqrshexagonaldemo.demoparent.transactions.application.port.outbound.account.AccountOutPort +import io.holixon.cqrshexagonaldemo.demoparent.transactions.application.port.outbound.eventing.EventingOutAdapter +import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.exception.AccountNotFoundException +import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.account.Account +import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.account.Amount +import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.account.Iban +import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.account.Money +import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.customer.CustomerNumber +import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.event.MoneyDepositedEvent +import io.mockk.every +import io.mockk.impl.annotations.InjectMockKs +import io.mockk.impl.annotations.MockK +import io.mockk.impl.annotations.RelaxedMockK +import io.mockk.junit5.MockKExtension +import io.mockk.verify +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import org.junit.jupiter.api.extension.ExtendWith +import java.math.BigDecimal + +@ExtendWith(MockKExtension::class) +class DepositUsecaseTest { + + @MockK + private lateinit var accountOutPort: AccountOutPort + + @RelaxedMockK + private lateinit var eventingOutAdapter: EventingOutAdapter + + @InjectMockKs + private lateinit var depositUsecase: DepositUsecase + + private val validIban = Iban("DE00123456789") + + @Test + fun `should deposit on valid account`() { + //Arrange + val account = Account( + CustomerNumber("000123"), + validIban, + Money(Amount(BigDecimal.valueOf(123.45))) + ) + + every { + accountOutPort.findAccount(any()) + } returns account + + every { + accountOutPort.deposit(any(), Amount(BigDecimal.ONE)) + } returns Account( + account.customerNumber, + validIban, + Money(Amount(BigDecimal.valueOf(124.45))) + ) + + //Act + depositUsecase.deposit(validIban, Amount(BigDecimal.ONE)) + + //Assert + verify { + eventingOutAdapter.publishEvent(any(MoneyDepositedEvent::class)) + } + } + + @Test + fun `should not deposit with non existent account`() { + //Arrange + every { + accountOutPort.deposit(any(Account::class), Amount(BigDecimal.ONE)) + } throws AccountNotFoundException("Account not found") + + every { + accountOutPort.findAccount(any()) + } returns Account(CustomerNumber("abc"), validIban, Money(Amount(BigDecimal.ONE))) + + // Act and Assert + assertThrows { + depositUsecase.deposit(validIban, Amount(BigDecimal.ONE)) + } + + verify(exactly = 0) { + eventingOutAdapter.publishEvent(any(MoneyDepositedEvent::class)) + } + } + + @Test + fun `should not deposit with negative deposit value`() { + //Assert + assertThrows { + depositUsecase.deposit(validIban, Amount(BigDecimal.ONE.negate())) + } + + verify(exactly = 0) { + eventingOutAdapter.publishEvent(any(MoneyDepositedEvent::class)) + } + } + +} diff --git a/demo-transactions/src/test/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/integrationtest/GlobalIT.kt b/demo-transactions/src/test/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/integrationtest/GlobalIT.kt index fa94f07..420340c 100644 --- a/demo-transactions/src/test/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/integrationtest/GlobalIT.kt +++ b/demo-transactions/src/test/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/integrationtest/GlobalIT.kt @@ -1,7 +1,12 @@ package io.holixon.cqrshexagonaldemo.demoparent.transactions.integrationtest +import io.holixon.cqrshexagonaldemo.demoparent.transactions.application.port.inbound.account.CreateAccountInPort +import io.holixon.cqrshexagonaldemo.demoparent.transactions.application.port.inbound.account.DepositAccountInPort import io.holixon.cqrshexagonaldemo.demoparent.transactions.application.port.inbound.customer.CreateCustomerInPort +import io.holixon.cqrshexagonaldemo.demoparent.transactions.application.port.outbound.account.AccountOutPort +import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.account.Amount import io.holixon.cqrshexagonaldemo.demoparent.transactions.domain.model.common.Name +import org.assertj.core.api.Assertions import org.hamcrest.CoreMatchers.containsString import org.junit.jupiter.api.Test import org.springframework.beans.factory.annotation.Autowired @@ -9,12 +14,22 @@ import org.springframework.http.MediaType import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post import org.springframework.test.web.servlet.result.MockMvcResultMatchers.content import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status +import java.math.BigDecimal class GlobalIT : IntegrationTextBase() { @Autowired private lateinit var createCustomerInPort: CreateCustomerInPort + @Autowired + private lateinit var createAccountInPort: CreateAccountInPort + + @Autowired + private lateinit var depositAccountInPort: DepositAccountInPort + + @Autowired + private lateinit var accountOutPort: AccountOutPort + @Test fun `should create customer`() { // given @@ -26,15 +41,16 @@ class GlobalIT : IntegrationTextBase() { // when val response = this.mockMvc.perform( - post("/api/v1/customer/create") - .accept(MediaType.APPLICATION_JSON) - .contentType(MediaType.APPLICATION_JSON) - .content(payload)) + post("/api/v1/customer/create") + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(payload) + ) // then response.andExpect(status().isOk) - .andExpect(content().string(containsString("\"name\":\"Dagobert Duck\""))) - .andExpect(content().string(containsString("\"customerNumber\":"))) + .andExpect(content().string(containsString("\"name\":\"Dagobert Duck\""))) + .andExpect(content().string(containsString("\"customerNumber\":"))) } @Test @@ -50,14 +66,44 @@ class GlobalIT : IntegrationTextBase() { // when val response = this.mockMvc.perform( - post("/api/v1/account/create") - .accept(MediaType.APPLICATION_JSON) - .contentType(MediaType.APPLICATION_JSON) - .content(payload)) + post("/api/v1/account/create") + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(payload) + ) // then response.andExpect(status().isOk) - .andExpect(content().string(containsString("\"customerNumber\":\"${customer.customerNumber.value}\""))) - .andExpect(content().string(containsString("\"iban\":"))) + .andExpect(content().string(containsString("\"customerNumber\":\"${customer.customerNumber.value}\""))) + .andExpect(content().string(containsString("\"iban\":"))) + } + + + @Test + fun `should deposit money on existing account`() { + // given + val customer = createCustomerInPort.createCustomer(Name("Charles Montgomery Burns")) + val account = createAccountInPort.createAccount(customer.customerNumber) + depositAccountInPort.deposit(account.iban, Amount(BigDecimal.valueOf(123.45))) + + val payload = """ + { + "iban": "${account.iban}", + "amount": 111.11 + } + """.trimIndent() + + // when + val response = this.mockMvc.perform( + post("/api/v1/account/deposit") + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(payload) + ) + + // then + response.andExpect(status().isNoContent) + val currentAccount = accountOutPort.findAccount(account.iban) + Assertions.assertThat(currentAccount.balance.amount).isEqualTo(Amount(BigDecimal.valueOf(234.56))) } } \ No newline at end of file diff --git a/demo-transactions/src/test/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/integrationtest/testcontainers/MySqlTestContainerExtension.kt b/demo-transactions/src/test/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/integrationtest/testcontainers/MySqlTestContainerExtension.kt index 9833a36..aca7526 100644 --- a/demo-transactions/src/test/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/integrationtest/testcontainers/MySqlTestContainerExtension.kt +++ b/demo-transactions/src/test/kotlin/io/holixon/cqrshexagonaldemo/demoparent/transactions/integrationtest/testcontainers/MySqlTestContainerExtension.kt @@ -16,9 +16,9 @@ class MySqlTestContainerExtension : BeforeAllCallback, AfterAllCallback { override fun beforeAll(p0: ExtensionContext?) { mysql = MySQLContainer(CONTAINER_IMAGE_TAG) - .withDatabaseName("cqrs-meets-hexagonal") - .withUsername("SA") - .withPassword("Aut0mat0rs!") + .withDatabaseName("cqrs-meets-hexagonal-test") + .withUsername("dbuser") + .withPassword("password") mysql.start() diff --git a/docker/azure-sql-edge/data/.gitkeep b/docker/azure-sql-edge/data/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/docker/azure-sql-edge/docker-compose.yaml b/docker/azure-sql-edge/docker-compose.yaml deleted file mode 100644 index df73973..0000000 --- a/docker/azure-sql-edge/docker-compose.yaml +++ /dev/null @@ -1,55 +0,0 @@ -version: "3.5" -name: cqrs-meets-hexagonal - -services: - database: - image: mcr.microsoft.com/azure-sql-edge - container_name: cqrs-meets-hexagonal-azure-sql - environment: - ACCEPT_EULA: Y - MSSQL_SA_PASSWORD: Aut0mat0rs! - TZ: UTC - ports: - - "1434:1433" - volumes: - - ./data:/var/opt/mssql/data - - ./log:/var/opt/mssql/log - - ./secrets:/var/opt/mssql/secrets - - databaseSetup: - image: mcr.microsoft.com/mssql/server:2019-latest - container_name: cqrs-meets-hexagonal-azure-sql-setup - depends_on: - - database - restart: "no" - environment: - TZ: UTC - volumes: - - ./local:/opt/startup-scripts - entrypoint: [ "bash", "-c", "while ! /opt/mssql-tools/bin/sqlcmd -S cqrs-meets-hexagonal-azure-sql -U SA -P 'Aut0mat0rs!' -Q \"$$(cat /opt/startup-scripts/local-db-setup.sql)\"; do sleep 5; done" ] - - zookeeper: - image: confluentinc/cp-zookeeper:latest - environment: - ZOOKEEPER_CLIENT_PORT: 2182 - ZOOKEEPER_TICK_TIME: 2000 - ports: - - 22182:2182 - - kafka: - image: confluentinc/cp-kafka:latest - depends_on: - - zookeeper - ports: - - 29093:29092 - environment: - KAFKA_BROKER_ID: 1 - KAFKA_ZOOKEEPER_CONNECT: zookeeper:2182 - KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092,PLAINTEXT_HOST://localhost:29092 - KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT - KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT - KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 - KAFKA_AUTO_CREATE_TOPICS_ENABLE: "true" -networks: - cqrs-meets-hexagonal: - external: true diff --git a/docker/azure-sql-edge/local/local-db-setup.sql b/docker/azure-sql-edge/local/local-db-setup.sql deleted file mode 100644 index 67bc883..0000000 --- a/docker/azure-sql-edge/local/local-db-setup.sql +++ /dev/null @@ -1,3 +0,0 @@ -CREATE DATABASE [cqrs-meets-hexagonal]; -ALTER DATABASE [cqrs-meets-hexagonal] SET READ_COMMITTED_SNAPSHOT ON; -ALTER DATABASE [cqrs-meets-hexagonal] SET ALLOW_SNAPSHOT_ISOLATION ON; \ No newline at end of file diff --git a/docker/azure-sql-edge/local/rename-dbo-schema.sql b/docker/azure-sql-edge/local/rename-dbo-schema.sql deleted file mode 100644 index 03e95e7..0000000 --- a/docker/azure-sql-edge/local/rename-dbo-schema.sql +++ /dev/null @@ -1,4 +0,0 @@ -CREATE SCHEMA [transactions]; -GO; -CREATE SCHEMA [query]; -GO; diff --git a/docker/azure-sql-edge/log/.gitkeep b/docker/azure-sql-edge/log/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/docker/azure-sql-edge/run.sh b/docker/azure-sql-edge/run.sh deleted file mode 100755 index 5a6cb7b..0000000 --- a/docker/azure-sql-edge/run.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -colima start --cpu 2 --memory 4 --disk 10 -docker-compose up diff --git a/docker/azure-sql-edge/secrets/.gitkeep b/docker/azure-sql-edge/secrets/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/docker/mysql/docker-compose.yaml b/docker/mysql/docker-compose.yaml index 631ab74..3202977 100644 --- a/docker/mysql/docker-compose.yaml +++ b/docker/mysql/docker-compose.yaml @@ -12,8 +12,6 @@ services: MYSQL_ROOT_PASSWORD: 'Aut0mat0rs!' ports: - '3306:3306' - volumes: - - ./init.sql:/docker-entrypoint-initdb.d/init.sql volumes: data: diff --git a/docker/mysql/init.sql b/docker/mysql/init.sql deleted file mode 100644 index c9ace02..0000000 --- a/docker/mysql/init.sql +++ /dev/null @@ -1,7 +0,0 @@ -CREATE SCHEMA IF NOT EXISTS `transactions`; -CREATE SCHEMA IF NOT EXISTS `query`; - -GRANT ALL PRIVILEGES ON transactions.* TO 'SA'@'%'; -GRANT ALL PRIVILEGES ON query.* TO 'SA'@'%'; -FLUSH PRIVILEGES; - diff --git a/pom.xml b/pom.xml index 266b1dc..adc92bd 100644 --- a/pom.xml +++ b/pom.xml @@ -36,5 +36,6 @@ 2.4.0 1.19.7 2.0.1.Final + 1.13.10