This project illustrates TDD & Clean Architecture implementation in Java

Overview

Banking Kata - Java

CI

Overview

This project illustrates TDD & Clean Architecture implementation in Java, showing the Use Case Driven Development Approach.

We implement a Banking system with the following use cases:

  • Open account
  • Withdraw funds
  • Deposit funds
  • View account

Prerequisites

  • OpenJDK 17

Instructions

Running build with automated tests:

./gradlew build

Running JaCoCo code coverage:

./gradlew jacocoTestReport

Running PIT mutation testing:

./gradlew pitest

Reports

See the build\reports directory for the generated reports for test results, code coverage and mutation testing.

Reports:

  • build\reports\tests
  • build\reports\jacoco
  • build\reports\pitest
Comments
  • Keycloak - Local execution issue

    Keycloak - Local execution issue

    Keycloak works on GitHub Actions, but not locally when run on my machine.

    This is the trace from my local machine - executing it from IntelliJ terminal. I use Windows.

    
    PS C:\Users\valen\GitHub\valentinacupac\banking-kata-java> $env:POSTGRES_URL='jdbc:postgresql://localhost:5432/banking_kata'
    PS C:\Users\valen\GitHub\valentinacupac\banking-kata-java> $env:POSTGRES_USER='postgres'
    PS C:\Users\valen\GitHub\valentinacupac\banking-kata-java> $env:POSTGRES_PASSWORD='admin'
    PS C:\Users\valen\GitHub\valentinacupac\banking-kata-java> $env:MONGO_INITDB_ROOT_USERNAME='rootuser'
    PS C:\Users\valen\GitHub\valentinacupac\banking-kata-java> $env:MONGO_INITDB_ROOT_PASSWORD='rootpass'
    PS C:\Users\valen\GitHub\valentinacupac\banking-kata-java> $env:ME_CONFIG_MONGODB_ADMINUSERNAME='rootuser'
    PS C:\Users\valen\GitHub\valentinacupac\banking-kata-java> $env:ME_CONFIG_MONGODB_ADMINPASSWORD='rootpass'
    PS C:\Users\valen\GitHub\valentinacupac\banking-kata-java> $env:ME_CONFIG_MONGODB_SERVER='mongodb'
    PS C:\Users\valen\GitHub\valentinacupac\banking-kata-java> $env:KEYCLOAK_REALM_URL='http://localhost:10000/auth/realms/banking-kata'
    PS C:\Users\valen\GitHub\valentinacupac\banking-kata-java> $env:KEYCLOAK_TEST_CLIENT_ID='test-client'
    PS C:\Users\valen\GitHub\valentinacupac\banking-kata-java> $env:KEYCLOAK_TEST_CLIENT_SECRET='B9N1WDFFMuZmYuEzXSbRC739YGaE7kb5'
    
    
    
    PS C:\Users\valen\GitHub\valentinacupac\banking-kata-java> docker-compose up -d                                                     
    Creating network "banking-kata-java_local" with the default driver
    Creating network "banking-kata-java_default" with the default driver
    Creating postgres      ... done
    Creating mongo-express ... done
    Creating mongodb       ... done
    Creating keycloak      ... done
    Creating adminer       ... done
    
    
    
    
    PS C:\Users\valen\GitHub\valentinacupac\banking-kata-java> ./gradlew integrationTest
    
    > Task :integrationTest
    
    BankAccountControllerSystemTest > should_open_account_given_valid_request() FAILED
        org.springframework.web.reactive.function.client.WebClientRequestException at ExchangeFunctions.java:141
            Caused by: java.io.IOException at SocketDispatcher.java:-2
    2022-12-29 15:11:51.310  INFO 16964 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
    2022-12-29 15:11:51.314  INFO 16964 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
    2022-12-29 15:11:51.317  INFO 16964 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.
    2022-12-29 15:11:51.321  INFO 16964 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
    2022-12-29 15:11:51.322  INFO 16964 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-2 - Shutdown initiated...
    2022-12-29 15:11:51.324  INFO 16964 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-2 - Shutdown completed.
    2022-12-29 15:11:51.337  INFO 16964 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
    2022-12-29 15:11:51.337  INFO 16964 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-3 - Shutdown initiated...
    2022-12-29 15:11:51.339  INFO 16964 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-3 - Shutdown completed.
    
    22 tests completed, 1 failed
    
    
    

    The more detailed error is:

    should_open_account_given_valid_request()
    
    org.springframework.web.reactive.function.client.WebClientRequestException: An established connection was aborted by the software in your host machine; nested exception is java.io.IOException: An established connection was aborted by the software in your host machine
    	at app//org.springframework.web.reactive.function.client.ExchangeFunctions$DefaultExchangeFunction.lambda$wrapException$9(ExchangeFunctions.java:141)
    	at app//reactor.core.publisher.MonoErrorSupplied.subscribe(MonoErrorSupplied.java:55)
    
    Caused by: java.io.IOException: An established connection was aborted by the software in your host machine
    	at java.base/sun.nio.ch.SocketDispatcher.read0(Native Method)
    	at java.base/sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:46)
    
    

    Also, I noticed that Keycloak randomly goes into restarting mode for me. image

    And I get these kinds of errors locally with Keycloak (logs via Docker)

    14:22:00,823 ERROR [org.jboss.as.controller.management-operation] (Controller Boot Thread) WFLYCTL0013: Operation ("add") failed - address: ([("subsystem" => "metrics")]): java.lang.NullPointerException
    	at [email protected]//org.wildfly.extension.metrics.MetricsSubsystemAdd$2.execute(MetricsSubsystemAdd.java:91)
    
    bug 
    opened by valentinacupac 4
  • #58 Keycloak - Connection Error - Fix

    #58 Keycloak - Connection Error - Fix

    Changes:

    • Fix keycloak docker image. Now it uses a prepopulated realm (see src/main/resources/keycloak/realm-export.json)
    • Clean-up docker-compose.yml
    • Update ci.yml to use docker-compose.yml instead of custom services
    opened by adrianliz 3
  • Adding instructions and scripts for running PostgreSQL with Docker

    Adding instructions and scripts for running PostgreSQL with Docker

    In order to run integration tests with a PostgreSQL instance running in Docker I created:

    1. a docker-compose.yml file
    2. a script for setting environment variables
    3. a markdown file with some instructions
    opened by f-lombardo 3
  • OpenAccountUseCaseTest: Refactor request

    OpenAccountUseCaseTest: Refactor request

    Discussed in https://github.com/valentinacupac/banking-kata-java/discussions/43

    Originally posted by eamtalu June 26, 2022 Hi, I was just reviewing the testcases and one thing crossed into my mind. In the test case: OpenAccountUseCaseTest, I think the setup codes with GivenThat have no use in the test case - should_open_account_given_valid_request or at least I could not understand the use of it in this test case. Hence creating confusion may be.

    void should_open_account_given_valid_request(String firstName, String lastName, int initialBalance, long generatedAccountId, String generatedAccountNumber, LocalDate openingDate) { givenThat(accountIdGenerator).willGenerate(generatedAccountId); givenThat(accountNumberGenerator).willGenerate(generatedAccountNumber); givenThat(dateTimeService).willReturn(LocalDateTime.of(openingDate, LocalTime.MIN));

    Can I say, refactoring the test case by removing those 3 lines would increase the readability and intention.

    Thanks.

    opened by valentinacupac 2
  • KeyCloak - Connection Error

    KeyCloak - Connection Error

    PROBLEM DESCRIPTION

    BankAccountControllerSystemTest test fails after the changeset with Keycloak addition https://github.com/valentinacupac/banking-kata-java/commit/a69b455162fef3ee25ffe3b31e76f8a58db4b31a

    I executed the instructions as per running_with_docker.md.

    I get this response:

    > Task :test
    
    BankAccountControllerSystemTest > should_open_account_given_valid_request() FAILED
        org.springframework.web.reactive.function.client.WebClientRequestException at ExchangeFunctions.java:141
            Caused by: io.netty.channel.AbstractChannel$AnnotatedConnectException
                Caused by: java.net.ConnectException at Net.java:-2
    2022-12-27 17:56:02.448  INFO 29688 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
    2022-12-27 17:56:02.449  INFO 29688 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
    2022-12-27 17:56:02.452  INFO 29688 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.
    2022-12-27 17:56:02.462  INFO 29688 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
    2022-12-27 17:56:02.464  INFO 29688 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-2 - Shutdown initiated...
    2022-12-27 17:56:02.465  INFO 29688 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-2 - Shutdown completed.
    2022-12-27 17:56:02.472  INFO 29688 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
    2022-12-27 17:56:02.473  INFO 29688 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-3 - Shutdown initiated...
    2022-12-27 17:56:02.474  INFO 29688 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-3 - Shutdown completed.
    
    108 tests completed, 1 failed
    
    > Task :test FAILED
    
    FAILURE: Build failed with an exception.
    

    Reviewing the more detailed stack trace

    org.springframework.web.reactive.function.client.WebClientRequestException: Connection refused: no further information: localhost/127.0.0.1:10000; nested exception is io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information: localhost/127.0.0.1:10000
    	at app//org.springframework.web.reactive.function.client.ExchangeFunctions$DefaultExchangeFunction.lambda$wrapException$9(ExchangeFunctions.java:141)
    	at app//reactor.core.publisher.MonoErrorSupplied.subscribe(MonoErrorSupplied.java:55)
    	at app//reactor.core.publisher.Mono.subscribe(Mono.java:4400)
    	at app//reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:103)
    	at app//reactor.core.publisher.FluxPeek$PeekSubscriber.onError(FluxPeek.java:222)
    	at app//reactor.core.publisher.FluxPeek$PeekSubscriber.onError(FluxPeek.java:222)
    	at app//reactor.core.publisher.FluxMap$MapSubscriber.onError(FluxMap.java:132)
    	at app//reactor.core.publisher.FluxPeek$PeekSubscriber.onError(FluxPeek.java:222)
    	at app//reactor.core.publisher.MonoNext$NextSubscriber.onError(MonoNext.java:93)
    	at app//reactor.core.publisher.MonoFlatMapMany$FlatMapManyMain.onError(MonoFlatMapMany.java:204)
    	at app//reactor.core.publisher.SerializedSubscriber.onError(SerializedSubscriber.java:124)
    	at app//reactor.core.publisher.FluxRetryWhen$RetryWhenMainSubscriber.whenError(FluxRetryWhen.java:225)
    	at app//reactor.core.publisher.FluxRetryWhen$RetryWhenOtherSubscriber.onError(FluxRetryWhen.java:274)
    	at app//reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.drain(FluxConcatMap.java:415)
    	at app//reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.onNext(FluxConcatMap.java:251)
    	at app//reactor.core.publisher.EmitterProcessor.drain(EmitterProcessor.java:491)
    	at app//reactor.core.publisher.EmitterProcessor.tryEmitNext(EmitterProcessor.java:299)
    	at app//reactor.core.publisher.SinkManySerialized.tryEmitNext(SinkManySerialized.java:100)
    	at app//reactor.core.publisher.InternalManySink.emitNext(InternalManySink.java:27)
    	at app//reactor.core.publisher.FluxRetryWhen$RetryWhenMainSubscriber.onError(FluxRetryWhen.java:190)
    	at app//reactor.core.publisher.MonoCreate$DefaultMonoSink.error(MonoCreate.java:194)
    	at app//reactor.netty.http.client.HttpClientConnect$MonoHttpConnect$ClientTransportSubscriber.onError(HttpClientConnect.java:304)
    	at app//reactor.core.publisher.MonoCreate$DefaultMonoSink.error(MonoCreate.java:194)
    	at app//reactor.netty.resources.DefaultPooledConnectionProvider$DisposableAcquire.onError(DefaultPooledConnectionProvider.java:155)
    	at app//reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onError(FluxContextWrite.java:121)
    	at app//reactor.netty.internal.shaded.reactor.pool.AbstractPool$Borrower.fail(AbstractPool.java:477)
    	at app//reactor.netty.internal.shaded.reactor.pool.SimpleDequePool.lambda$drainLoop$9(SimpleDequePool.java:431)
    	at app//reactor.core.publisher.FluxDoOnEach$DoOnEachSubscriber.onError(FluxDoOnEach.java:186)
    	at app//reactor.core.publisher.MonoCreate$DefaultMonoSink.error(MonoCreate.java:194)
    	at app//reactor.netty.resources.DefaultPooledConnectionProvider$PooledConnectionAllocator$PooledConnectionInitializer.onError(DefaultPooledConnectionProvider.java:538)
    	at app//reactor.core.publisher.MonoFlatMap$FlatMapMain.secondError(MonoFlatMap.java:192)
    	at app//reactor.core.publisher.MonoFlatMap$FlatMapInner.onError(MonoFlatMap.java:259)
    	at app//reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:106)
    	at app//reactor.core.publisher.Operators.error(Operators.java:198)
    	at app//reactor.core.publisher.MonoError.subscribe(MonoError.java:53)
    	at app//reactor.core.publisher.Mono.subscribe(Mono.java:4400)
    	at app//reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:103)
    	at app//reactor.netty.transport.TransportConnector$MonoChannelPromise.tryFailure(TransportConnector.java:534)
    	at app//reactor.netty.transport.TransportConnector$MonoChannelPromise.setFailure(TransportConnector.java:488)
    	at app//reactor.netty.transport.TransportConnector.lambda$doConnect$7(TransportConnector.java:223)
    	at app//io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:578)
    	at app//io.netty.util.concurrent.DefaultPromise.notifyListeners0(DefaultPromise.java:571)
    	at app//io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:550)
    	at app//io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:491)
    	at app//io.netty.util.concurrent.DefaultPromise.setValue0(DefaultPromise.java:616)
    	at app//io.netty.util.concurrent.DefaultPromise.setFailure0(DefaultPromise.java:609)
    	at app//io.netty.util.concurrent.DefaultPromise.tryFailure(DefaultPromise.java:117)
    	at app//io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.fulfillConnectPromise(AbstractNioChannel.java:321)
    	at app//io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.finishConnect(AbstractNioChannel.java:337)
    	at app//io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:710)
    	at app//io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:658)
    	at app//io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:584)
    	at app//io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:496)
    	at app//io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986)
    	at app//io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
    	at app//io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    	at [email protected]/java.lang.Thread.run(Thread.java:833)
    	Suppressed: java.lang.Exception: #block terminated with an error
    		at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:139)
    		at reactor.core.publisher.Mono.block(Mono.java:1731)
    		at org.springframework.test.web.reactive.server.DefaultWebTestClient$DefaultRequestBodyUriSpec.exchange(DefaultWebTestClient.java:361)
    		at com.optivem.kata.banking.system.BankAccountControllerSystemTest.getToken(BankAccountControllerSystemTest.java:52)
    		at com.optivem.kata.banking.system.BankAccountControllerSystemTest.should_open_account_given_valid_request(BankAccountControllerSystemTest.java:67)
    		at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    		at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    		at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    		at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    		at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
    		at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
    		at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
    		at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
    		at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
    		at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
    		at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
    		at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
    		at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
    		at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
    		at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
    		at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
    		at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
    		at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
    		at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
    		at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    		at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
    		at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
    		at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
    		at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
    		at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    		at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
    		at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    		at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
    		at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    		at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
    		at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
    		at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
    		at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
    		at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
    		at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    		at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
    		at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    		at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
    		at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    		at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
    		at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
    		at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
    		at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
    		at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
    		at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    		at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
    		at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    		at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
    		at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    		at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
    		at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
    		at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
    		at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
    		at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
    		at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
    		at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
    		at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
    		at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
    		at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
    		at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
    		at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
    		at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
    		at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
    		at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:99)
    		at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:79)
    		at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:75)
    		at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
    		at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    		at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    		at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    		at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    		at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
    		at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    		at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
    		at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
    		at jdk.proxy2/jdk.proxy2.$Proxy5.stop(Unknown Source)
    		at org.gradle.api.internal.tasks.testing.worker.TestWorker$3.run(TestWorker.java:193)
    		at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:129)
    		at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:100)
    		at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:60)
    		at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
    		at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:133)
    		at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:71)
    		at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
    		at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
    Caused by: io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information: localhost/127.0.0.1:10000
    Caused by: java.net.ConnectException: Connection refused: no further information
    	at java.base/sun.nio.ch.Net.pollConnect(Native Method)
    	at java.base/sun.nio.ch.Net.pollConnectNow(Net.java:672)
    	at java.base/sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:946)
    	at io.netty.channel.socket.nio.NioSocketChannel.doFinishConnect(NioSocketChannel.java:330)
    	at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.finishConnect(AbstractNioChannel.java:334)
    	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:710)
    	at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:658)
    	at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:584)
    	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:496)
    	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986)
    	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
    	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    	at java.base/java.lang.Thread.run(Thread.java:833)
    

    Similar failure currently occurs on GitHub Actions too https://github.com/valentinacupac/banking-kata-java/actions/runs/3788816924/jobs/6441972612

    BankAccountControllerSystemTest > should_open_account_given_valid_request() FAILED
        org.springframework.web.reactive.function.client.WebClientRequestException at ExchangeFunctions.java:1[41](https://github.com/valentinacupac/banking-kata-java/actions/runs/3788816924/jobs/6441972612#step:8:42)
            Caused by: io.netty.channel.AbstractChannel$AnnotatedConnectException
                Caused by: java.net.ConnectException at Errors.java:155
    2022-12-27 16:54:10.0[47](https://github.com/valentinacupac/banking-kata-java/actions/runs/3788816924/jobs/6441972612#step:8:48)  INFO 3365 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
    2022-12-27 16:54:10.0[49](https://github.com/valentinacupac/banking-kata-java/actions/runs/3788816924/jobs/6441972612#step:8:50)  INFO 3365 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
    2022-12-27 16:54:10.0[53](https://github.com/valentinacupac/banking-kata-java/actions/runs/3788816924/jobs/6441972612#step:8:54)  INFO 3365 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.
    
    108 tests completed, 1 failed
    2022-12-27 16:[54](https://github.com/valentinacupac/banking-kata-java/actions/runs/3788816924/jobs/6441972612#step:8:55):10.070  INFO 3365 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
    2022-12-27 16:54:10.071  INFO 3365 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-2 - Shutdown initiated...
    2022-12-27 16:54:10.073  INFO 3365 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-2 - Shutdown completed.
    2022-12-27 16:54:10.081  INFO 3365 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
    2022-12-27 16:54:10.081  INFO 3365 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-3 - Shutdown initiated...
    2022-12-27 16:54:10.085  INFO 3365 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-3 - Shutdown completed.
    

    HOTFIX

    I have temporarily commented out the security-related code (see commit https://github.com/valentinacupac/banking-kata-java/commit/ef5ba9cf21d9a00289747a16bf839dfa00fde942) because BankAccountControllerSystemTest.should_open_account_given_valid_request was failing both locally & on GitHub Actions. That code could be brought back later, after we find out how to fix this issue to make the test pass.

    bug 
    opened by valentinacupac 2
  • #33 OpenAccountUseCase - Publishing events

    #33 OpenAccountUseCase - Publishing events

    Hi Valentina, I am highly inspired by the clean code architecture and a continuous learner from your great talk. While exploring and learning the architecture, I dare to attempt to develop some piece of code on #33 OpenAccountUseCase - Publishing events. In my test and understanding, it is working. I would feel myself happy if you kindly review and see if it can be merged or any rework needed.

    Thanks Valentina.

    opened by eamtalu 2
  • introduce spock tests

    introduce spock tests

    Hi Valentina I found your presentation very informative and had some interesting insights. I had heard of Hexagonal Architecture but I had never really tried it out. I will definitely try this approach on my next project.

    I usually use Spock for my test because I love how expressive it is. I have added a sample test to your code. Please let me know what you think.

    Here is a TDD Kata that I did years ago - I use Spock for my test cases.

    I love the passion you display for clean and concise code, I think we share that passion. I will definitely keep supporting you to spread to word.

    Kind Regards

    Donald

    opened by donaldsiziba 2
  • Docker compose - Databases not automatically created (Workaround)

    Docker compose - Databases not automatically created (Workaround)

    This is a local issue that appeared on some local machines, pending to find full solution.

    When you run:

    ./gradlew integrationTest
    

    You see the following error:

    > Task :integrationTest
    
    BankingApplicationTests > contextLoads() FAILED
        java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:132
            Caused by: org.springframework.beans.factory.BeanCreationException at AbstractAutowireCapableBeanFactory.java:1804
                Caused by: javax.persistence.PersistenceException at AbstractEntityManagerFactoryBean.java:421
                    Caused by: org.hibernate.exception.GenericJDBCException at StandardSQLExceptionConverter.java:42
                        Caused by: org.postgresql.util.PSQLException at QueryExecutorImpl.java:2675
    
    JpaBankAccountStorageTest > should_return_empty_given_non_existent_account_number() FAILED
        org.junit.jupiter.api.extension.ParameterResolutionException at ExecutableInvoker.java:239
            Caused by: java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:132
                Caused by: org.springframework.beans.factory.BeanCreationException at AbstractAutowireCapableBeanFactory.java:1804
                    Caused by: javax.persistence.PersistenceException at AbstractEntityManagerFactoryBean.java:421
                        Caused by: org.hibernate.exception.GenericJDBCException at StandardSQLExceptionConverter.java:42
                            Caused by: org.postgresql.util.PSQLException at QueryExecutorImpl.java:2675
    
    JpaBankAccountStorageTest > should_return_added_bank_account() FAILED
        org.junit.jupiter.api.extension.ParameterResolutionException at ExecutableInvoker.java:239
            Caused by: java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:132
                Caused by: org.springframework.beans.factory.BeanCreationException at AbstractAutowireCapableBeanFactory.java:1804
                    Caused by: javax.persistence.PersistenceException at AbstractEntityManagerFactoryBean.java:421
                        Caused by: org.hibernate.exception.GenericJDBCException at StandardSQLExceptionConverter.java:42
                            Caused by: org.postgresql.util.PSQLException at QueryExecutorImpl.java:2675
    
    JpaBankAccountStorageTest > should_find_multiple_added_bank_accounts() FAILED
        org.junit.jupiter.api.extension.ParameterResolutionException at ExecutableInvoker.java:239
            Caused by: java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:132
                Caused by: org.springframework.beans.factory.BeanCreationException at AbstractAutowireCapableBeanFactory.java:1804
                    Caused by: javax.persistence.PersistenceException at AbstractEntityManagerFactoryBean.java:421
                        Caused by: org.hibernate.exception.GenericJDBCException at StandardSQLExceptionConverter.java:42
                            Caused by: org.postgresql.util.PSQLException at QueryExecutorImpl.java:2675
    
    BankAccountControllerSystemTest > should_open_account_given_valid_request() FAILED
        org.junit.jupiter.api.extension.ParameterResolutionException at ExecutableInvoker.java:239
            Caused by: java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:132
                Caused by: org.springframework.beans.factory.BeanCreationException at AbstractAutowireCapableBeanFactory.java:1804
                    Caused by: javax.persistence.PersistenceException at AbstractEntityManagerFactoryBean.java:421
                        Caused by: org.hibernate.exception.GenericJDBCException at StandardSQLExceptionConverter.java:42
                            Caused by: org.postgresql.util.PSQLException at QueryExecutorImpl.java:2675
    
    22 tests completed, 5 failed
    
    > Task :integrationTest FAILED
    
    FAILURE: Build failed with an exception.
    
    * What went wrong:
    Execution failed for task ':integrationTest'.
    > There were failing tests. See the report at: file:///C:/Users/valen/GitHub/valentinacupac/banking-kata-java/build/reports/tests/integrationTest/index.html
    
    * Try:
    > Run with --stacktrace option to get the stack trace.
    > Run with --info or --debug option to get more log output.
    > Run with --scan to get full insights.
    
    * Get more help at https://help.gradle.org
    
    BUILD FAILED in 23s
    8 actionable tasks: 8 executed
    

    You open up the detailed file (e.g. file:///C:/Users/valen/GitHub/valentinacupac/banking-kata-java/build/reports/tests/integrationTest/index.html above). You open up the error log for BankingApplicationTests. contextLoads()

    As you scroll to the bottom, you see the underlying cause is FATAL: database "banking_kata_db" does not exist:

    java.lang.IllegalStateException: Failed to load ApplicationContext
    	at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:132)
    	at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:124)
    	at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:190)
        ...
    Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.exception.GenericJDBCException: Unable to open JDBC Connection for DDL execution
    	at app//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1804)
    	at app//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:620)
    	at app//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
        ...
    Caused by: javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.exception.GenericJDBCException: Unable to open JDBC Connection for DDL execution
    	at app//org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:421)
    	at app//org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:396)
    	at app//org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:341)
        ...
    Caused by: org.hibernate.exception.GenericJDBCException: Unable to open JDBC Connection for DDL execution
    	at app//org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
    	at app//org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113)
    	at app//org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:99)
        ...
    Caused by: org.postgresql.util.PSQLException: FATAL: database "banking_kata_db" does not exist
    	at app//org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2675)
    	at app//org.postgresql.core.v3.QueryExecutorImpl.readStartupMessages(QueryExecutorImpl.java:2787)
    	at app//org.postgresql.core.v3.QueryExecutorImpl.<init>(QueryExecutorImpl.java:173)
        ...
    

    Root Cause

    The root cause is that for some reason, on some local machines, the docker-entrypoint-initdb.d seems not to be executed in docker.compose.yaml This issue was only noted on some local machines, but on GitHub Actions everything works well.

    Workaround:

    Open up Docker Desktop, go into the Docker container postgres and open up its CLI.

    Then input the following:

    psql -U postgres;
    \l
    CREATE DATABASE banking_kata_db OWNER postgres;
    CREATE DATABASE keycloak_db OWNER postgres;
    \l
    

    Then re-run the integration tests and verify they pass:

    ./gradlew integrationTest
    

    If you experienced the issue we described in this ticket, please comment below. If you tried the workaround, please let us know whether or not it worked for you. If you tried and found any other solutions, please comment too.

    bug wontfix 
    opened by valentinacupac 1
  • Database tests failing on GitHub Actions

    Database tests failing on GitHub Actions

    DB tests are passing locally, but failing on GitHub Actions after changes in https://github.com/valentinacupac/banking-kata-java/commit/a69b455162fef3ee25ffe3b31e76f8a58db4b31a

    GitHub Actions log https://github.com/valentinacupac/banking-kata-java/actions/runs/3788279403/jobs/6440898243#step:8:86

    `BankingApplicationTests > contextLoads() FAILED java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:132 Caused by: java.lang.IllegalStateException at SpringBootCondition.java:60 Caused by: java.lang.IllegalArgumentException at PropertyPlaceholderHelper.java:180

    JpaBankAccountStorageTest > should_return_empty_given_non_existent_account_number() FAILED org.junit.jupiter.api.extension.ParameterResolutionException at ExecutableInvoker.java:239 Caused by: java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:132 Caused by: java.lang.IllegalStateException at SpringBootCondition.java:60 Caused by: java.lang.IllegalArgumentException at PropertyPlaceholderHelper.java:180

    JpaBankAccountStorageTest > should_return_added_bank_account() FAILED org.junit.jupiter.api.extension.ParameterResolutionException at ExecutableInvoker.java:239 Caused by: java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:132 Caused by: java.lang.IllegalStateException at SpringBootCondition.java:60 Caused by: java.lang.IllegalArgumentException at PropertyPlaceholderHelper.java:180

    JpaBankAccountStorageTest > should_find_multiple_added_bank_accounts() FAILED org.junit.jupiter.api.extension.ParameterResolutionException at ExecutableInvoker.java:239 Caused by: java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:132 Caused by: java.lang.IllegalStateException at SpringBootCondition.java:60 Caused by: java.lang.IllegalArgumentException at PropertyPlaceholderHelper.java:180

    BankAccountControllerSystemTest > should_open_account_given_valid_request() FAILED org.junit.jupiter.api.extension.ParameterResolutionException at ExecutableInvoker.java:239 Caused by: java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:132 Caused by: java.lang.IllegalStateException at SpringBootCondition.java:60 Caused by: java.lang.IllegalArgumentException at PropertyPlaceholderHelper.java:180

    108 tests completed, 5 failed`

    Pending to see if this is caused due to Postgres password change? Aside from that, there weren't any other changes related to Postgres.

    Locally, the tests pass (when Postgres environment variables are configured), the issue started appearing on GitHub Actions only.

    bug 
    opened by valentinacupac 1
  • #37 REST API - Add Keycloak authentication

    #37 REST API - Add Keycloak authentication

    Changes:

    • Configure Spring Security to use Keycloak as authorization server.
    • Modify docker-compose to use jboss Keycloak and adminer (for visualize database tables) images.
    • Modify application.yml and application-test.yml to use new env vars.
    • Modify BankAccountControllerSystemTest to use new Keycloak authentication.
    opened by adrianliz 1
  • #34 BankAccountRepository - MongoDB

    #34 BankAccountRepository - MongoDB

    Hi Valentina,

    Hope you are well. Based on your last meetup talk, I have been able to understand the persistence and further worked a little bit on the following for this issue - #34 BankAccountRepository - MongoDB. This is so interesting to me. I have been able to grab a good understanding on mongodb(document) and its spring repository(mongo template).

    I hope this seems okay. But May I request you to have a look and see if it is the right way to do it. I have done the following in this PR:

    1. Added Gradle dependency for mongo template
    2. Added mongodb and mongodb-express(mongodb admin tool) in the docker-compose while I was working, tested okay.
    3. Updated ci.yaml file for mongo-db(you may discard it, if it is not needed). I was not able to test it.
    4. Updated application.yml file with mongo environment variable.
    5. Under infra--Persistence: Added class - BankAccountDocument (naming convention could be wrong, but I found it relevant as mongo consider document only where string,localdate are the datatype. I understood string seems to be the only datatype. although there are few but string seems to me the dominant.
    6. Added two repository class: one is custom using mongotemplate and alternatively other one is mongorepository. MongoTemplate seems provide better control as per my understanding.
    7. Added implementation class of - MongoBankAccountStorage.

    Note: Since there are two implementation of BankAccountStorage, therefore two beans for it. I believe there could be toggle in application.yml. For the time being to compile okay, I just made your jpabankaccountstorage as @primary bean.

    So, these are above I have done, for your kind review. I apologise if any mistake and would appreciate your kind advice for rework and further enhancement.

    Many Thanks, Amin

    opened by eamtalu 1
  • Use of Transaction

    Use of Transaction

    Discussed in https://github.com/valentinacupac/banking-kata-java/discussions/54

    Originally posted by ldauvilaire August 23, 2022 Storage (i.e. Database) transactions have to be managed or else data integrity can be broken in case of access in parallel.

    The use cases : DepositFundsUseCase and WithdrawFundsUseCase shall use only one transaction (read and update done into the same transaction). The current code is using 2 (implicit) transactions, one for reading (repository.findRequired(accountNumber)) and another one for updating (repository.update(bankAccount)), this would not work in a "real" bank.

    Of course the @Transactional shall not be implemented into the domain but into driven port(s). May be a "TransfertFund" from one account to another would help to show the problem in evidence.

    enhancement 
    opened by valentinacupac 1
  • Modularization - JVM Test Suite - Separate Test Execution

    Modularization - JVM Test Suite - Separate Test Execution

    • [x] Separation of execution of unit tests versus integration tests
    • [ ] Only integration tests should require DB installation, environment variables, etc...
    • [ ] Docker compose needed only for integration tests
    • [ ] Perhaps also separate the system/e2e tests?
    • [x] Shared test fixtures
    enhancement 
    opened by valentinacupac 0
  • Communication - Synchronous communication with external services

    Communication - Synchronous communication with external services

    A reality we can often observe in real world applications, and even more so in microservices architectures, is communication with multiple services in order to achieve a task. For example, in case of opening a new account, checking that a person exists and is registered in the country.

    It would be useful to add an example of communication with a fictional external system to demonstrate the implementation with hexagonal architecture (hint: basically a repository).

    opened by TristanoSuriani 3
  • Adding BDD test with cucumber to demonstrate different way to use in OutsideIn TDD

    Adding BDD test with cucumber to demonstrate different way to use in OutsideIn TDD

    The idea it's to add Cucumber to demonstrate OutsideIn TDD way. It would most probably showed in the 23 Nov 2022 meetup.

    Job to be done :

    • describe the kata with *.feature
    • implements different approach from: the present view, port and use case
    opened by cuvaalex 1
  • Modularization - Restrict imports in gradle to a specific package to ensure hexagonal architecture boundaries

    Modularization - Restrict imports in gradle to a specific package to ensure hexagonal architecture boundaries

    Hello,

    Last weekend I tried to add on the project a plugin in order to banned some imports according to some packages. This can be very useful to check at the build step if we violated boundaries of the hexagonal architecture. For example thanks to this plugin, I can ensure that we can't have imports from infrastructure in domain package.

    On top of that, if it's the case, we can add some exclusions to make explicit the todo list of what should be shift and ensure that no new banned imports will be added.

    Maven Plugin:

    • url : https://github.com/skuzzle/restrict-imports-enforcer-rule
    • description : Maven enforcer rule that bans certain imports. Keep your code base clean and free from usage of unwanted classes

    Little problem, when I opened the banking-cata-java project, I was surprised because it is not a maven project but a gradle project. And for gradle I don't know how I can use this useful plugin.

    • I tried to call maven plugin in gradle but this seems to be weird.
    • According to this https://kordamp.org/enforcer-gradle-plugin/#_excludedependencies and this https://github.com/kordamp/enforcer-gradle-plugin, I tried to add a root configuration in settings.gradle but I don't know how I can exclude dependencies for a specific package (may be if you know some groovy tips) and I tried to add several build.gradle project to have specific configuration according to those sub packages but it's not working like this, indeed, a sub gradle project it's like a module maven and we can't apply this to only separate packages (because domain and infra are in the same project).

    So if you have an idea on how we can have a similar check by using gradle I will be happy to talk with you :)

    see below a maven sample to exclude infra imports in domain package :

    					<execution>
    						<id>check-imports</id>
    						<phase>process-sources</phase>
    						<goals>
    							<goal>enforce</goal>
    						</goals>
    						<configuration>
    							<rules>
    								<RestrictImports>
    									<groups>
    										<group>
    											<reason>Forbid to depend to infrastructure/application (adapters primary/secondary) or external lib in domain</reason>
    											<basePackages>
    												<basePackage>com.example.demo.domain.**</basePackage>
    											</basePackages>
    											<bannedImports>
    												<bannedImport>com.example.demo.adapters.primaries.**</bannedImport>
    												<bannedImport>com.example.demo.adapters.secondaries.**</bannedImport>
    												<bannedImport>com.fasterxml.jackson.**</bannedImport>
    												<bannedImport>org.springframework.**</bannedImport>
    												<bannedImport>io.swagger.**</bannedImport>
    												<bannedImport>lombok.**</bannedImport>
    											</bannedImports>
    											<exclusions>
    											</exclusions>
    										</group>
                                                                                        <group>
                                                                                          <reason>Forbid to depend to infrastructure (secondary) in application (primary)</reason>
                                                                                          <basePackages>
                                                                                            <basePackage>com.example.demo.adapters.primaries.**</basePackage>
                                                                                          </basePackages>
                                                                                          <bannedImports>
                                                                                            <bannedImport>com.example.demo.adapters.secondaries.**</bannedImport>
                                                                                          </bannedImports>
                                                                                          <exclusions>
                                                                                          </exclusions>
                                                                                        </group>
                                                                                        <group>
                                                                                          <reason>Limit dependency of demo to the other domains (useful in case of modular monolith)</reason>
                                                                                          <basePackages>
                                                                                            <basePackage>com.example.demo.**</basePackage>
                                                                                          </basePackages>
                                                                                          <bannedImports>
                                                                                            <bannedImport>com.example.business.**</bannedImport>
                                                                                          </bannedImports>
                                                                                        </group>
    									</groups>
    								</RestrictImports>
    
    								<!-- You could have another rule instance here for restricting further imports -->
    							</rules>
    						</configuration>
    					</execution> 
    
    opened by nicolasrosado 2
Owner
Valentina Cupać
Founder & Technical Coach @ Optivem
Valentina Cupać
Entornos de Desarrollo - 05 Clean Code y TDD: Pruebas de Software. 1DAM. Curso 2021-2022.

Entornos de Desarrollo - 04 Clean Code y TDD: Pruebas de Software Tema 05. Clean Code y TDD: Pruebas de Software. Curso 2021/2022. Contenidos Introduc

José Luis González Sánchez 19 Nov 3, 2022
A React Native project starter with Typescript, a theme provider with hook to easy styling component, a folder architecture ready and some configs to keep a codebase clean.

React Native Boilerplate Folder structure : src ├── assets │   ├── audios │   ├── fonts │   ├── icons │   └── images ├── components │   ├── Layout.tsx

LazyRabbit 23 Sep 1, 2022
参考 DDD/Clean Architecture 设计理念,整合 Spring Boot/Spring Security/Mybatis Plus/Vavr 的 Spring Realworld 应用案例

Demo · 更多项目 · 参考资料 ms-spring-ddd-examples Unified Domain-driven Layered Architecture for MicroService Apps,试图探索一套切实可行的应用架构规范,可以复制、可以理解、可以落地、可以控制复杂性的指导

王下邀月熊 19 Sep 23, 2022
Spring Boot Clean Architecture - Iran Plate

Spring Boot Clean Architecture Sample Iran Plate Location Finder I used the Clean Architecture in my project. In this method we can develop our projec

Mahdi Amirabdolahi 4 Jul 6, 2022
An example to show how you could use clean architecture and DDD elements with Camunda.

Camunda DDD and Clean Architecture An example to show how you could use clean architecture and DDD and their advantages with Camunda. I also wrote a b

Luc Weinbrecht 10 Dec 15, 2022
Projeto java + spring + maven +TDD

Java - Spring Framework Sistema simples para geração de mensagens. ciclo do TDD (escreva um teste que falha, faça o teste passar e refatore); versiona

null 1 Apr 2, 2022
Projeto Java com Spring Boot + TDD + Mockbean

TDD TDD (Test Driven Development ou Desenvolvimento Movido a Testes) é bem como seu nome diz: uma prática de desenvolvimento de software orientada a t

Ariane Rocha 1 Feb 3, 2022
N-Layer Architecture human resource management system project with Java.

HRMS Project Backend N-Layer Architecture human resource management system project with Java. Report Bug · Request Feature About The Project Built Wit

Ahmet Çetinkaya 78 Dec 26, 2022
Hexagonal Architecture Demo Project about Ticketing and Payment

This project is a sample production-ready implementation for demonstrating the power of Hexagonal Architecture (aka Ports And Adapters Pattern) written in Java.

Alican Akkuş 382 Jan 1, 2023
This project was created as a simple example to show how we can implement the hexagonal architecture(software design) proposed by Netflix.

Netflix Hexagonal Architecture Table of contents About the project Description Built with Installation Requirements to run Usage information Run Licen

José Lucas 12 Dec 20, 2022
Restaurant Management Project with Microservice Architecture by Evren Tan

Restaurant Management Restaurant Management Project with Microservice Architecture is developed by Evren Tan. Table of Contents Modules Cloud Config S

Evren Tan 26 Dec 11, 2022
Buildable src reconstructed from the clean Phobos 1.9.0 jar

CLEAN_Phobos_1.9.0-BUILDABLE-SRC Buildable src reconstructed from the clean Phobos 1.9.0 jar. Full buildable and functional, jar in releases is built

null 62 Dec 28, 2022
Phobos 1.9.0 Clean Buildable SRC.

[CLEAN] Phobos 1.9.0 Buildable SRC & Release This source has been checked by two people, myself and a friend. My friend did not find anything as he br

Hqrion 58 Dec 17, 2022
Practice and testing with Java 11, Prometheus, and Spring-boot with MicroService Architecture. Designed to run on Kubernetes in minikube.

This application was written by Andrew Aslakson Built to run on minikube using kubernetes General race tracking system? Secure with Firebase Authentic

null 1 Feb 5, 2022
An assistance platform made using Spring framework that analyses your code, and helps you either to start a devops project, or to turn an existing project into a devops project using open source software (Git, Docker, Jenkins..)

DevOpsify Description An assistance platform made using Spring framework that analyses your code, and helps you either to start a devops project, or t

obaydah bouifadene 14 Nov 8, 2022
E-Commerce System Simulation with layered architecture

ECommermeSimulation E-Commerce System Simulation with layered architecture Users can become a member of the system by entering their information. User

Esranur Türkmen 5 Jul 16, 2021
Microservice Architecture with Spring Boot, Spring Cloud and Docker

Piggy Metrics Piggy Metrics is a simple financial advisor app built to demonstrate the Microservice Architecture Pattern using Spring Boot, Spring Clo

Alexander Lukyanchikov 12.1k Jan 1, 2023
Demo microservice architecture with Spring ,Spring Cloud Gateway , Spring Cloud config server , Eureuka , keycloak and Docker.

spring-microservice Demo microservice architecture with Spring ,Spring Cloud Gateway , Spring Cloud config server , Eureuka , keycloak and Docker. Arc

null 4 Sep 13, 2022
An estate management api based on the hexagonal architecture, built on top of Quarkus

An estate management api based on the hexagonal architecture, built on top of Quarkus

Mudi Lukman 2 Mar 30, 2022