From d97506a686e30ecc80497605e62bb4f7644515ef Mon Sep 17 00:00:00 2001 From: tmorin Date: Fri, 15 Mar 2024 20:36:04 +0100 Subject: [PATCH 1/4] chore: upgrade dependencies --- .idea/.gitignore | 3 +- .mvn/wrapper/maven-wrapper.properties | 8 +- core-api/pom.xml | 1 + core-scenario/pom.xml | 1 + core-simple/pom.xml | 1 + examples/pom.xml | 1 + examples/todo-core/pom.xml | 3 +- examples/todo-infra-quarkus/pom.xml | 59 ++++--- examples/tutorial/pom.xml | 5 +- mvnw | 218 +++++++++++++------------- mvnw.cmd | 31 +++- pom.xml | 14 +- spi-api/pom.xml | 1 + spi-simple/pom.xml | 1 + 14 files changed, 180 insertions(+), 167 deletions(-) diff --git a/.idea/.gitignore b/.idea/.gitignore index ff67481..0e40d12 100644 --- a/.idea/.gitignore +++ b/.idea/.gitignore @@ -1,2 +1,3 @@ * -!prettier.xml \ No newline at end of file +!prettier.xml# GitHub Copilot persisted chat sessions +/copilot/chatSessions diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index 4f3b9f5..346d645 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -5,14 +5,14 @@ # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at -# +# # http://www.apache.org/licenses/LICENSE-2.0 -# +# # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.2/apache-maven-3.8.2-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.6/apache-maven-3.9.6-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/core-api/pom.xml b/core-api/pom.xml index 72baad0..62fc5a0 100644 --- a/core-api/pom.xml +++ b/core-api/pom.xml @@ -4,6 +4,7 @@ faggregate io.morin.faggregate 1.6.0-SNAPSHOT + ../pom.xml 4.0.0 diff --git a/core-scenario/pom.xml b/core-scenario/pom.xml index 59f6f1e..92cbffa 100644 --- a/core-scenario/pom.xml +++ b/core-scenario/pom.xml @@ -4,6 +4,7 @@ faggregate io.morin.faggregate 1.6.0-SNAPSHOT + ../pom.xml 4.0.0 diff --git a/core-simple/pom.xml b/core-simple/pom.xml index 2538448..7445ed1 100644 --- a/core-simple/pom.xml +++ b/core-simple/pom.xml @@ -4,6 +4,7 @@ faggregate io.morin.faggregate 1.6.0-SNAPSHOT + ../pom.xml 4.0.0 diff --git a/examples/pom.xml b/examples/pom.xml index e9c213c..d846565 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -4,6 +4,7 @@ faggregate io.morin.faggregate 1.6.0-SNAPSHOT + ../pom.xml 4.0.0 diff --git a/examples/todo-core/pom.xml b/examples/todo-core/pom.xml index 67c9251..24d347e 100644 --- a/examples/todo-core/pom.xml +++ b/examples/todo-core/pom.xml @@ -4,6 +4,7 @@ faggregate-examples io.morin.faggregate.examples 1.6.0-SNAPSHOT + ../pom.xml 4.0.0 @@ -52,7 +53,7 @@ com.fasterxml.jackson.core jackson-databind - 2.16.1 + 2.17.0 jakarta.enterprise diff --git a/examples/todo-infra-quarkus/pom.xml b/examples/todo-infra-quarkus/pom.xml index 64b02fc..abca1d8 100644 --- a/examples/todo-infra-quarkus/pom.xml +++ b/examples/todo-infra-quarkus/pom.xml @@ -1,26 +1,27 @@ - 4.0.0 io.morin.faggregate.examples faggregate-examples 1.6.0-SNAPSHOT + ../pom.xml + 4.0.0 examples-todo-infra-quarkus A simple implementation of the faggregate-examples-todo-model module. - 3.8.1 - false - 11 + 3.12.1 + 17 UTF-8 UTF-8 quarkus-bom io.quarkus.platform - 3.0.4.Final - 3.0.0-M5 + 3.8.2 + true + 3.2.5 @@ -114,6 +115,25 @@ + + maven-failsafe-plugin + ${surefire-plugin.version} + + + + integration-test + verify + + + + + + ${project.build.directory}/${project.build.finalName}-runner + org.jboss.logmanager.LogManager + ${maven.home} + + + @@ -125,33 +145,8 @@ native - - - - maven-failsafe-plugin - ${surefire-plugin.version} - - - - integration-test - verify - - - - - ${project.build.directory}/${project.build.finalName}-runner - - org.jboss.logmanager.LogManager - - ${maven.home} - - - - - - - + false native diff --git a/examples/tutorial/pom.xml b/examples/tutorial/pom.xml index 7ca8873..600c528 100644 --- a/examples/tutorial/pom.xml +++ b/examples/tutorial/pom.xml @@ -5,6 +5,7 @@ io.morin.faggregate.examples faggregate-examples 1.6.0-SNAPSHOT + ../pom.xml io.morin.faggregate examples-tutorial @@ -15,12 +16,12 @@ org.asciidoctor asciidoctor-maven-plugin - 2.2.2 + 2.2.4 org.asciidoctor asciidoctorj-diagram - 2.2.7 + 2.3.0 diff --git a/mvnw b/mvnw index 5643201..8d937f4 100755 --- a/mvnw +++ b/mvnw @@ -19,7 +19,7 @@ # ---------------------------------------------------------------------------- # ---------------------------------------------------------------------------- -# Maven Start Up Batch script +# Apache Maven Wrapper startup batch script, version 3.2.0 # # Required ENV vars: # ------------------ @@ -27,7 +27,6 @@ # # Optional ENV vars # ----------------- -# M2_HOME - location of maven2's installed home dir # MAVEN_OPTS - parameters passed to the Java VM when running Maven # e.g. to debug Maven itself, use # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 @@ -54,7 +53,7 @@ fi cygwin=false; darwin=false; mingw=false -case "`uname`" in +case "$(uname)" in CYGWIN*) cygwin=true ;; MINGW*) mingw=true;; Darwin*) darwin=true @@ -62,9 +61,9 @@ case "`uname`" in # See https://developer.apple.com/library/mac/qa/qa1170/_index.html if [ -z "$JAVA_HOME" ]; then if [ -x "/usr/libexec/java_home" ]; then - export JAVA_HOME="`/usr/libexec/java_home`" + JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME else - export JAVA_HOME="/Library/Java/Home" + JAVA_HOME="/Library/Java/Home"; export JAVA_HOME fi fi ;; @@ -72,68 +71,38 @@ esac if [ -z "$JAVA_HOME" ] ; then if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=`java-config --jre-home` + JAVA_HOME=$(java-config --jre-home) fi fi -if [ -z "$M2_HOME" ] ; then - ## resolve links - $0 may be a link to maven's home - PRG="$0" - - # need this for relative symlinks - while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi - done - - saveddir=`pwd` - - M2_HOME=`dirname "$PRG"`/.. - - # make it fully qualified - M2_HOME=`cd "$M2_HOME" && pwd` - - cd "$saveddir" - # echo Using m2 at $M2_HOME -fi - # For Cygwin, ensure paths are in UNIX format before anything is touched if $cygwin ; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --unix "$M2_HOME"` [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + JAVA_HOME=$(cygpath --unix "$JAVA_HOME") [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --unix "$CLASSPATH"` + CLASSPATH=$(cygpath --path --unix "$CLASSPATH") fi # For Mingw, ensure paths are in UNIX format before anything is touched if $mingw ; then - [ -n "$M2_HOME" ] && - M2_HOME="`(cd "$M2_HOME"; pwd)`" - [ -n "$JAVA_HOME" ] && - JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] && + JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)" fi if [ -z "$JAVA_HOME" ]; then - javaExecutable="`which javac`" - if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + javaExecutable="$(which javac)" + if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then # readlink(1) is not available as standard on Solaris 10. - readLink=`which readlink` - if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + readLink=$(which readlink) + if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then if $darwin ; then - javaHome="`dirname \"$javaExecutable\"`" - javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + javaHome="$(dirname "\"$javaExecutable\"")" + javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac" else - javaExecutable="`readlink -f \"$javaExecutable\"`" + javaExecutable="$(readlink -f "\"$javaExecutable\"")" fi - javaHome="`dirname \"$javaExecutable\"`" - javaHome=`expr "$javaHome" : '\(.*\)/bin'` + javaHome="$(dirname "\"$javaExecutable\"")" + javaHome=$(expr "$javaHome" : '\(.*\)/bin') JAVA_HOME="$javaHome" export JAVA_HOME fi @@ -149,7 +118,7 @@ if [ -z "$JAVACMD" ] ; then JAVACMD="$JAVA_HOME/bin/java" fi else - JAVACMD="`\\unset -f command; \\command -v java`" + JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)" fi fi @@ -163,12 +132,9 @@ if [ -z "$JAVA_HOME" ] ; then echo "Warning: JAVA_HOME environment variable is not set." fi -CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher - # traverses directory structure from process work directory to filesystem root # first directory with .mvn subdirectory is considered project base directory find_maven_basedir() { - if [ -z "$1" ] then echo "Path not specified to find_maven_basedir" @@ -184,96 +150,99 @@ find_maven_basedir() { fi # workaround for JBEAP-8937 (on Solaris 10/Sparc) if [ -d "${wdir}" ]; then - wdir=`cd "$wdir/.."; pwd` + wdir=$(cd "$wdir/.." || exit 1; pwd) fi # end of workaround done - echo "${basedir}" + printf '%s' "$(cd "$basedir" || exit 1; pwd)" } # concatenates all lines of a file concat_lines() { if [ -f "$1" ]; then - echo "$(tr -s '\n' ' ' < "$1")" + # Remove \r in case we run on Windows within Git Bash + # and check out the repository with auto CRLF management + # enabled. Otherwise, we may read lines that are delimited with + # \r\n and produce $'-Xarg\r' rather than -Xarg due to word + # splitting rules. + tr -s '\r\n' ' ' < "$1" + fi +} + +log() { + if [ "$MVNW_VERBOSE" = true ]; then + printf '%s\n' "$1" fi } -BASE_DIR=`find_maven_basedir "$(pwd)"` +BASE_DIR=$(find_maven_basedir "$(dirname "$0")") if [ -z "$BASE_DIR" ]; then exit 1; fi +MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR +log "$MAVEN_PROJECTBASEDIR" + ########################################################################################## # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central # This allows using the maven wrapper in projects that prohibit checking in binary data. ########################################################################################## -if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found .mvn/wrapper/maven-wrapper.jar" - fi +wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" +if [ -r "$wrapperJarPath" ]; then + log "Found $wrapperJarPath" else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." - fi + log "Couldn't find $wrapperJarPath, downloading it ..." + if [ -n "$MVNW_REPOURL" ]; then - jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" else - jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" fi - while IFS="=" read key value; do - case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + while IFS="=" read -r key value; do + # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) + safeValue=$(echo "$value" | tr -d '\r') + case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;; esac - done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" - if [ "$MVNW_VERBOSE" = true ]; then - echo "Downloading from: $jarUrl" - fi - wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" + log "Downloading from: $wrapperUrl" + if $cygwin; then - wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") fi if command -v wget > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found wget ... using wget" - fi + log "Found wget ... using wget" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" else - wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" fi elif command -v curl > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found curl ... using curl" - fi + log "Found curl ... using curl" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - curl -o "$wrapperJarPath" "$jarUrl" -f + curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" else - curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" fi - else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Falling back to using Java to download" - fi - javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + log "Falling back to using Java to download" + javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" + javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" # For Cygwin, switch paths to Windows format before running javac if $cygwin; then - javaClass=`cygpath --path --windows "$javaClass"` + javaSource=$(cygpath --path --windows "$javaSource") + javaClass=$(cygpath --path --windows "$javaClass") fi - if [ -e "$javaClass" ]; then - if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Compiling MavenWrapperDownloader.java ..." - fi - # Compiling the Java class - ("$JAVA_HOME/bin/javac" "$javaClass") + if [ -e "$javaSource" ]; then + if [ ! -e "$javaClass" ]; then + log " - Compiling MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/javac" "$javaSource") fi - if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - # Running the downloader - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Running MavenWrapperDownloader.java ..." - fi - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + if [ -e "$javaClass" ]; then + log " - Running MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" fi fi fi @@ -282,35 +251,58 @@ fi # End of extension ########################################################################################## -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} -if [ "$MVNW_VERBOSE" = true ]; then - echo $MAVEN_PROJECTBASEDIR +# If specified, validate the SHA-256 sum of the Maven wrapper jar file +wrapperSha256Sum="" +while IFS="=" read -r key value; do + case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;; + esac +done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" +if [ -n "$wrapperSha256Sum" ]; then + wrapperSha256Result=false + if command -v sha256sum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + elif command -v shasum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." + echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." + exit 1 + fi + if [ $wrapperSha256Result = false ]; then + echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 + echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 + echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 + exit 1 + fi fi + MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" # For Cygwin, switch paths to Windows format before running java if $cygwin; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --path --windows "$M2_HOME"` [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + CLASSPATH=$(cygpath --path --windows "$CLASSPATH") [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` + MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") fi # Provide a "standardized" way to retrieve the CLI args that will # work with both Windows and non-Windows executions. -MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" export MAVEN_CMD_LINE_ARGS WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain +# shellcheck disable=SC2086 # safe args exec "$JAVACMD" \ $MAVEN_OPTS \ $MAVEN_DEBUG_OPTS \ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" \ "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/mvnw.cmd b/mvnw.cmd index 8a15b7f..c4586b5 100644 --- a/mvnw.cmd +++ b/mvnw.cmd @@ -18,13 +18,12 @@ @REM ---------------------------------------------------------------------------- @REM ---------------------------------------------------------------------------- -@REM Maven Start Up Batch script +@REM Apache Maven Wrapper startup batch script, version 3.2.0 @REM @REM Required ENV vars: @REM JAVA_HOME - location of a JDK home dir @REM @REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven @@ -120,10 +119,10 @@ SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain -set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B ) @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central @@ -134,11 +133,11 @@ if exist %WRAPPER_JAR% ( ) ) else ( if not "%MVNW_REPOURL%" == "" ( - SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" ) if "%MVNW_VERBOSE%" == "true" ( echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %DOWNLOAD_URL% + echo Downloading from: %WRAPPER_URL% ) powershell -Command "&{"^ @@ -146,7 +145,7 @@ if exist %WRAPPER_JAR% ( "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ "}"^ - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ "}" if "%MVNW_VERBOSE%" == "true" ( echo Finished downloading %WRAPPER_JAR% @@ -154,6 +153,24 @@ if exist %WRAPPER_JAR% ( ) @REM End of extension +@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file +SET WRAPPER_SHA_256_SUM="" +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B +) +IF NOT %WRAPPER_SHA_256_SUM%=="" ( + powershell -Command "&{"^ + "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ + "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ + " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ + " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ + " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ + " exit 1;"^ + "}"^ + "}" + if ERRORLEVEL 1 goto error +) + @REM Provide a "standardized" way to retrieve the CLI args that will @REM work with both Windows and non-Windows executions. set MAVEN_CMD_LINE_ARGS=%* diff --git a/pom.xml b/pom.xml index 8a2b21b..06465f0 100644 --- a/pom.xml +++ b/pom.xml @@ -69,12 +69,12 @@ org.apache.maven.plugins maven-surefire-plugin - 3.0.0-M5 + 3.2.3 org.jacoco jacoco-maven-plugin - 0.8.9 + 0.8.10 @@ -93,7 +93,7 @@ org.apache.maven.plugins maven-release-plugin - 3.0.0-M5 + 3.0.1 chore: chore(release): @{releaseLabel} @@ -105,7 +105,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.4.0 + 3.5.0 attach-javadocs @@ -125,20 +125,20 @@ org.projectlombok lombok - 1.18.28 + 1.18.30 provided org.junit.jupiter junit-jupiter - 5.9.3 + 5.10.2 test org.mockito mockito-junit-jupiter - 5.4.0 + 5.11.0 test diff --git a/spi-api/pom.xml b/spi-api/pom.xml index 3b8777a..5a87132 100644 --- a/spi-api/pom.xml +++ b/spi-api/pom.xml @@ -4,6 +4,7 @@ faggregate io.morin.faggregate 1.6.0-SNAPSHOT + ../pom.xml 4.0.0 diff --git a/spi-simple/pom.xml b/spi-simple/pom.xml index 4d3f34c..7187415 100644 --- a/spi-simple/pom.xml +++ b/spi-simple/pom.xml @@ -4,6 +4,7 @@ faggregate io.morin.faggregate 1.6.0-SNAPSHOT + ../pom.xml 4.0.0 From 0ab5703bc3e1b0ee285f6b0a384f7054cf2508bb Mon Sep 17 00:00:00 2001 From: tmorin Date: Sat, 16 Mar 2024 14:42:18 +0100 Subject: [PATCH 2/4] fix(examples-tutorial): remove a wrong statement related to side effect implementation --- examples/tutorial/src/asciidoc/index.adoc | 3 --- 1 file changed, 3 deletions(-) diff --git a/examples/tutorial/src/asciidoc/index.adoc b/examples/tutorial/src/asciidoc/index.adoc index 2b53a21..3bce617 100644 --- a/examples/tutorial/src/asciidoc/index.adoc +++ b/examples/tutorial/src/asciidoc/index.adoc @@ -205,9 +205,6 @@ In `faggregate`, we define those functions as side effects: The side effects are applied according to the intention of the handled command. For instance, the *initializer* is executed when a Command Handler has been registered with the `INITIALIZATION` intention. The details of the intentions are explained in the following sections. -The default implementation of `faggregate`, i.e. `faggregate-core-simple`, provides default implementation throwing an `UnsupportedOperationException`. -Therefore, according to your context, you have to implement and register the side effects. - === The Initializer An initializer is executed when the type of the handled Command has been registered with the `INITIALIZATION` intention. From c80881e0f91ab191ed3f52e0404dda5f4f4b19a6 Mon Sep 17 00:00:00 2001 From: tmorin Date: Sat, 16 Mar 2024 14:45:26 +0100 Subject: [PATCH 3/4] chore: add a link to the validation framework package --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c9da4cc..2bd10a0 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ Therefore, a custom configuration is required to resolve the artifacts, please r io.morin.faggregate faggregate-core-simple - 1.0.0 + VERSION ``` @@ -76,17 +76,19 @@ Therefore, a custom configuration is required to resolve the artifacts, please r io.morin.faggregate faggregate-spi-simple - 1.0.0 + VERSION ``` ### The validation framework +[The GitHub Package](https://github.com/tmorin/faggregate/packages/1842497) + ```xml io.morin.faggregate - faggregate-core-validation - 1.0.0 + faggregate-core-scenario + VERSION ``` From a73c1e7c6a3b428160e268a584ccf568d3042241 Mon Sep 17 00:00:00 2001 From: tmorin Date: Sat, 16 Mar 2024 21:46:37 +0100 Subject: [PATCH 4/4] feat(scenario): simplify scenario implemenation providing an in memory repository and additional helper methods --- .../core/validation/InMemoryRepository.java | 115 ++++++++++++++++ .../core/validation/ScenarioExecutor.java | 11 +- .../faggregate/core/validation/Suite.java | 78 ++++++++++- .../validation/InMemoryRepositoryTest.java | 127 ++++++++++++++++++ .../core/validation/ScenarioExecutorTest.java | 16 +-- .../faggregate/core/validation/SuiteTest.java | 61 ++++++++- .../java/todo/model/mapper/TodoMappers.java | 4 +- 7 files changed, 389 insertions(+), 23 deletions(-) create mode 100644 core-scenario/src/main/java/io/morin/faggregate/core/validation/InMemoryRepository.java create mode 100644 core-scenario/src/test/java/io/morin/faggregate/core/validation/InMemoryRepositoryTest.java diff --git a/core-scenario/src/main/java/io/morin/faggregate/core/validation/InMemoryRepository.java b/core-scenario/src/main/java/io/morin/faggregate/core/validation/InMemoryRepository.java new file mode 100644 index 0000000..6f7d3f6 --- /dev/null +++ b/core-scenario/src/main/java/io/morin/faggregate/core/validation/InMemoryRepository.java @@ -0,0 +1,115 @@ +package io.morin.faggregate.core.validation; + +import io.morin.faggregate.api.Context; +import io.morin.faggregate.api.Initializer; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import lombok.Builder; +import lombok.NonNull; +import lombok.Value; + +/** + * An in-memory repository is a repository that stores the state and the events in memory. + *

+ * The purpose of this repository is to be used for testing and prototyping. + * Especially in conjunction with the scenario execution. + * So that, the scenario can be validated by the core business logic before to be used by the side effect implementations. + *

+ * The initialization of the state can be handled by an initializer on load. + * The initializedWhenNoFound flag must be set to true. + * So that, the initializer will be called when the state is not found. + * + * @param the type of the aggregate identifier + * @param the type of the aggregate state + */ +@Value +@Builder +public class InMemoryRepository implements Suite.Repository { + + /** + * The map to store the states. + */ + @Builder.Default + Map statesMap = new HashMap<>(); + + /** + * The map to store the events. + */ + @Builder.Default + Map> eventsMap = new HashMap<>(); + + /** + * The flag to initialize the state when the state is not found. + *

+ * The default value is false. + */ + boolean initializedWhenNoFound; + + /** + * The initializer is called when the state is not found and the initializedWhenNoFound flag is set to true. + *

+ * The default initializer throws an UnsupportedOperationException. + */ + @Builder.Default + Initializer initializer = context -> { + throw new UnsupportedOperationException("Not implemented"); + }; + + @Override + public CompletableFuture persist(Context context, S state, List events) { + // Delegate the store method + return this.storeState(context.getIdentifier(), state, events).toCompletableFuture(); + } + + @Override + @SuppressWarnings("unchecked") + public CompletableFuture> load(Context context) { + // Load the state + return this.loadState(context.getIdentifier()) + .thenApply(d -> (Optional) Optional.ofNullable(d)) + .thenCompose(optional -> { + // If the state is not found and the initializedWhenNoFound flag is set to true, initialize the state + if (optional.isEmpty() && initializedWhenNoFound) { + return initializer.initialize(context).thenApply(Optional::of); + } + return CompletableFuture.completedFuture(optional); + }) + .toCompletableFuture(); + } + + @Override + public CompletableFuture destroy(Context context, S state, List events) { + // Remove the state + statesMap.remove(context.getIdentifier()); + + // Remove the events + eventsMap.remove(context.getIdentifier()); + + // Return a completed future + return CompletableFuture.completedFuture(null); + } + + @Override + @SuppressWarnings("unchecked") + public CompletionStage storeState( + @NonNull Object identifier, + @NonNull Object state, + @NonNull List events + ) { + // Persist the state + statesMap.put((I) identifier, (S) state); + + // Persist the events + eventsMap.computeIfAbsent((I) identifier, k -> new ArrayList<>()).addAll(events); + + // Return a completed future + return CompletableFuture.completedStage(null); + } + + @Override + public CompletionStage loadState(@NonNull Object identifier) { + // Load the state + return CompletableFuture.completedStage(statesMap.get(identifier)); + } +} diff --git a/core-scenario/src/main/java/io/morin/faggregate/core/validation/ScenarioExecutor.java b/core-scenario/src/main/java/io/morin/faggregate/core/validation/ScenarioExecutor.java index eb71cc2..83d6746 100644 --- a/core-scenario/src/main/java/io/morin/faggregate/core/validation/ScenarioExecutor.java +++ b/core-scenario/src/main/java/io/morin/faggregate/core/validation/ScenarioExecutor.java @@ -76,7 +76,8 @@ public CompletionStage execute() { return Optional // GIVEN STEP - initialize the state of the aggregate with a given state .ofNullable(scenario.getGiven().getState()) - .map(state -> before.store(scenario.getGiven().getIdentifier(), state, scenario.getGiven().getEvents())) + .map(state -> before.storeState(scenario.getGiven().getIdentifier(), state, scenario.getGiven().getEvents()) + ) .orElseGet(() -> CompletableFuture.completedStage(null)) // GIVEN STEP - mutate the aggregate with given commands .thenAccept(unused -> { @@ -94,7 +95,7 @@ public CompletionStage execute() { // WHEN - create the outcome based on the fetch aggregate state and the output of the command .thenCompose(output -> after - .load(scenario.getGiven().getIdentifier()) + .loadState(scenario.getGiven().getIdentifier()) .thenApply(currentState -> new Outcome(output, currentState)) ) // THEN - assert the outcome @@ -139,7 +140,7 @@ public interface Before { * @param events a set of initial domain events * @return a completion stage */ - CompletionStage store(@NonNull Object identifier, @NonNull Object state, @NonNull List events); + CompletionStage storeState(@NonNull Object identifier, @NonNull Object state, @NonNull List events); } /** @@ -153,7 +154,7 @@ public interface After { * @param identifier the identifier of the aggregate * @return the state of the aggregate as a completion stage */ - CompletionStage load(@NonNull Object identifier); + CompletionStage loadState(@NonNull Object identifier); } /** @@ -168,7 +169,7 @@ static class Outcome { final Output output; /** - * The state fetched using {@link After#load(Object)}. + * The state fetched using {@link After#loadState(Object)}. */ final Object state; } diff --git a/core-scenario/src/main/java/io/morin/faggregate/core/validation/Suite.java b/core-scenario/src/main/java/io/morin/faggregate/core/validation/Suite.java index 2489fb7..59aaba1 100644 --- a/core-scenario/src/main/java/io/morin/faggregate/core/validation/Suite.java +++ b/core-scenario/src/main/java/io/morin/faggregate/core/validation/Suite.java @@ -1,9 +1,10 @@ package io.morin.faggregate.core.validation; -import io.morin.faggregate.api.AggregateManager; +import io.morin.faggregate.api.*; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; +import java.util.function.Supplier; import java.util.stream.Collectors; import lombok.*; @@ -14,6 +15,28 @@ @Builder public class Suite { + /** + * The repository is a set of interfaces to store, load and destroy the state of the aggregate. + * + * @param the type of the identifier + * @param the type of the state + */ + public interface Repository + extends Loader, Persister, Destroyer, ScenarioExecutor.Before, ScenarioExecutor.After { + /** + * Apply the in-memory repository to the aggregate manager builder. + * + * @param builder the aggregate manager builder + * @return the aggregate manager builder + */ + default AggregateManagerBuilder applyTo(@NonNull AggregateManagerBuilder builder) { + builder.set((Loader) this); + builder.set((Persister) this); + builder.set((Destroyer) this); + return builder; + } + } + /** * The set of scenarios. */ @@ -21,7 +44,47 @@ public class Suite { List scenarios; /** - * Execute the scenarios sequentially. + * The supplier of the in-memory repository. + *

+ * The default value is a supplier that creates a new instance of the in-memory repository. + */ + @Builder.Default + Supplier> repositorySupplier = () -> InMemoryRepository.builder().build(); + + /** + * Execute the scenarios sequentially based on the given Aggregate Manager Builder. + *

+ * The method build the artifact manager associating side effect implementations to an in-memory repository. + * Moreover, the before and after lambda are implemented to store and load the state of the aggregate. + * This method is useful to validate the scenarios before to be used by the side effect implementations. + * That means to perform integration test on the core business logic, i.e. the {@link io.morin.faggregate.api.Handler} + * and the {@link io.morin.faggregate.api.Mutator}. + *

+ * The in-memory repository implements the following interfaces: + *

    + *
  • {@link io.morin.faggregate.api.Persister}
  • + *
  • {@link io.morin.faggregate.api.Loader}
  • + *
  • {@link io.morin.faggregate.api.Destroyer}
  • + *
  • {@link io.morin.faggregate.core.validation.ScenarioExecutor.Before#storeState(Object, Object, List)}
  • + *
  • {@link io.morin.faggregate.core.validation.ScenarioExecutor.After#loadState(Object)}
  • + *
+ * + * @param amBuilder the Aggregate Manager Builder + * @param The type of the identifier + * @param The type of the state + * @return a completion stage + */ + @SuppressWarnings("unchecked") + public CompletableFuture execute(@NonNull AggregateManagerBuilder amBuilder) { + val repository = (Repository) repositorySupplier.get(); + return execute(repository.applyTo(amBuilder).build(), repository, repository); + } + + /** + * Execute the scenarios sequentially based on the given Aggregate Manager. + *

+ * This method is useful to validate the side effect implementations when the scenarios don't rely on both an initial + * state and the validation of the final state. * * @param am the Aggregate Manager * @param The type of the identifier @@ -33,15 +96,20 @@ public CompletableFuture execute(@NonNull AggregateManager am) { } /** - * Execute the scenarios sequentially. + * Execute the scenarios sequentially based on the given Aggregate Manager. + *

+ * This method is useful to validate the side effect implementations when the scenarios rely on either an initial + * state or the validation of the final state. *

* The before lambda is executed before the _Given_ phase. * Its purpose is to store the state of the aggregate. - * As long as the state of the artifact is not provided during the _Given_ phase, the before lambda is not mandatory. + * As long as the state of the artifact is not provided during the Given phase (i.e. {@link io.morin.faggregate.core.validation.Scenario.Given#state}), + * the before lambda is not mandatory. *

* The after lambda is executed after the _Then_ phase. * Its purpose is to load the state of the aggregate. - * As long as the state of the artifact is not validated during the _Then_ phase, the after lambda is not mandatory. + * As long as the state of the artifact is not validated during the Then phase (i.e. {@link io.morin.faggregate.core.validation.Scenario.Then#state}), + * the after lambda is not mandatory. * * @param am the Aggregate Manager * @param before the optional before lambda diff --git a/core-scenario/src/test/java/io/morin/faggregate/core/validation/InMemoryRepositoryTest.java b/core-scenario/src/test/java/io/morin/faggregate/core/validation/InMemoryRepositoryTest.java new file mode 100644 index 0000000..27e283b --- /dev/null +++ b/core-scenario/src/test/java/io/morin/faggregate/core/validation/InMemoryRepositoryTest.java @@ -0,0 +1,127 @@ +package io.morin.faggregate.core.validation; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import io.morin.faggregate.api.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import lombok.SneakyThrows; +import lombok.val; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class InMemoryRepositoryTest { + + @Mock + Context context; + + @Mock + AggregateManagerBuilder aggregateManagerBuilder; + + @Test + @SneakyThrows + void shouldPersist() { + when(context.getIdentifier()).thenReturn("id"); + + val repository = InMemoryRepository.builder().build(); + + repository.persist(context, "state", List.of("event_a")).get(); + + assertEquals("state", repository.getStatesMap().get("id")); + assertEquals(List.of("event_a"), repository.getEventsMap().get("id")); + } + + @Test + @SneakyThrows + void shouldLoad() { + when(context.getIdentifier()).thenReturn("id"); + + val repository = InMemoryRepository + .builder() + .statesMap(Map.of("id", "state")) + .eventsMap(Map.of("id", List.of("event_a"))) + .build(); + + val optionalState = repository.load(context).get(); + + assertTrue(optionalState.isPresent()); + assertEquals("state", optionalState.get()); + } + + @Test + @SneakyThrows + void shouldNotLoad() { + when(context.getIdentifier()).thenReturn("id"); + + val repository = InMemoryRepository.builder().build(); + + val optionalState = repository.load(context).get(); + + assertTrue(optionalState.isEmpty()); + } + + @Test + @SneakyThrows + void shouldWithInitializer() { + when(context.getIdentifier()).thenReturn("id"); + + val repository = InMemoryRepository + .builder() + .initializedWhenNoFound(true) + .initializer(context -> CompletableFuture.completedFuture("state")) + .build(); + + val optionalState = repository.load(context).get(); + + assertTrue(optionalState.isPresent()); + assertEquals("state", optionalState.get()); + } + + @Test + @SneakyThrows + void shouldNotLoadWithInitializerWhenNotActivated() { + when(context.getIdentifier()).thenReturn("id"); + + val repository = InMemoryRepository.builder().initializedWhenNoFound(true).build(); + + val exception = assertThrows(ExecutionException.class, () -> repository.load(context).get()); + + assertEquals(UnsupportedOperationException.class, exception.getCause().getClass()); + } + + @Test + @SneakyThrows + void shouldDestroy() { + when(context.getIdentifier()).thenReturn("id"); + + val repository = InMemoryRepository + .builder() + .statesMap(new HashMap<>(Map.of("id", "state"))) + .eventsMap(new HashMap<>(Map.of("id", List.of("event_a")))) + .build(); + + repository.destroy(context, "state_b", List.of("event_b")).get(); + + assertFalse(repository.getStatesMap().containsKey("id")); + assertFalse(repository.getEventsMap().containsKey("id")); + } + + @Test + void shouldApplyTo() { + val repository = InMemoryRepository.builder().build(); + + assertNotNull(repository.applyTo(aggregateManagerBuilder)); + + verify(aggregateManagerBuilder).set((Loader) repository); + verify(aggregateManagerBuilder).set((Persister) repository); + verify(aggregateManagerBuilder).set((Destroyer) repository); + } +} diff --git a/core-scenario/src/test/java/io/morin/faggregate/core/validation/ScenarioExecutorTest.java b/core-scenario/src/test/java/io/morin/faggregate/core/validation/ScenarioExecutorTest.java index fa8d7be..3849254 100644 --- a/core-scenario/src/test/java/io/morin/faggregate/core/validation/ScenarioExecutorTest.java +++ b/core-scenario/src/test/java/io/morin/faggregate/core/validation/ScenarioExecutorTest.java @@ -83,9 +83,9 @@ void shouldSuccess() { .thenReturn(CompletableFuture.completedFuture(OutputBuilder.get(null).add(expectedEvent).build())); when(am.execute(eq("id"), any(String.class))) .thenReturn(CompletableFuture.completedFuture(OutputBuilder.get(null).build())); - when(after.load(any())).thenReturn(CompletableFuture.completedStage(expectedState)); + when(after.loadState(any())).thenReturn(CompletableFuture.completedStage(expectedState)); Assertions.assertDoesNotThrow(() -> executor.execute().toCompletableFuture().get()); - verify(before, new Only()).store(eq("id"), eq(initialState), anyList()); + verify(before, new Only()).storeState(eq("id"), eq(initialState), anyList()); verify(am, new Times(2)).execute(eq("id"), anyString()); verify(asserter, new Only()).accept(eq(expectedState), anyList()); } @@ -94,9 +94,9 @@ void shouldSuccess() { void shouldSuccessWhenInitialState() { when(am.execute(eq("id"), any(ApplyUppercase.class))) .thenReturn(CompletableFuture.completedFuture(OutputBuilder.get(null).add(expectedEvent).build())); - when(after.load(any())).thenReturn(CompletableFuture.completedStage(expectedState)); + when(after.loadState(any())).thenReturn(CompletableFuture.completedStage(expectedState)); Assertions.assertDoesNotThrow(() -> executorAlt.execute().toCompletableFuture().get()); - verify(before, new NoInteractions()).store(any(), any(), any()); + verify(before, new NoInteractions()).storeState(any(), any(), any()); verify(am, new Only()).execute(eq("id"), any(ApplyUppercase.class)); } @@ -104,7 +104,7 @@ void shouldSuccessWhenInitialState() { void shouldFailedWhenWrongExpectedState() { when(am.execute(any(), any())) .thenReturn(CompletableFuture.completedFuture(OutputBuilder.get(null).add(expectedEvent).build())); - when(after.load(any())).thenReturn(CompletableFuture.completedStage(initialState)); + when(after.loadState(any())).thenReturn(CompletableFuture.completedStage(initialState)); Assertions.assertThrows(ExecutionException.class, () -> executor.execute().toCompletableFuture().get()); } @@ -113,7 +113,7 @@ void shouldFailedWhenWrongExpectedState() { void shouldFailedWhenWrongExpectedEvent() { when(am.execute(any(), any())) .thenReturn(CompletableFuture.completedFuture(OutputBuilder.get(null).add(wrongExpectedEvent).build())); - when(after.load(any())).thenReturn(CompletableFuture.completedStage(expectedState)); + when(after.loadState(any())).thenReturn(CompletableFuture.completedStage(expectedState)); Assertions.assertThrows(ExecutionException.class, () -> executor.execute().toCompletableFuture().get()); } @@ -126,7 +126,7 @@ void shouldFailedWhenTooMuchExpectedEvents() { OutputBuilder.get(null).add(expectedEvent).add(wrongExpectedEvent).build() ) ); - when(after.load(any())).thenReturn(CompletableFuture.completedStage(expectedState)); + when(after.loadState(any())).thenReturn(CompletableFuture.completedStage(expectedState)); Assertions.assertThrows(ExecutionException.class, () -> executor.execute().toCompletableFuture().get()); } @@ -143,7 +143,7 @@ void shouldFailedWhenAsserterFails() { .thenReturn(CompletableFuture.completedFuture(OutputBuilder.get(null).add(expectedEvent).build())); when(am.execute(eq("id"), any(String.class))) .thenReturn(CompletableFuture.completedFuture(OutputBuilder.get(null).build())); - when(after.load(any())).thenReturn(CompletableFuture.completedStage(expectedState)); + when(after.loadState(any())).thenReturn(CompletableFuture.completedStage(expectedState)); doThrow(new IllegalStateException()).when(asserter).accept(any(), any()); Assertions.assertThrows(ExecutionException.class, () -> executor.execute().toCompletableFuture().get()); diff --git a/core-scenario/src/test/java/io/morin/faggregate/core/validation/SuiteTest.java b/core-scenario/src/test/java/io/morin/faggregate/core/validation/SuiteTest.java index 7b99358..3134708 100644 --- a/core-scenario/src/test/java/io/morin/faggregate/core/validation/SuiteTest.java +++ b/core-scenario/src/test/java/io/morin/faggregate/core/validation/SuiteTest.java @@ -5,6 +5,7 @@ import static org.mockito.Mockito.*; import io.morin.faggregate.api.AggregateManager; +import io.morin.faggregate.api.AggregateManagerBuilder; import io.morin.faggregate.api.Output; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -36,7 +37,13 @@ class SuiteTest { Scenario.Then then; @Mock - AggregateManager am; + AggregateManager am; + + @Mock + AggregateManagerBuilder amBuilder; + + @Mock + Suite.Repository repository; @Mock ScenarioExecutor.Before before; @@ -47,6 +54,54 @@ class SuiteTest { @Mock Output output; + @Test + void shouldExecuteWithInMemory() { + when(scenarioA.getGiven()).thenReturn(given); + when(scenarioA.getWhen()).thenReturn(when); + when(scenarioA.getThen()).thenReturn(then); + + when(scenarioB.getGiven()).thenReturn(given); + when(scenarioB.getWhen()).thenReturn(when); + when(scenarioB.getThen()).thenReturn(then); + + when(scenarioC.getGiven()).thenReturn(given); + when(scenarioC.getWhen()).thenReturn(when); + when(scenarioC.getThen()).thenReturn(then); + + when(repository.loadState(any())).thenReturn(CompletableFuture.completedFuture(null)); + when(repository.applyTo(any())).thenReturn(amBuilder); + + when(amBuilder.build()).thenReturn(am); + when(am.execute(any(), any())).thenReturn(CompletableFuture.completedFuture(output)); + + assertDoesNotThrow(() -> + Suite + .builder() + .scenario(scenarioA) + .scenario(scenarioB) + .scenario(scenarioC) + .repositorySupplier(() -> repository) + .build() + .execute(amBuilder) + .toCompletableFuture() + .get() + ); + + verify(am, Mockito.times(3)).execute(any(), any()); + + verify(scenarioA, Mockito.times(4)).getGiven(); + verify(scenarioA, Mockito.times(1)).getWhen(); + verify(scenarioA, Mockito.times(3)).getThen(); + + verify(scenarioB, Mockito.times(4)).getGiven(); + verify(scenarioB, Mockito.times(1)).getWhen(); + verify(scenarioB, Mockito.times(3)).getThen(); + + verify(scenarioC, Mockito.times(4)).getGiven(); + verify(scenarioC, Mockito.times(1)).getWhen(); + verify(scenarioC, Mockito.times(3)).getThen(); + } + @Test void shouldExecute() { when(scenarioA.getGiven()).thenReturn(given); @@ -62,7 +117,7 @@ void shouldExecute() { when(scenarioC.getThen()).thenReturn(then); when(am.execute(any(), any())).thenReturn(CompletableFuture.completedFuture(output)); - when(after.load(any())).thenReturn(CompletableFuture.completedFuture(null)); + when(after.loadState(any())).thenReturn(CompletableFuture.completedFuture(null)); assertDoesNotThrow(() -> Suite @@ -77,7 +132,7 @@ void shouldExecute() { ); verify(am, Mockito.times(3)).execute(any(), any()); - verify(after, Mockito.times(3)).load(any()); + verify(after, Mockito.times(3)).loadState(any()); verify(scenarioA, Mockito.times(4)).getGiven(); verify(scenarioA, Mockito.times(1)).getWhen(); diff --git a/examples/todo-core/src/main/java/todo/model/mapper/TodoMappers.java b/examples/todo-core/src/main/java/todo/model/mapper/TodoMappers.java index e510c90..0c6d109 100644 --- a/examples/todo-core/src/main/java/todo/model/mapper/TodoMappers.java +++ b/examples/todo-core/src/main/java/todo/model/mapper/TodoMappers.java @@ -18,7 +18,7 @@ public class TodoMappers { * @param todoList the list entity * @return the view */ - public static TodoListView toView(TodoList todoList) { + public TodoListView toView(TodoList todoList) { return TodoListView.builder().todoListId(todoList.todoListId()).label(todoList.label()).build(); } @@ -29,7 +29,7 @@ public static TodoListView toView(TodoList todoList) { * @param todoItem the item entity * @return the view */ - public static TodoItemView toView(TodoList todoList, TodoItem todoItem) { + public TodoItemView toView(TodoList todoList, TodoItem todoItem) { return TodoItemView .builder() .todoListId(todoList.todoListId())