From 582865b3c04959b00fc145311ec73a56b81d001b Mon Sep 17 00:00:00 2001 From: "fabrizio.guerrini" Date: Thu, 18 May 2023 09:18:24 +0200 Subject: [PATCH 1/9] PSCF2-88 Implementazione dell'API GET /terminals/{paTaxCode} PSCF2-90 Implementazione dell'API GET/presets/{paTaxCode}/{subscriberId} PSCF2-89 Implementazione dell'API POST /presets --- .dockerignore | 5 + .gitignore | 40 ++ .mvn/wrapper/.gitignore | 1 + .mvn/wrapper/MavenWrapperDownloader.java | 142 +++++ .mvn/wrapper/maven-wrapper.properties | 18 + README.md | 5 + mvnw | 316 ++++++++++ mvnw.cmd | 188 ++++++ pom.xml | 265 ++++++++ src/main/docker/Dockerfile.jvm | 95 +++ src/main/docker/Dockerfile.legacy-jar | 91 +++ src/main/docker/Dockerfile.native | 27 + src/main/docker/Dockerfile.native-micro | 30 + .../pagopa/swclient/mil/preset/ErrorCode.java | 43 ++ .../swclient/mil/preset/OperationType.java | 12 + .../swclient/mil/preset/PresetStatus.java | 12 + .../swclient/mil/preset/bean/Notice.java | 241 ++++++++ .../mil/preset/bean/PaymentTransaction.java | 386 ++++++++++++ .../mil/preset/bean/PresetHeaders.java | 68 ++ .../mil/preset/bean/PresetRequest.java | 136 ++++ .../mil/preset/bean/PresetResponse.java | 247 ++++++++ .../mil/preset/bean/PresetsPathParam.java | 64 ++ .../mil/preset/bean/PresetsResponse.java | 41 ++ .../mil/preset/bean/SubcribersResponse.java | 42 ++ .../mil/preset/bean/SubscriberRequest.java | 61 ++ .../mil/preset/bean/SubscriberResponse.java | 228 +++++++ .../mil/preset/bean/SubscribersPathParam.java | 41 ++ .../mil/preset/bean/UnsubscriberHeaders.java | 156 +++++ .../preset/bean/UnsubscriberPathParam.java | 64 ++ .../mil/preset/dao/PresetRepository.java | 12 + .../mil/preset/dao/PresetsEntity.java | 222 +++++++ .../mil/preset/dao/SubscriberEntity.java | 207 +++++++ .../mil/preset/dao/SubscriberRepository.java | 12 + .../mil/preset/resource/PresetsResource.java | 308 ++++++++++ .../preset/resource/SubscribeResource.java | 297 +++++++++ .../swclient/mil/preset/utils/DateUtils.java | 24 + .../constraints/MerchantIdNotNullForPos.java | 28 + .../MerchantIdNotNullForPosValidator.java | 22 + src/main/resources/application.properties | 46 ++ .../mil/preset/PresetResourceTest.java | 579 ++++++++++++++++++ .../mil/preset/SubscribeResourceTest.java | 325 ++++++++++ .../mil/preset/it/PresetResourceTestIT.java | 216 +++++++ .../preset/it/SubscribeResourceTestIT.java | 190 ++++++ .../preset/resource/MongoTestResource.java | 112 ++++ src/test/resources/mongoInit.js | 103 ++++ 45 files changed, 5768 insertions(+) create mode 100644 .dockerignore create mode 100644 .gitignore create mode 100644 .mvn/wrapper/.gitignore create mode 100644 .mvn/wrapper/MavenWrapperDownloader.java create mode 100644 .mvn/wrapper/maven-wrapper.properties create mode 100644 README.md create mode 100644 mvnw create mode 100644 mvnw.cmd create mode 100644 pom.xml create mode 100644 src/main/docker/Dockerfile.jvm create mode 100644 src/main/docker/Dockerfile.legacy-jar create mode 100644 src/main/docker/Dockerfile.native create mode 100644 src/main/docker/Dockerfile.native-micro create mode 100644 src/main/java/it/pagopa/swclient/mil/preset/ErrorCode.java create mode 100644 src/main/java/it/pagopa/swclient/mil/preset/OperationType.java create mode 100644 src/main/java/it/pagopa/swclient/mil/preset/PresetStatus.java create mode 100644 src/main/java/it/pagopa/swclient/mil/preset/bean/Notice.java create mode 100644 src/main/java/it/pagopa/swclient/mil/preset/bean/PaymentTransaction.java create mode 100644 src/main/java/it/pagopa/swclient/mil/preset/bean/PresetHeaders.java create mode 100644 src/main/java/it/pagopa/swclient/mil/preset/bean/PresetRequest.java create mode 100644 src/main/java/it/pagopa/swclient/mil/preset/bean/PresetResponse.java create mode 100644 src/main/java/it/pagopa/swclient/mil/preset/bean/PresetsPathParam.java create mode 100644 src/main/java/it/pagopa/swclient/mil/preset/bean/PresetsResponse.java create mode 100644 src/main/java/it/pagopa/swclient/mil/preset/bean/SubcribersResponse.java create mode 100644 src/main/java/it/pagopa/swclient/mil/preset/bean/SubscriberRequest.java create mode 100644 src/main/java/it/pagopa/swclient/mil/preset/bean/SubscriberResponse.java create mode 100644 src/main/java/it/pagopa/swclient/mil/preset/bean/SubscribersPathParam.java create mode 100644 src/main/java/it/pagopa/swclient/mil/preset/bean/UnsubscriberHeaders.java create mode 100644 src/main/java/it/pagopa/swclient/mil/preset/bean/UnsubscriberPathParam.java create mode 100644 src/main/java/it/pagopa/swclient/mil/preset/dao/PresetRepository.java create mode 100644 src/main/java/it/pagopa/swclient/mil/preset/dao/PresetsEntity.java create mode 100644 src/main/java/it/pagopa/swclient/mil/preset/dao/SubscriberEntity.java create mode 100644 src/main/java/it/pagopa/swclient/mil/preset/dao/SubscriberRepository.java create mode 100644 src/main/java/it/pagopa/swclient/mil/preset/resource/PresetsResource.java create mode 100644 src/main/java/it/pagopa/swclient/mil/preset/resource/SubscribeResource.java create mode 100644 src/main/java/it/pagopa/swclient/mil/preset/utils/DateUtils.java create mode 100644 src/main/java/it/pagopa/swclient/mil/preset/validation/constraints/MerchantIdNotNullForPos.java create mode 100644 src/main/java/it/pagopa/swclient/mil/preset/validation/constraints/MerchantIdNotNullForPosValidator.java create mode 100644 src/main/resources/application.properties create mode 100644 src/test/java/it/pagopa/swclient/mil/preset/PresetResourceTest.java create mode 100644 src/test/java/it/pagopa/swclient/mil/preset/SubscribeResourceTest.java create mode 100644 src/test/java/it/pagopa/swclient/mil/preset/it/PresetResourceTestIT.java create mode 100644 src/test/java/it/pagopa/swclient/mil/preset/it/SubscribeResourceTestIT.java create mode 100644 src/test/java/it/pagopa/swclient/mil/preset/resource/MongoTestResource.java create mode 100644 src/test/resources/mongoInit.js diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..94810d0 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +* +!target/*-runner +!target/*-runner.jar +!target/lib/* +!target/quarkus-app/* \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..693002a --- /dev/null +++ b/.gitignore @@ -0,0 +1,40 @@ +#Maven +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +release.properties +.flattened-pom.xml + +# Eclipse +.project +.classpath +.settings/ +bin/ + +# IntelliJ +.idea +*.ipr +*.iml +*.iws + +# NetBeans +nb-configuration.xml + +# Visual Studio Code +.vscode +.factorypath + +# OSX +.DS_Store + +# Vim +*.swp +*.swo + +# patch +*.orig +*.rej + +# Local environment +.env diff --git a/.mvn/wrapper/.gitignore b/.mvn/wrapper/.gitignore new file mode 100644 index 0000000..e72f5e8 --- /dev/null +++ b/.mvn/wrapper/.gitignore @@ -0,0 +1 @@ +maven-wrapper.jar diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java new file mode 100644 index 0000000..1708393 --- /dev/null +++ b/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,142 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * 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. + */ + +import java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.Properties; + +public class MavenWrapperDownloader +{ + private static final String WRAPPER_VERSION = "3.1.1"; + + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = + "https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/" + WRAPPER_VERSION + + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to use instead of the + * default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main( String args[] ) + { + System.out.println( "- Downloader started" ); + File baseDirectory = new File( args[0] ); + System.out.println( "- Using base directory: " + baseDirectory.getAbsolutePath() ); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File( baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH ); + String url = DEFAULT_DOWNLOAD_URL; + if ( mavenWrapperPropertyFile.exists() ) + { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try + { + mavenWrapperPropertyFileInputStream = new FileInputStream( mavenWrapperPropertyFile ); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load( mavenWrapperPropertyFileInputStream ); + url = mavenWrapperProperties.getProperty( PROPERTY_NAME_WRAPPER_URL, url ); + } + catch ( IOException e ) + { + System.out.println( "- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'" ); + } + finally + { + try + { + if ( mavenWrapperPropertyFileInputStream != null ) + { + mavenWrapperPropertyFileInputStream.close(); + } + } + catch ( IOException e ) + { + // Ignore ... + } + } + } + System.out.println( "- Downloading from: " + url ); + + File outputFile = new File( baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH ); + if ( !outputFile.getParentFile().exists() ) + { + if ( !outputFile.getParentFile().mkdirs() ) + { + System.out.println( "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + + "'" ); + } + } + System.out.println( "- Downloading to: " + outputFile.getAbsolutePath() ); + try + { + downloadFileFromURL( url, outputFile ); + System.out.println( "Done" ); + System.exit( 0 ); + } + catch ( Throwable e ) + { + System.out.println( "- Error downloading" ); + e.printStackTrace(); + System.exit( 1 ); + } + } + + private static void downloadFileFromURL( String urlString, File destination ) + throws Exception + { + if ( System.getenv( "MVNW_USERNAME" ) != null && System.getenv( "MVNW_PASSWORD" ) != null ) + { + String username = System.getenv( "MVNW_USERNAME" ); + char[] password = System.getenv( "MVNW_PASSWORD" ).toCharArray(); + Authenticator.setDefault( new Authenticator() + { + @Override + protected PasswordAuthentication getPasswordAuthentication() + { + return new PasswordAuthentication( username, password ); + } + } ); + } + URL website = new URL( urlString ); + ReadableByteChannel rbc; + rbc = Channels.newChannel( website.openStream() ); + FileOutputStream fos = new FileOutputStream( destination ); + fos.getChannel().transferFrom( rbc, 0, Long.MAX_VALUE ); + fos.close(); + rbc.close(); + } + +} diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..61a2ef1 --- /dev/null +++ b/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# 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.6/apache-maven-3.8.6-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar diff --git a/README.md b/README.md new file mode 100644 index 0000000..8a29f04 --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# Multi-channel Integration Layer - Preset +Preset Microservice for Multi-channel Integration Layer of SW Client Project. + +## Dependencies +This project depends on mil-common. If you don't want to clone and install it locally, run ```mvn validate -Dmaven.home=``` before. \ No newline at end of file diff --git a/mvnw b/mvnw new file mode 100644 index 0000000..eaa3d30 --- /dev/null +++ b/mvnw @@ -0,0 +1,316 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# 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 +# +# https://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. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# 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 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # 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`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + 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"` + [ -n "$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)`" +fi + +if [ -z "$JAVA_HOME" ]; 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 + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`\\unset -f command; \\command -v java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +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" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# 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 +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; 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" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + 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") + 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") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +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"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$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 $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +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 new file mode 100644 index 0000000..abb7c32 --- /dev/null +++ b/mvnw.cmd @@ -0,0 +1,188 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven Start Up Batch script +@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 +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +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.1/maven-wrapper-3.1.1.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 +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "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%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@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=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..cee7798 --- /dev/null +++ b/pom.xml @@ -0,0 +1,265 @@ + + + 4.0.0 + it.pagopa.swclient.mil + preset + 1.0.1-SNAPSHOT + Preset Microservice for Multi-channel Integration Layer of SW Client Project + + 17 + ${java.version} + ${java.version} + ${java.version} + 3.8.1 + 3.0.0-M7 + UTF-8 + UTF-8 + quarkus-bom + io.quarkus.platform + 3.0.2.Final + 2.0.1 + true + + + + + ${quarkus.platform.group-id} + ${quarkus.platform.artifact-id} + ${quarkus.platform.version} + pom + import + + + + + + io.quarkus + quarkus-resteasy-reactive-jackson + + + io.quarkus + quarkus-hibernate-validator + + + io.quarkus + quarkus-smallrye-health + + + io.quarkus + quarkus-arc + + + io.quarkus + quarkus-resteasy-reactive + + + io.quarkus + quarkus-rest-client-reactive + + + io.quarkus + quarkus-mongodb-panache + + + io.quarkus + quarkus-junit5 + test + + + io.rest-assured + rest-assured + test + + + io.quarkus + quarkus-junit5-mockito + test + + + it.pagopa.swclient.mil + common + ${common.version} + + + io.quarkus + quarkus-panache-mock + test + + + io.quarkus + quarkus-jacoco + test + + + org.jacoco + jacoco-maven-plugin + 0.8.6 + + + io.quarkus + quarkus-container-image-docker + + + com.github.tomakehurst + wiremock-jre8 + 2.35.0 + test + + + org.testcontainers + testcontainers + test + + + io.quarkus + quarkus-rest-client-reactive-jackson + + + + + + ${quarkus.platform.group-id} + quarkus-maven-plugin + ${quarkus.platform.version} + true + + + + build + generate-code + generate-code-tests + + + + + + maven-compiler-plugin + ${compiler-plugin.version} + + + -parameters + + + + io.quarkus + quarkus-panache-common + ${quarkus.platform.version} + + + + + + maven-surefire-plugin + ${surefire-plugin.version} + + + org.jboss.logmanager.LogManager + ${maven.home} + + + + + maven-failsafe-plugin + ${surefire-plugin.version} + + + + integration-test + verify + + + + ${project.build.directory}/${project.build.finalName}-runner + org.jboss.logmanager.LogManager + ${maven.home} + + + + + + + + + + + + bootstrap + + + bootstrap + + + + + + org.apache.maven.plugins + maven-scm-plugin + 2.0.0-M3 + + ${maven.home} + install + + + + clone_and_install_mil-common + validate + + scm:git:/~https://github.com/pagopa/mil-common.git + tag + ${common.version} + + + bootstrap + + + + + + + + + native + + + native + + + + false + native + + + + coverage + + + + org.jacoco + jacoco-maven-plugin + 0.8.8 + + + prepare-agent + + prepare-agent + + + + report + + report + + + + XML + + + + + + + + + + diff --git a/src/main/docker/Dockerfile.jvm b/src/main/docker/Dockerfile.jvm new file mode 100644 index 0000000..dc889bf --- /dev/null +++ b/src/main/docker/Dockerfile.jvm @@ -0,0 +1,95 @@ +#### +# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode +# +# Before building the container image run: +# +# ./mvnw package +# +# Then, build the image with: +# +# docker build -f src/main/docker/Dockerfile.jvm -t quarkus/code-with-quarkus-jvm . +# +# Then run the container using: +# +# docker run -i --rm -p 8080:8080 quarkus/code-with-quarkus-jvm +# +# If you want to include the debug port into your docker image +# you will have to expose the debug port (default 5005 being the default) like this : EXPOSE 8080 5005. +# Additionally you will have to set -e JAVA_DEBUG=true and -e JAVA_DEBUG_PORT=*:5005 +# when running the container +# +# Then run the container using : +# +# docker run -i --rm -p 8080:8080 quarkus/code-with-quarkus-jvm +# +# This image uses the `run-java.sh` script to run the application. +# This scripts computes the command line to execute your Java application, and +# includes memory/GC tuning. +# You can configure the behavior using the following environment properties: +# - JAVA_OPTS: JVM options passed to the `java` command (example: "-verbose:class") +# - JAVA_OPTS_APPEND: User specified Java options to be appended to generated options +# in JAVA_OPTS (example: "-Dsome.property=foo") +# - JAVA_MAX_MEM_RATIO: Is used when no `-Xmx` option is given in JAVA_OPTS. This is +# used to calculate a default maximal heap memory based on a containers restriction. +# If used in a container without any memory constraints for the container then this +# option has no effect. If there is a memory constraint then `-Xmx` is set to a ratio +# of the container available memory as set here. The default is `50` which means 50% +# of the available memory is used as an upper boundary. You can skip this mechanism by +# setting this value to `0` in which case no `-Xmx` option is added. +# - JAVA_INITIAL_MEM_RATIO: Is used when no `-Xms` option is given in JAVA_OPTS. This +# is used to calculate a default initial heap memory based on the maximum heap memory. +# If used in a container without any memory constraints for the container then this +# option has no effect. If there is a memory constraint then `-Xms` is set to a ratio +# of the `-Xmx` memory as set here. The default is `25` which means 25% of the `-Xmx` +# is used as the initial heap size. You can skip this mechanism by setting this value +# to `0` in which case no `-Xms` option is added (example: "25") +# - JAVA_MAX_INITIAL_MEM: Is used when no `-Xms` option is given in JAVA_OPTS. +# This is used to calculate the maximum value of the initial heap memory. If used in +# a container without any memory constraints for the container then this option has +# no effect. If there is a memory constraint then `-Xms` is limited to the value set +# here. The default is 4096MB which means the calculated value of `-Xms` never will +# be greater than 4096MB. The value of this variable is expressed in MB (example: "4096") +# - JAVA_DIAGNOSTICS: Set this to get some diagnostics information to standard output +# when things are happening. This option, if set to true, will set +# `-XX:+UnlockDiagnosticVMOptions`. Disabled by default (example: "true"). +# - JAVA_DEBUG: If set remote debugging will be switched on. Disabled by default (example: +# true"). +# - JAVA_DEBUG_PORT: Port used for remote debugging. Defaults to 5005 (example: "8787"). +# - CONTAINER_CORE_LIMIT: A calculated core limit as described in +# https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt. (example: "2") +# - CONTAINER_MAX_MEMORY: Memory limit given to the container (example: "1024"). +# - GC_MIN_HEAP_FREE_RATIO: Minimum percentage of heap free after GC to avoid expansion. +# (example: "20") +# - GC_MAX_HEAP_FREE_RATIO: Maximum percentage of heap free after GC to avoid shrinking. +# (example: "40") +# - GC_TIME_RATIO: Specifies the ratio of the time spent outside the garbage collection. +# (example: "4") +# - GC_ADAPTIVE_SIZE_POLICY_WEIGHT: The weighting given to the current GC time versus +# previous GC times. (example: "90") +# - GC_METASPACE_SIZE: The initial metaspace size. (example: "20") +# - GC_MAX_METASPACE_SIZE: The maximum metaspace size. (example: "100") +# - GC_CONTAINER_OPTIONS: Specify Java GC to use. The value of this variable should +# contain the necessary JRE command-line options to specify the required GC, which +# will override the default of `-XX:+UseParallelGC` (example: -XX:+UseG1GC). +# - HTTPS_PROXY: The location of the https proxy. (example: "myuser@127.0.0.1:8080") +# - HTTP_PROXY: The location of the http proxy. (example: "myuser@127.0.0.1:8080") +# - NO_PROXY: A comma separated lists of hosts, IP addresses or domains that can be +# accessed directly. (example: "foo.example.com,bar.example.com") +# +### +FROM registry.access.redhat.com/ubi8/openjdk-17:1.14 + +ENV LANGUAGE='en_US:en' + + +# We make four distinct layers so if there are application changes the library layers can be re-used +COPY --chown=185 target/quarkus-app/lib/ /deployments/lib/ +COPY --chown=185 target/quarkus-app/*.jar /deployments/ +COPY --chown=185 target/quarkus-app/app/ /deployments/app/ +COPY --chown=185 target/quarkus-app/quarkus/ /deployments/quarkus/ + +EXPOSE 8080 +USER 185 +ENV JAVA_OPTS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" +ENV JAVA_APP_JAR="/deployments/quarkus-run.jar" + diff --git a/src/main/docker/Dockerfile.legacy-jar b/src/main/docker/Dockerfile.legacy-jar new file mode 100644 index 0000000..0d4ff83 --- /dev/null +++ b/src/main/docker/Dockerfile.legacy-jar @@ -0,0 +1,91 @@ +#### +# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode +# +# Before building the container image run: +# +# ./mvnw package -Dquarkus.package.type=legacy-jar +# +# Then, build the image with: +# +# docker build -f src/main/docker/Dockerfile.legacy-jar -t quarkus/code-with-quarkus-legacy-jar . +# +# Then run the container using: +# +# docker run -i --rm -p 8080:8080 quarkus/code-with-quarkus-legacy-jar +# +# If you want to include the debug port into your docker image +# you will have to expose the debug port (default 5005 being the default) like this : EXPOSE 8080 5005. +# Additionally you will have to set -e JAVA_DEBUG=true and -e JAVA_DEBUG_PORT=*:5005 +# when running the container +# +# Then run the container using : +# +# docker run -i --rm -p 8080:8080 quarkus/code-with-quarkus-legacy-jar +# +# This image uses the `run-java.sh` script to run the application. +# This scripts computes the command line to execute your Java application, and +# includes memory/GC tuning. +# You can configure the behavior using the following environment properties: +# - JAVA_OPTS: JVM options passed to the `java` command (example: "-verbose:class") +# - JAVA_OPTS_APPEND: User specified Java options to be appended to generated options +# in JAVA_OPTS (example: "-Dsome.property=foo") +# - JAVA_MAX_MEM_RATIO: Is used when no `-Xmx` option is given in JAVA_OPTS. This is +# used to calculate a default maximal heap memory based on a containers restriction. +# If used in a container without any memory constraints for the container then this +# option has no effect. If there is a memory constraint then `-Xmx` is set to a ratio +# of the container available memory as set here. The default is `50` which means 50% +# of the available memory is used as an upper boundary. You can skip this mechanism by +# setting this value to `0` in which case no `-Xmx` option is added. +# - JAVA_INITIAL_MEM_RATIO: Is used when no `-Xms` option is given in JAVA_OPTS. This +# is used to calculate a default initial heap memory based on the maximum heap memory. +# If used in a container without any memory constraints for the container then this +# option has no effect. If there is a memory constraint then `-Xms` is set to a ratio +# of the `-Xmx` memory as set here. The default is `25` which means 25% of the `-Xmx` +# is used as the initial heap size. You can skip this mechanism by setting this value +# to `0` in which case no `-Xms` option is added (example: "25") +# - JAVA_MAX_INITIAL_MEM: Is used when no `-Xms` option is given in JAVA_OPTS. +# This is used to calculate the maximum value of the initial heap memory. If used in +# a container without any memory constraints for the container then this option has +# no effect. If there is a memory constraint then `-Xms` is limited to the value set +# here. The default is 4096MB which means the calculated value of `-Xms` never will +# be greater than 4096MB. The value of this variable is expressed in MB (example: "4096") +# - JAVA_DIAGNOSTICS: Set this to get some diagnostics information to standard output +# when things are happening. This option, if set to true, will set +# `-XX:+UnlockDiagnosticVMOptions`. Disabled by default (example: "true"). +# - JAVA_DEBUG: If set remote debugging will be switched on. Disabled by default (example: +# true"). +# - JAVA_DEBUG_PORT: Port used for remote debugging. Defaults to 5005 (example: "8787"). +# - CONTAINER_CORE_LIMIT: A calculated core limit as described in +# https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt. (example: "2") +# - CONTAINER_MAX_MEMORY: Memory limit given to the container (example: "1024"). +# - GC_MIN_HEAP_FREE_RATIO: Minimum percentage of heap free after GC to avoid expansion. +# (example: "20") +# - GC_MAX_HEAP_FREE_RATIO: Maximum percentage of heap free after GC to avoid shrinking. +# (example: "40") +# - GC_TIME_RATIO: Specifies the ratio of the time spent outside the garbage collection. +# (example: "4") +# - GC_ADAPTIVE_SIZE_POLICY_WEIGHT: The weighting given to the current GC time versus +# previous GC times. (example: "90") +# - GC_METASPACE_SIZE: The initial metaspace size. (example: "20") +# - GC_MAX_METASPACE_SIZE: The maximum metaspace size. (example: "100") +# - GC_CONTAINER_OPTIONS: Specify Java GC to use. The value of this variable should +# contain the necessary JRE command-line options to specify the required GC, which +# will override the default of `-XX:+UseParallelGC` (example: -XX:+UseG1GC). +# - HTTPS_PROXY: The location of the https proxy. (example: "myuser@127.0.0.1:8080") +# - HTTP_PROXY: The location of the http proxy. (example: "myuser@127.0.0.1:8080") +# - NO_PROXY: A comma separated lists of hosts, IP addresses or domains that can be +# accessed directly. (example: "foo.example.com,bar.example.com") +# +### +FROM registry.access.redhat.com/ubi8/openjdk-17:1.14 + +ENV LANGUAGE='en_US:en' + + +COPY target/lib/* /deployments/lib/ +COPY target/*-runner.jar /deployments/quarkus-run.jar + +EXPOSE 8080 +USER 185 +ENV JAVA_OPTS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" +ENV JAVA_APP_JAR="/deployments/quarkus-run.jar" diff --git a/src/main/docker/Dockerfile.native b/src/main/docker/Dockerfile.native new file mode 100644 index 0000000..4e076cf --- /dev/null +++ b/src/main/docker/Dockerfile.native @@ -0,0 +1,27 @@ +#### +# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode. +# +# Before building the container image run: +# +# ./mvnw package -Pnative +# +# Then, build the image with: +# +# docker build -f src/main/docker/Dockerfile.native -t quarkus/code-with-quarkus . +# +# Then run the container using: +# +# docker run -i --rm -p 8080:8080 quarkus/code-with-quarkus +# +### +FROM registry.access.redhat.com/ubi8/ubi-minimal:8.6 +WORKDIR /work/ +RUN chown 1001 /work \ + && chmod "g+rwX" /work \ + && chown 1001:root /work +COPY --chown=1001:root target/*-runner /work/application + +EXPOSE 8080 +USER 1001 + +CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] diff --git a/src/main/docker/Dockerfile.native-micro b/src/main/docker/Dockerfile.native-micro new file mode 100644 index 0000000..40afb1a --- /dev/null +++ b/src/main/docker/Dockerfile.native-micro @@ -0,0 +1,30 @@ +#### +# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode. +# It uses a micro base image, tuned for Quarkus native executables. +# It reduces the size of the resulting container image. +# Check https://quarkus.io/guides/quarkus-runtime-base-image for further information about this image. +# +# Before building the container image run: +# +# ./mvnw package -Pnative +# +# Then, build the image with: +# +# docker build -f src/main/docker/Dockerfile.native-micro -t quarkus/code-with-quarkus . +# +# Then run the container using: +# +# docker run -i --rm -p 8080:8080 quarkus/code-with-quarkus +# +### +FROM quay.io/quarkus/quarkus-micro-image:2.0 +WORKDIR /work/ +RUN chown 1001 /work \ + && chmod "g+rwX" /work \ + && chown 1001:root /work +COPY --chown=1001:root target/*-runner /work/application + +EXPOSE 8080 +USER 1001 + +CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] diff --git a/src/main/java/it/pagopa/swclient/mil/preset/ErrorCode.java b/src/main/java/it/pagopa/swclient/mil/preset/ErrorCode.java new file mode 100644 index 0000000..63ed212 --- /dev/null +++ b/src/main/java/it/pagopa/swclient/mil/preset/ErrorCode.java @@ -0,0 +1,43 @@ +/* + * ErrorCode.java + * + * 12 dec 2022 + */ + +package it.pagopa.swclient.mil.preset; + +/** + * + * @author Antonio Tarricone + */ +public final class ErrorCode { + public static final String MODULE_ID = "00A"; + + public static final String PATAX_CODE_MUST_NOT_BE_NULL = MODULE_ID + "000001"; + public static final String PATAX_CODE_MUST_MATCH_REGEXP = MODULE_ID + "000002"; + + public static final String ERROR_COMMUNICATION_MONGO_DB = MODULE_ID + "000003"; + + public static final String SUBSCRIBER_ID_MUST_NOT_BE_NULL = MODULE_ID + "000004"; + public static final String SUBSCRIBER_ID_MUST_MATCH_REGEXP = MODULE_ID + "000005"; + + public static final String ERROR_SUBSCRIBER_NOT_FOUND = MODULE_ID + "000006"; + + public static final String ERROR_STORING_TERMINAL_IN_DB = MODULE_ID + "000007"; + public static final String ERROR_CONFLICT_TERMINAL_IN_DB = MODULE_ID + "000008"; + + public static final String OPERATION_TYPE_MUST_NOT_BE_NULL = MODULE_ID + "000009"; + public static final String OPERATION_TYPE_MUST_MATCH_REGEXP = MODULE_ID + "00000A"; + + public static final String NOTICE_TAX_CODE_MUST_NOT_BE_NULL = MODULE_ID + "00000B"; + public static final String NOTICE_TAX_CODE_MUST_MATCH_REGEXP = MODULE_ID + "00000C"; + + public static final String NOTICE_NUMBER_MUST_NOT_BE_NULL = MODULE_ID + "00000D"; + public static final String NOTICE_NUMBER_MUST_MATCH_REGEXP = MODULE_ID + "00000E"; + + public static final String ERROR_PRESET_OPERATION_NOT_FOUND = MODULE_ID + "00000F"; + + private ErrorCode() { + + } +} diff --git a/src/main/java/it/pagopa/swclient/mil/preset/OperationType.java b/src/main/java/it/pagopa/swclient/mil/preset/OperationType.java new file mode 100644 index 0000000..9f7eb81 --- /dev/null +++ b/src/main/java/it/pagopa/swclient/mil/preset/OperationType.java @@ -0,0 +1,12 @@ +/** + * + */ +package it.pagopa.swclient.mil.preset; + +/** + * @author fabrizio.guerrini + * + */ +public enum OperationType { + PAYMENT_NOTICE +} diff --git a/src/main/java/it/pagopa/swclient/mil/preset/PresetStatus.java b/src/main/java/it/pagopa/swclient/mil/preset/PresetStatus.java new file mode 100644 index 0000000..5aa4dbb --- /dev/null +++ b/src/main/java/it/pagopa/swclient/mil/preset/PresetStatus.java @@ -0,0 +1,12 @@ +/** + * + */ +package it.pagopa.swclient.mil.preset; + +/** + * @author fabrizio.guerrini + * + */ +public enum PresetStatus { + TO_EXECUTE +} diff --git a/src/main/java/it/pagopa/swclient/mil/preset/bean/Notice.java b/src/main/java/it/pagopa/swclient/mil/preset/bean/Notice.java new file mode 100644 index 0000000..306b5a8 --- /dev/null +++ b/src/main/java/it/pagopa/swclient/mil/preset/bean/Notice.java @@ -0,0 +1,241 @@ +package it.pagopa.swclient.mil.preset.bean; + +import com.fasterxml.jackson.annotation.JsonInclude; + +import io.quarkus.runtime.annotations.RegisterForReflection; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; + +import com.fasterxml.jackson.annotation.JsonInclude.Include; + +/** + * Entity bean containing the data of a payment notice as returned by the activatePayment API of the node + */ +@RegisterForReflection +public class Notice { + + /** + * The payment token returned by the node + */ + @NotNull + @Pattern(regexp = "^[ -~]") + private String paymentToken; + + /** + * The tax code of the public administration + */ + @NotNull + @Pattern(regexp = "^[0-9]{11}$") + private String paTaxCode; + + /** + * The identifier of the payment notice + */ + @NotNull + @Pattern(regexp = "^[0-9]{18}$") + private String noticeNumber; + + /** + * The amount of the payment notice + */ + @Min(value = 1) + @Max(value = 99999999999L) + private Long amount; + + /** + * The description of the payment notice + */ + @Pattern(regexp = "^[ -~]") + @JsonInclude(Include.NON_NULL) + private String description; + + /** + * The company that issued the payment notice + */ + @Pattern(regexp = "^[ -~]") + @JsonInclude(Include.NON_NULL) + private String company; + + /** + * The office of the company that issued the payment notice + */ + @Pattern(regexp = "^[ -~]") + @JsonInclude(Include.NON_NULL) + private String office; + + /** + * The creditor identifier, as returned by the callback of the node after a successful payment + */ + @Pattern(regexp = "^[ -~]") + @JsonInclude(Include.NON_NULL) + private String creditorReferenceId; + + /** + * The debtor name, as returned by the callback of the node after a successful payment + */ + @Pattern(regexp = "^[ -~]") + @JsonInclude(Include.NON_NULL) + private String debtor; + + /** + * Gets paymentToken + * @return value of paymentToken + */ + public String getPaymentToken() { + return paymentToken; + } + + /** + * Sets paymentToken + * @param paymentToken value of paymentToken + */ + public void setPaymentToken(String paymentToken) { + this.paymentToken = paymentToken; + } + + /** + * Gets paTaxCode + * @return value of paTaxCode + */ + public String getPaTaxCode() { + return paTaxCode; + } + + /** + * Sets paTaxCode + * @param paTaxCode value of paTaxCode + */ + public void setPaTaxCode(String paTaxCode) { + this.paTaxCode = paTaxCode; + } + + /** + * Gets noticeNumber + * @return value of noticeNumber + */ + public String getNoticeNumber() { + return noticeNumber; + } + + /** + * Sets noticeNumber + * @param noticeNumber value of noticeNumber + */ + public void setNoticeNumber(String noticeNumber) { + this.noticeNumber = noticeNumber; + } + + /** + * Gets amount + * @return value of amount + */ + public Long getAmount() { + return amount; + } + + /** + * Sets amount + * @param amount value of amount + */ + public void setAmount(Long amount) { + this.amount = amount; + } + + /** + * Gets description + * @return value of description + */ + public String getDescription() { + return description; + } + + /** + * Sets description + * @param description value of description + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * Gets company + * @return value of company + */ + public String getCompany() { + return company; + } + + /** + * Sets company + * @param company value of company + */ + public void setCompany(String company) { + this.company = company; + } + + /** + * Gets office + * @return value of office + */ + public String getOffice() { + return office; + } + + /** + * Sets office + * @param office value of office + */ + public void setOffice(String office) { + this.office = office; + } + + /** + * Gets creditorReferenceId + * @return value of creditorReferenceId + */ + public String getCreditorReferenceId() { + return creditorReferenceId; + } + + /** + * Sets creditorReferenceId + * @param creditorReferenceId value of creditorReferenceId + */ + public void setCreditorReferenceId(String creditorReferenceId) { + this.creditorReferenceId = creditorReferenceId; + } + + /** + * Gets debtor + * @return value of debtor + */ + public String getDebtor() { + return debtor; + } + + /** + * Sets debtor + * @param debtor value of debtor + */ + public void setDebtor(String debtor) { + this.debtor = debtor; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("Notice{"); + sb.append("paymentToken='").append(paymentToken).append('\''); + sb.append(", paTaxCode='").append(paTaxCode).append('\''); + sb.append(", noticeNumber='").append(noticeNumber).append('\''); + sb.append(", amount=").append(amount); + sb.append(", description='").append(description).append('\''); + sb.append(", company='").append(company).append('\''); + sb.append(", office='").append(office).append('\''); + sb.append(", creditorReferenceId='").append(creditorReferenceId).append('\''); + sb.append(", debtor='").append(debtor).append('\''); + sb.append('}'); + return sb.toString(); + } +} diff --git a/src/main/java/it/pagopa/swclient/mil/preset/bean/PaymentTransaction.java b/src/main/java/it/pagopa/swclient/mil/preset/bean/PaymentTransaction.java new file mode 100644 index 0000000..4ae31fc --- /dev/null +++ b/src/main/java/it/pagopa/swclient/mil/preset/bean/PaymentTransaction.java @@ -0,0 +1,386 @@ +package it.pagopa.swclient.mil.preset.bean; + +import io.quarkus.runtime.annotations.RegisterForReflection; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; + +/** + * Entity bean containing the data of a payment transaction + */ +@RegisterForReflection +public class PaymentTransaction { + + /** + * The identifier of the payment transaction + */ + @NotNull + @Pattern(regexp = "^[a-zA-Z0-9]{32}$") + private String transactionId; + + /** + * The identifier of the acquirer, passed by the client + */ + @NotNull + @Pattern(regexp = "^\\d{1,11}$") + private String acquirerId; + + /** + * The channel used for the payment, passed by the client + */ + @NotNull + @Pattern(regexp = "ATM|POS|TOTEM|CASH_REGISTER|CSA") + private String channel; + + /** + * The identifier of the merchant, passed by the client + */ + @Pattern(regexp = "^[0-9a-zA-Z]{1,15}$") + @JsonInclude(Include.NON_NULL) + private String merchantId; + + /** + * The identifier of the terminal, passed by the client + */ + @NotNull + @Pattern(regexp = "^[0-9a-zA-Z]{1,8}$") + private String terminalId; + + /** + * The timestamp of the transaction creation on the DB + */ + @NotNull + @Max(value = 19) + private String insertTimestamp; + + /** + * The list of notices paid in this transaction + */ + @NotNull + private List notices; + + /** + * The total amount of the payment notices, calculated by the MIL + */ + @Min(value = 1) + @Max(value = 99999999999L) + private long totalAmount; + + /** + * The total fee for the payment transaction, retrieved by GEC and passed by the client + */ + @Min(value = 1) + @Max(value = 99999999999L) + @JsonInclude(Include.NON_NULL) + private Long fee; + + /** + * The status of this payment transaction. Can be one of {@link PaymentTransactionStatus} + */ + @NotNull + @Pattern(regexp = "PRE_CLOSE|PENDING|ERROR_ON_CLOSE|CLOSED|ERROR_ON_RESULT|ERROR_ON_PAYMENT|ABORTED") + private String status; + + /** + * The payment method used for this transaction, passed by the client + */ + @Pattern(regexp = "PAGOBANCOMAT|DEBIT_CARD|CREDIT_CARD|PAYMENT_CARD|BANK_ACCOUNT|CASH") + @JsonInclude(Include.NON_NULL) + private String paymentMethod; + + /** + * Timestamp of the e-money transaction , passed by the client + */ + @Max(value = 19) + @JsonInclude(Include.NON_NULL) + private String paymentTimestamp; + + /** + * Timestamp of the call to the close API + */ + @Max(value = 19) + @JsonInclude(Include.NON_NULL) + private String closeTimestamp; + + /** + * Timestamp of the transaction payment, passed by the node in the callback + */ + @Max(value = 19) + @JsonInclude(Include.NON_NULL) + private String paymentDate; + + /** + * Timestamp of the call to the callback by the node + */ + @Max(value = 19) + @JsonInclude(Include.NON_NULL) + private String callbackTimestamp; + + /** + * Gets transactionId + * @return value of transactionId + */ + public String getTransactionId() { + return transactionId; + } + + /** + * Sets transactionId + * @param transactionId value of transactionId + */ + public void setTransactionId(String transactionId) { + this.transactionId = transactionId; + } + + /** + * Gets acquirerId + * @return value of acquirerId + */ + public String getAcquirerId() { + return acquirerId; + } + + /** + * Sets acquirerId + * @param acquirerId value of acquirerId + */ + public void setAcquirerId(String acquirerId) { + this.acquirerId = acquirerId; + } + + /** + * Gets channel + * @return value of channel + */ + public String getChannel() { + return channel; + } + + /** + * Sets channel + * @param channel value of channel + */ + public void setChannel(String channel) { + this.channel = channel; + } + + /** + * Gets merchantId + * @return value of merchantId + */ + public String getMerchantId() { + return merchantId; + } + + /** + * Sets merchantId + * @param merchantId value of merchantId + */ + public void setMerchantId(String merchantId) { + this.merchantId = merchantId; + } + + /** + * Gets terminalId + * @return value of terminalId + */ + public String getTerminalId() { + return terminalId; + } + + /** + * Sets terminalId + * @param terminalId value of terminalId + */ + public void setTerminalId(String terminalId) { + this.terminalId = terminalId; + } + + /** + * Gets insertTimestamp + * @return value of insertTimestamp + */ + public String getInsertTimestamp() { + return insertTimestamp; + } + + /** + * Sets insertTimestamp + * @param insertTimestamp value of insertTimestamp + */ + public void setInsertTimestamp(String insertTimestamp) { + this.insertTimestamp = insertTimestamp; + } + + /** + * Gets notices + * @return value of notices + */ + public List getNotices() { + return notices; + } + + /** + * Sets notices + * @param notices value of notices + */ + public void setNotices(List notices) { + this.notices = notices; + } + + /** + * Gets totalAmount + * @return value of totalAmount + */ + public long getTotalAmount() { + return totalAmount; + } + + /** + * Sets totalAmount + * @param totalAmount value of totalAmount + */ + public void setTotalAmount(long totalAmount) { + this.totalAmount = totalAmount; + } + + /** + * Gets fee + * @return value of fee + */ + public Long getFee() { + return fee; + } + + /** + * Sets fee + * @param fee value of fee + */ + public void setFee(Long fee) { + this.fee = fee; + } + + /** + * Gets status + * @return value of status + */ + public String getStatus() { + return status; + } + + /** + * Sets status + * @param status value of status + */ + public void setStatus(String status) { + this.status = status; + } + + /** + * Gets paymentMethod + * @return value of paymentMethod + */ + public String getPaymentMethod() { + return paymentMethod; + } + + /** + * Sets paymentMethod + * @param paymentMethod value of paymentMethod + */ + public void setPaymentMethod(String paymentMethod) { + this.paymentMethod = paymentMethod; + } + + /** + * Gets paymentTimestamp + * @return value of paymentTimestamp + */ + public String getPaymentTimestamp() { + return paymentTimestamp; + } + + /** + * Sets paymentTimestamp + * @param paymentTimestamp value of paymentTimestamp + */ + public void setPaymentTimestamp(String paymentTimestamp) { + this.paymentTimestamp = paymentTimestamp; + } + + /** + * Gets closeTimestamp + * @return value of closeTimestamp + */ + public String getCloseTimestamp() { + return closeTimestamp; + } + + /** + * Sets closeTimestamp + * @param closeTimestamp value of closeTimestamp + */ + public void setCloseTimestamp(String closeTimestamp) { + this.closeTimestamp = closeTimestamp; + } + + /** + * Gets paymentDate + * @return value of paymentDate + */ + public String getPaymentDate() { + return paymentDate; + } + + /** + * Sets paymentDate + * @param paymentDate value of paymentDate + */ + public void setPaymentDate(String paymentDate) { + this.paymentDate = paymentDate; + } + + /** + * Gets callbackTimestamp + * @return value of callbackTimestamp + */ + public String getCallbackTimestamp() { + return callbackTimestamp; + } + + /** + * Sets callbackTimestamp + * @param callbackTimestamp value of callbackTimestamp + */ + public void setCallbackTimestamp(String callbackTimestamp) { + this.callbackTimestamp = callbackTimestamp; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("PaymentTransaction{"); + sb.append("transactionId='").append(transactionId).append('\''); + sb.append(", acquirerId='").append(acquirerId).append('\''); + sb.append(", channel='").append(channel).append('\''); + sb.append(", merchantId='").append(merchantId).append('\''); + sb.append(", terminalId='").append(terminalId).append('\''); + sb.append(", insertTimestamp='").append(insertTimestamp).append('\''); + sb.append(", notices=").append(notices); + sb.append(", totalAmount=").append(totalAmount); + sb.append(", fee=").append(fee); + sb.append(", status='").append(status).append('\''); + sb.append(", paymentMethod='").append(paymentMethod).append('\''); + sb.append(", paymentTimestamp='").append(paymentTimestamp).append('\''); + sb.append(", closeTimestamp='").append(closeTimestamp).append('\''); + sb.append(", paymentDate='").append(paymentDate).append('\''); + sb.append(", callbackTimestamp='").append(callbackTimestamp).append('\''); + sb.append('}'); + return sb.toString(); + } +} diff --git a/src/main/java/it/pagopa/swclient/mil/preset/bean/PresetHeaders.java b/src/main/java/it/pagopa/swclient/mil/preset/bean/PresetHeaders.java new file mode 100644 index 0000000..a229fbc --- /dev/null +++ b/src/main/java/it/pagopa/swclient/mil/preset/bean/PresetHeaders.java @@ -0,0 +1,68 @@ +/** + * + */ +package it.pagopa.swclient.mil.preset.bean; + +import it.pagopa.swclient.mil.ErrorCode; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; +import jakarta.ws.rs.HeaderParam; + +public class PresetHeaders { + /* + * Request ID + */ + @HeaderParam("RequestId") + @NotNull(message = ErrorCode.REQUEST_ID_MUST_NOT_BE_NULL_MSG) + @Pattern(regexp = "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$", message = ErrorCode.REQUEST_ID_MUST_MATCH_REGEXP_MSG) + private String requestId; + + /* + * Version of the required API + */ + @HeaderParam("Version") + @Size(max = 64, message = ErrorCode.VERSION_SIZE_MUST_BE_AT_MOST_MAX_MSG) + @Pattern(regexp = "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$", message = ErrorCode.VERSION_MUST_MATCH_REGEXP_MSG) + private String version; + + /** + * @return the requestId + */ + public String getRequestId() { + return requestId; + } + + /** + * @param requestId the requestId to set + */ + public void setRequestId(String requestId) { + this.requestId = requestId; + } + + /** + * @return the version + */ + public String getVersion() { + return version; + } + + /** + * @param version the version to set + */ + public void setVersion(String version) { + this.version = version; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("PresetHeaders [requestId="); + builder.append(requestId); + builder.append(", version="); + builder.append(version); + builder.append("]"); + return builder.toString(); + } + +} diff --git a/src/main/java/it/pagopa/swclient/mil/preset/bean/PresetRequest.java b/src/main/java/it/pagopa/swclient/mil/preset/bean/PresetRequest.java new file mode 100644 index 0000000..7579c85 --- /dev/null +++ b/src/main/java/it/pagopa/swclient/mil/preset/bean/PresetRequest.java @@ -0,0 +1,136 @@ +/** + * + */ +package it.pagopa.swclient.mil.preset.bean; + +import it.pagopa.swclient.mil.preset.ErrorCode; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; + +public class PresetRequest { + + /* + * Operation of payment of a notice + */ + @NotNull(message = "[" + ErrorCode.PATAX_CODE_MUST_NOT_BE_NULL + "] operationType must not be null") + @Pattern(regexp = "PAYMENT_NOTICE", message = "[" + ErrorCode.OPERATION_TYPE_MUST_MATCH_REGEXP + "] operationType must match \"{regexp}\"") + private String operationType; + + + /* + * Tax code of the creditor company + */ + @NotNull(message = "[" + ErrorCode.PATAX_CODE_MUST_NOT_BE_NULL + "] paTaxCode must not be null") + @Pattern(regexp = "^[0-9]{11}$", message = "[" + ErrorCode.PATAX_CODE_MUST_MATCH_REGEXP + "] paTaxCode must match \"{regexp}\"") + private String paTaxCode; + + + /* + * Subscriber ID + */ + @NotNull(message = "[" + ErrorCode.SUBSCRIBER_ID_MUST_NOT_BE_NULL + "] subscriberId must not be null") + @Pattern(regexp = "^[0-9a-z]{6}$", message = "[" + ErrorCode.SUBSCRIBER_ID_MUST_MATCH_REGEXP + "] subscriberId must match \"{regexp}\"") + private String subscriberId; + + + /* + * Tax code of the creditor company + */ + @NotNull(message = "[" + ErrorCode.NOTICE_TAX_CODE_MUST_NOT_BE_NULL + "] noticeTaxCode must not be null") + @Pattern(regexp = "^[0-9]{11}$", message = "[" + ErrorCode.NOTICE_TAX_CODE_MUST_MATCH_REGEXP + "] noticeTaxCode must match \"{regexp}\"") + private String noticeTaxCode; + + /* + * Notice number + */ + @NotNull(message = "[" + ErrorCode.SUBSCRIBER_ID_MUST_NOT_BE_NULL + "] noticeNumber must not be null") + @Pattern(regexp = "^[0-9]{18}$", message = "[" + ErrorCode.SUBSCRIBER_ID_MUST_MATCH_REGEXP + "] noticeNumber must match \"{regexp}\"") + private String noticeNumber; + + /** + * @return the operationType + */ + public String getOperationType() { + return operationType; + } + + /** + * @param operationType the operationType to set + */ + public void setOperationType(String operationType) { + this.operationType = operationType; + } + + /** + * @return the paTaxCode + */ + public String getPaTaxCode() { + return paTaxCode; + } + + /** + * @param paTaxCode the paTaxCode to set + */ + public void setPaTaxCode(String paTaxCode) { + this.paTaxCode = paTaxCode; + } + + /** + * @return the subscriberId + */ + public String getSubscriberId() { + return subscriberId; + } + + /** + * @param subscriberId the subscriberId to set + */ + public void setSubscriberId(String subscriberId) { + this.subscriberId = subscriberId; + } + + /** + * @return the noticeTaxCode + */ + public String getNoticeTaxCode() { + return noticeTaxCode; + } + + /** + * @param noticeTaxCode the noticeTaxCode to set + */ + public void setNoticeTaxCode(String noticeTaxCode) { + this.noticeTaxCode = noticeTaxCode; + } + + /** + * @return the noticeNumber + */ + public String getNoticeNumber() { + return noticeNumber; + } + + /** + * @param noticeNumber the noticeNumber to set + */ + public void setNoticeNumber(String noticeNumber) { + this.noticeNumber = noticeNumber; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("PresetRequest [operationType="); + builder.append(operationType); + builder.append(", paTaxCode="); + builder.append(paTaxCode); + builder.append(", subscriberId="); + builder.append(subscriberId); + builder.append(", noticeTaxCode="); + builder.append(noticeTaxCode); + builder.append(", noticeNumber="); + builder.append(noticeNumber); + builder.append("]"); + return builder.toString(); + } +} diff --git a/src/main/java/it/pagopa/swclient/mil/preset/bean/PresetResponse.java b/src/main/java/it/pagopa/swclient/mil/preset/bean/PresetResponse.java new file mode 100644 index 0000000..e306516 --- /dev/null +++ b/src/main/java/it/pagopa/swclient/mil/preset/bean/PresetResponse.java @@ -0,0 +1,247 @@ +/** + * + */ +package it.pagopa.swclient.mil.preset.bean; + +import io.quarkus.runtime.annotations.RegisterForReflection; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; + +@RegisterForReflection +public class PresetResponse { + /* + * Operation type + */ + @NotNull + @Pattern(regexp = "PAYMENT_NOTICE") + public String operationType; + + /* + * Preset Id + */ + @NotNull + @Pattern(regexp = "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$") + private String presetId; + + /* + * Tax code of the creditor company + */ + @NotNull + @Pattern(regexp = "^[0-9]{11}$") + private String paTaxCode; + + /* + * Subscriber ID + */ + @NotNull + @Pattern(regexp = "^[0-9a-z]{6}$") + private String subscriberId; + + /* + * Creation timestamp + */ + @NotNull + @Max(value = 19) + private String creationTimestamp; + + /* + * Status + */ + @Pattern(regexp = "TO_EXECUTE|EXECUTED") + private String status; + + /* + * Status timestamp + */ + @NotNull + @Max(value = 19) + private String statusTimestamp; + + /* + * Tax code of the creditor company + */ + @NotNull + @Pattern(regexp = "^[0-9]{11}$") + private String noticeTaxCode; + + /* + * Notice number + */ + @NotNull + @Pattern(regexp = "^[0-9]{18}$") + private String noticeNumber; + + /* + * Payment status + */ + @NotNull + private PaymentTransaction statusDetails; + + /** + * @return the operationType + */ + public String getOperationType() { + return operationType; + } + + /** + * @param operationType the operationType to set + */ + public void setOperationType(String operationType) { + this.operationType = operationType; + } + + /** + * @return the presetId + */ + public String getPresetId() { + return presetId; + } + + /** + * @param presetId the presetId to set + */ + public void setPresetId(String presetId) { + this.presetId = presetId; + } + + /** + * @return the paTaxCode + */ + public String getPaTaxCode() { + return paTaxCode; + } + + /** + * @param paTaxCode the paTaxCode to set + */ + public void setPaTaxCode(String paTaxCode) { + this.paTaxCode = paTaxCode; + } + + /** + * @return the subscriberId + */ + public String getSubscriberId() { + return subscriberId; + } + + /** + * @param subscriberId the subscriberId to set + */ + public void setSubscriberId(String subscriberId) { + this.subscriberId = subscriberId; + } + + /** + * @return the creationTimestamp + */ + public String getCreationTimestamp() { + return creationTimestamp; + } + + /** + * @param creationTimestamp the creationTimestamp to set + */ + public void setCreationTimestamp(String creationTimestamp) { + this.creationTimestamp = creationTimestamp; + } + + /** + * @return the status + */ + public String getStatus() { + return status; + } + + /** + * @param status the status to set + */ + public void setStatus(String status) { + this.status = status; + } + + /** + * @return the statusTimestamp + */ + public String getStatusTimestamp() { + return statusTimestamp; + } + + /** + * @param statusTimestamp the statusTimestamp to set + */ + public void setStatusTimestamp(String statusTimestamp) { + this.statusTimestamp = statusTimestamp; + } + + /** + * @return the noticeTaxCode + */ + public String getNoticeTaxCode() { + return noticeTaxCode; + } + + /** + * @param noticeTaxCode the noticeTaxCode to set + */ + public void setNoticeTaxCode(String noticeTaxCode) { + this.noticeTaxCode = noticeTaxCode; + } + + /** + * @return the noticeNumber + */ + public String getNoticeNumber() { + return noticeNumber; + } + + /** + * @param noticeNumber the noticeNumber to set + */ + public void setNoticeNumber(String noticeNumber) { + this.noticeNumber = noticeNumber; + } + + /** + * @return the statusDetails + */ + public PaymentTransaction getStatusDetails() { + return statusDetails; + } + + /** + * @param statusDetails the statusDetails to set + */ + public void setStatusDetails(PaymentTransaction statusDetails) { + this.statusDetails = statusDetails; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("PresetResponse [operationType="); + builder.append(operationType); + builder.append(", presetId="); + builder.append(presetId); + builder.append(", paTaxCode="); + builder.append(paTaxCode); + builder.append(", subscriberId="); + builder.append(subscriberId); + builder.append(", creationTimestamp="); + builder.append(creationTimestamp); + builder.append(", status="); + builder.append(status); + builder.append(", statusTimestamp="); + builder.append(statusTimestamp); + builder.append(", noticeTaxCode="); + builder.append(noticeTaxCode); + builder.append(", noticeNumber="); + builder.append(noticeNumber); + builder.append(", statusDetails="); + builder.append(statusDetails); + builder.append("]"); + return builder.toString(); + } +} diff --git a/src/main/java/it/pagopa/swclient/mil/preset/bean/PresetsPathParam.java b/src/main/java/it/pagopa/swclient/mil/preset/bean/PresetsPathParam.java new file mode 100644 index 0000000..605ea76 --- /dev/null +++ b/src/main/java/it/pagopa/swclient/mil/preset/bean/PresetsPathParam.java @@ -0,0 +1,64 @@ +package it.pagopa.swclient.mil.preset.bean; + +import it.pagopa.swclient.mil.preset.ErrorCode; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; +import jakarta.ws.rs.PathParam; + +public class PresetsPathParam { + + /* + * Tax code of the creditor company + */ + @PathParam(value = "paTaxCode") + @NotNull(message = "[" + ErrorCode.PATAX_CODE_MUST_NOT_BE_NULL + "] paTaxCode must not be null") + @Pattern(regexp = "^[0-9]{11}$", message = "[" + ErrorCode.PATAX_CODE_MUST_MATCH_REGEXP + "] paTaxCode must match \"{regexp}\"") + private String paTaxCode; + + /* + * Subscriber ID + */ + @PathParam(value = "subscriberId") + @NotNull(message = "[" + ErrorCode.SUBSCRIBER_ID_MUST_NOT_BE_NULL + "] subscriberId must not be null") + @Pattern(regexp = "^[0-9a-z]{6}$", message = "[" + ErrorCode.SUBSCRIBER_ID_MUST_MATCH_REGEXP + "] subscriberId must match \"{regexp}\"") + private String subscriberId; + + /** + * @return the paTaxCode + */ + public String getPaTaxCode() { + return paTaxCode; + } + + /** + * @param paTaxCode the paTaxCode to set + */ + public void setPaTaxCode(String paTaxCode) { + this.paTaxCode = paTaxCode; + } + + /** + * @return the subscriberId + */ + public String getSubscriberId() { + return subscriberId; + } + + /** + * @param subscriberId the subscriberId to set + */ + public void setSubscriberId(String subscriberId) { + this.subscriberId = subscriberId; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("PresetsPathParam [paTaxCode="); + builder.append(paTaxCode); + builder.append(", subscriberId="); + builder.append(subscriberId); + builder.append("]"); + return builder.toString(); + } +} diff --git a/src/main/java/it/pagopa/swclient/mil/preset/bean/PresetsResponse.java b/src/main/java/it/pagopa/swclient/mil/preset/bean/PresetsResponse.java new file mode 100644 index 0000000..6e41224 --- /dev/null +++ b/src/main/java/it/pagopa/swclient/mil/preset/bean/PresetsResponse.java @@ -0,0 +1,41 @@ +/** + * + */ +package it.pagopa.swclient.mil.preset.bean; + +import java.util.List; + +import io.quarkus.runtime.annotations.RegisterForReflection; +import jakarta.validation.constraints.NotNull; + +@RegisterForReflection +public class PresetsResponse { + /* + * List of preset operations + */ + @NotNull + private List presets; + + /** + * @return the presets + */ + public List getPresets() { + return presets; + } + + /** + * @param presets the presets to set + */ + public void setPresets(List presets) { + this.presets = presets; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("PresetsResponse [presets="); + builder.append(presets); + builder.append("]"); + return builder.toString(); + } +} diff --git a/src/main/java/it/pagopa/swclient/mil/preset/bean/SubcribersResponse.java b/src/main/java/it/pagopa/swclient/mil/preset/bean/SubcribersResponse.java new file mode 100644 index 0000000..720ea78 --- /dev/null +++ b/src/main/java/it/pagopa/swclient/mil/preset/bean/SubcribersResponse.java @@ -0,0 +1,42 @@ +/** + * + */ +package it.pagopa.swclient.mil.preset.bean; + +import java.util.ArrayList; +import java.util.List; + +import io.quarkus.runtime.annotations.RegisterForReflection; +import jakarta.validation.constraints.NotNull; + +@RegisterForReflection +public class SubcribersResponse { + /* + * List of subscribed terminals + */ + @NotNull + private List subscribers = new ArrayList<>(); + + /** + * @return the subscribers + */ + public List getSubscribers() { + return subscribers; + } + + /** + * @param subscriberResponses the subscribers to set + */ + public void setSubscribers(List subscriberResponses) { + this.subscribers = subscriberResponses; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("SubcribersResponse [subscribers="); + builder.append(subscribers); + builder.append("]"); + return builder.toString(); + } +} diff --git a/src/main/java/it/pagopa/swclient/mil/preset/bean/SubscriberRequest.java b/src/main/java/it/pagopa/swclient/mil/preset/bean/SubscriberRequest.java new file mode 100644 index 0000000..263a03d --- /dev/null +++ b/src/main/java/it/pagopa/swclient/mil/preset/bean/SubscriberRequest.java @@ -0,0 +1,61 @@ +/** + * + */ +package it.pagopa.swclient.mil.preset.bean; + +import it.pagopa.swclient.mil.preset.ErrorCode; +import jakarta.validation.constraints.Pattern; + +public class SubscriberRequest { + /* + * Tax code of the creditor company + */ + @Pattern(regexp = "^[0-9]{11}$", message = "[" + ErrorCode.PATAX_CODE_MUST_MATCH_REGEXP + "] paTaxCode must match \"{regexp}\"") + private String paTaxCode; + + /* + * Mnemonic terminal label + */ + @Pattern(regexp = "^[\\u0001-\\uD7FF\\uE000-\\uFFFD\\u10000-\\u10FFFF]{1,256}$") + private String label; + + /** + * @return the paTaxCode + */ + public String getPaTaxCode() { + return paTaxCode; + } + + /** + * @param paTaxCode the paTaxCode to set + */ + public void setPaTaxCode(String paTaxCode) { + this.paTaxCode = paTaxCode; + } + + /** + * @return the label + */ + public String getLabel() { + return label; + } + + /** + * @param label the label to set + */ + public void setLabel(String label) { + this.label = label; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("SubscriberRequest [paTaxCode="); + builder.append(paTaxCode); + builder.append(", label="); + builder.append(label); + builder.append("]"); + return builder.toString(); + } + +} diff --git a/src/main/java/it/pagopa/swclient/mil/preset/bean/SubscriberResponse.java b/src/main/java/it/pagopa/swclient/mil/preset/bean/SubscriberResponse.java new file mode 100644 index 0000000..1a22113 --- /dev/null +++ b/src/main/java/it/pagopa/swclient/mil/preset/bean/SubscriberResponse.java @@ -0,0 +1,228 @@ +/** + * + */ +package it.pagopa.swclient.mil.preset.bean; + +import io.quarkus.runtime.annotations.RegisterForReflection; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; + +@RegisterForReflection +public class SubscriberResponse { + + /* + * Acquirer ID assigned by PagoPA + */ + @NotNull + @Pattern(regexp = "^\\d{1,11}$") + public String acquirerId; + + /* + * Channel originating the request + */ + @NotNull + @Pattern(regexp = "[ATM|POS|TOTEM|CASH_REGISTER|CSA]") + private String channel; + + /* + * Merchant ID. Mandatory when Channel equals POS + */ + @NotNull + @Pattern(regexp = "^[0-9a-zA-Z]") + private String merchantId; + + /* + * ID of the terminal originating the transaction. It must be unique per acquirer and channel. + */ + @NotNull + @Pattern(regexp = "^[0-9a-zA-Z]{1,8}$") + private String terminalId; + + /* + * Tax code of the creditor company + */ + @NotNull + @Pattern(regexp = "^[0-9]{11}$") + private String paTaxCode; + + /* + * Subscriber ID + */ + @NotNull + @Pattern(regexp = "^[0-9a-z]{6}$") + private String subscriberId; + + + /* + * Mnemonic terminal label + */ + @NotNull + @Pattern(regexp = "^[\\u0001-\\uD7FF\\uE000-\\uFFFD\\u10000-\\u10FFFF]{1,256}$") + private String label; + + /* + * Subscription timestamp + */ + @NotNull + @Max(value = 19) + private String subscriptionTimestamp; + + /* + * Last usage timestamp + */ + @NotNull + @Max(value = 19) + private String lastUsageTimestamp; + + /** + * @return the acquirerId + */ + public String getAcquirerId() { + return acquirerId; + } + + /** + * @param acquirerId the acquirerId to set + */ + public void setAcquirerId(String acquirerId) { + this.acquirerId = acquirerId; + } + + /** + * @return the channel + */ + public String getChannel() { + return channel; + } + + /** + * @param channel the channel to set + */ + public void setChannel(String channel) { + this.channel = channel; + } + + /** + * @return the merchantId + */ + public String getMerchantId() { + return merchantId; + } + + /** + * @param merchantId the merchantId to set + */ + public void setMerchantId(String merchantId) { + this.merchantId = merchantId; + } + + /** + * @return the terminalId + */ + public String getTerminalId() { + return terminalId; + } + + /** + * @param terminalId the terminalId to set + */ + public void setTerminalId(String terminalId) { + this.terminalId = terminalId; + } + + /** + * @return the paTaxCode + */ + public String getPaTaxCode() { + return paTaxCode; + } + + /** + * @param paTaxCode the paTaxCode to set + */ + public void setPaTaxCode(String paTaxCode) { + this.paTaxCode = paTaxCode; + } + + /** + * @return the subscriberId + */ + public String getSubscriberId() { + return subscriberId; + } + + /** + * @param subscriberId the subscriberId to set + */ + public void setSubscriberId(String subscriberId) { + this.subscriberId = subscriberId; + } + + /** + * @return the label + */ + public String getLabel() { + return label; + } + + /** + * @param label the label to set + */ + public void setLabel(String label) { + this.label = label; + } + + /** + * @return the subscriptionTimestamp + */ + public String getSubscriptionTimestamp() { + return subscriptionTimestamp; + } + + /** + * @param subscriptionTimestamp the subscriptionTimestamp to set + */ + public void setSubscriptionTimestamp(String subscriptionTimestamp) { + this.subscriptionTimestamp = subscriptionTimestamp; + } + + /** + * @return the lastUsageTimestamp + */ + public String getLastUsageTimestamp() { + return lastUsageTimestamp; + } + + /** + * @param lastUsageTimestamp the lastUsageTimestamp to set + */ + public void setLastUsageTimestamp(String lastUsageTimestamp) { + this.lastUsageTimestamp = lastUsageTimestamp; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("SubscribersResponse [acquirerId="); + builder.append(acquirerId); + builder.append(", channel="); + builder.append(channel); + builder.append(", merchantId="); + builder.append(merchantId); + builder.append(", terminalId="); + builder.append(terminalId); + builder.append(", paTaxCode="); + builder.append(paTaxCode); + builder.append(", subscriberId="); + builder.append(subscriberId); + builder.append(", label="); + builder.append(label); + builder.append(", subscriptionTimestamp="); + builder.append(subscriptionTimestamp); + builder.append(", lastUsageTimestamp="); + builder.append(lastUsageTimestamp); + builder.append("]"); + return builder.toString(); + } +} diff --git a/src/main/java/it/pagopa/swclient/mil/preset/bean/SubscribersPathParam.java b/src/main/java/it/pagopa/swclient/mil/preset/bean/SubscribersPathParam.java new file mode 100644 index 0000000..7c12bcd --- /dev/null +++ b/src/main/java/it/pagopa/swclient/mil/preset/bean/SubscribersPathParam.java @@ -0,0 +1,41 @@ +package it.pagopa.swclient.mil.preset.bean; + +import it.pagopa.swclient.mil.preset.ErrorCode; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; +import jakarta.ws.rs.PathParam; + +public class SubscribersPathParam { + + /* + * Tax code of the creditor company + */ + @PathParam(value = "paTaxCode") + @NotNull(message = "[" + ErrorCode.PATAX_CODE_MUST_NOT_BE_NULL + "] paTaxCode must not be null") + @Pattern(regexp = "^[0-9]{11}$", message = "[" + ErrorCode.PATAX_CODE_MUST_MATCH_REGEXP + "] paTaxCode must match \"{regexp}\"") + private String paTaxCode; + + /** + * @return the paTaxCode + */ + public String getPaTaxCode() { + return paTaxCode; + } + + /** + * @param paTaxCode the paTaxCode to set + */ + public void setPaTaxCode(String paTaxCode) { + this.paTaxCode = paTaxCode; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("SubscribersPathParam [paTaxCode="); + builder.append(paTaxCode); + builder.append("]"); + return builder.toString(); + } + +} diff --git a/src/main/java/it/pagopa/swclient/mil/preset/bean/UnsubscriberHeaders.java b/src/main/java/it/pagopa/swclient/mil/preset/bean/UnsubscriberHeaders.java new file mode 100644 index 0000000..680e9db --- /dev/null +++ b/src/main/java/it/pagopa/swclient/mil/preset/bean/UnsubscriberHeaders.java @@ -0,0 +1,156 @@ +/** + * + */ +package it.pagopa.swclient.mil.preset.bean; + +import it.pagopa.swclient.mil.ErrorCode; +import it.pagopa.swclient.mil.bean.Channel; +import it.pagopa.swclient.mil.preset.validation.constraints.MerchantIdNotNullForPos; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; +import jakarta.ws.rs.HeaderParam; + +@MerchantIdNotNullForPos(message = ErrorCode.MERCHANT_ID_MUST_NOT_BE_NULL_FOR_POS_MSG) +public class UnsubscriberHeaders { + /* + * Request ID + */ + @HeaderParam("RequestId") + @NotNull(message = ErrorCode.REQUEST_ID_MUST_NOT_BE_NULL_MSG) + @Pattern(regexp = "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$", message = ErrorCode.REQUEST_ID_MUST_MATCH_REGEXP_MSG) + private String requestId; + + /* + * Version of the required API + */ + @HeaderParam("Version") + @Size(max = 64, message = ErrorCode.VERSION_SIZE_MUST_BE_AT_MOST_MAX_MSG) + @Pattern(regexp = "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$", message = ErrorCode.VERSION_MUST_MATCH_REGEXP_MSG) + private String version; + + /* + * Acquirer ID assigned by PagoPA + */ + @HeaderParam("AcquirerId") + @Pattern(regexp = "^\\d{1,11}$", message = ErrorCode.ACQUIRER_ID_MUST_MATCH_REGEXP_MSG) + private String acquirerId; + + /* + * Channel originating the request + */ + @HeaderParam("Channel") + @Pattern(regexp = "^(" + Channel.ATM + "|" + Channel.POS + "|" + Channel.TOTEM + "|" + Channel.CASH_REGISTER + "|" + Channel.CSA + ")$", message = ErrorCode.CHANNEL_MUST_MATCH_REGEXP_MSG) + private String channel; + + /* + * Merchant ID originating the transaction. If Channel equals to POS, MerchantId must not be null. + */ + @HeaderParam("MerchantId") + @Pattern(regexp = "^[0-9a-zA-Z]{1,15}$", message = ErrorCode.MERCHANT_ID_MUST_MATCH_REGEXP_MSG) + private String merchantId; + + /* + * ID of the terminal originating the transaction. It must be unique per acquirer, channel and + * merchant if present. + */ + @HeaderParam("TerminalId") + @Pattern(regexp = "^[0-9a-zA-Z]{1,8}$", message = ErrorCode.TERMINAL_ID_MUST_MATCH_REGEXP_MSG) + private String terminalId; + + /** + * @return the requestId + */ + public String getRequestId() { + return requestId; + } + + /** + * @param requestId the requestId to set + */ + public void setRequestId(String requestId) { + this.requestId = requestId; + } + + /** + * @return the version + */ + public String getVersion() { + return version; + } + + /** + * @param version the version to set + */ + public void setVersion(String version) { + this.version = version; + } + + /** + * @return the acquirerId + */ + public String getAcquirerId() { + return acquirerId; + } + + /** + * @param acquirerId the acquirerId to set + */ + public void setAcquirerId(String acquirerId) { + this.acquirerId = acquirerId; + } + + /** + * @return the channel + */ + public String getChannel() { + return channel; + } + + /** + * @param channel the channel to set + */ + public void setChannel(String channel) { + this.channel = channel; + } + + /** + * @return the merchantId + */ + public String getMerchantId() { + return merchantId; + } + + /** + * @param merchantId the merchantId to set + */ + public void setMerchantId(String merchantId) { + this.merchantId = merchantId; + } + + /** + * @return the terminalId + */ + public String getTerminalId() { + return terminalId; + } + + /** + * @param terminalId the terminalId to set + */ + public void setTerminalId(String terminalId) { + this.terminalId = terminalId; + } + + @Override + public String toString() { + return new StringBuilder("CommonHeader [requestId=").append(requestId) + .append(", version=").append(version) + .append(", acquirerId=").append(acquirerId) + .append(", channel=").append(channel) + .append(", merchantId=").append(merchantId) + .append(", terminalId=").append(terminalId) + .append("]") + .toString(); + } +} diff --git a/src/main/java/it/pagopa/swclient/mil/preset/bean/UnsubscriberPathParam.java b/src/main/java/it/pagopa/swclient/mil/preset/bean/UnsubscriberPathParam.java new file mode 100644 index 0000000..f91beb1 --- /dev/null +++ b/src/main/java/it/pagopa/swclient/mil/preset/bean/UnsubscriberPathParam.java @@ -0,0 +1,64 @@ +package it.pagopa.swclient.mil.preset.bean; + +import it.pagopa.swclient.mil.preset.ErrorCode; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; +import jakarta.ws.rs.PathParam; + +public class UnsubscriberPathParam { + + /* + * Tax code of the creditor company + */ + @PathParam(value = "paTaxCode") + @NotNull(message = "[" + ErrorCode.PATAX_CODE_MUST_NOT_BE_NULL + "] paTaxCode must not be null") + @Pattern(regexp = "^[0-9]{11}$", message = "[" + ErrorCode.PATAX_CODE_MUST_MATCH_REGEXP + "] paTaxCode must match \"{regexp}\"") + private String paTaxCode; + + /* + * ID assigned to subscribed terminal + */ + @PathParam(value = "subscriberId") + @NotNull(message = "[" + ErrorCode.SUBSCRIBER_ID_MUST_NOT_BE_NULL + "] subscriberId must not be null") + @Pattern(regexp = "^[0-9a-z]{6}$", message = "[" + ErrorCode.SUBSCRIBER_ID_MUST_MATCH_REGEXP + "] subscriberId must match \"{regexp}\"") + private String subscriberId; + + /** + * @return the paTaxCode + */ + public String getPaTaxCode() { + return paTaxCode; + } + + /** + * @param paTaxCode the paTaxCode to set + */ + public void setPaTaxCode(String paTaxCode) { + this.paTaxCode = paTaxCode; + } + + /** + * @return the subscriberId + */ + public String getSubscriberId() { + return subscriberId; + } + + /** + * @param subscriberId the subscriberId to set + */ + public void setSubscriberId(String subscriberId) { + this.subscriberId = subscriberId; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("UnsubscriberPathParam [paTaxCode="); + builder.append(paTaxCode); + builder.append(", subscriberId="); + builder.append(subscriberId); + builder.append("]"); + return builder.toString(); + } +} diff --git a/src/main/java/it/pagopa/swclient/mil/preset/dao/PresetRepository.java b/src/main/java/it/pagopa/swclient/mil/preset/dao/PresetRepository.java new file mode 100644 index 0000000..7e1b2ee --- /dev/null +++ b/src/main/java/it/pagopa/swclient/mil/preset/dao/PresetRepository.java @@ -0,0 +1,12 @@ +package it.pagopa.swclient.mil.preset.dao; + +import io.quarkus.mongodb.panache.reactive.ReactivePanacheMongoRepository; +import jakarta.enterprise.context.ApplicationScoped; + +/** + * MongoDB repository to access the preset information, reactive flavor + */ +@ApplicationScoped +public class PresetRepository implements ReactivePanacheMongoRepository { + +} \ No newline at end of file diff --git a/src/main/java/it/pagopa/swclient/mil/preset/dao/PresetsEntity.java b/src/main/java/it/pagopa/swclient/mil/preset/dao/PresetsEntity.java new file mode 100644 index 0000000..b9b3b20 --- /dev/null +++ b/src/main/java/it/pagopa/swclient/mil/preset/dao/PresetsEntity.java @@ -0,0 +1,222 @@ +package it.pagopa.swclient.mil.preset.dao; + +import org.bson.codecs.pojo.annotations.BsonId; + +import io.quarkus.mongodb.panache.common.MongoEntity; +import it.pagopa.swclient.mil.preset.bean.PaymentTransaction; + +/** + * Entity of the Preset service + */ +@MongoEntity(database = "mil", collection = "presets") +public class PresetsEntity { + + /* + * id set as presetId + */ + @BsonId + private String id; + + /* + * Operation type + */ + public String operationType; + + /* + * Preset Id + */ + private String presetId; + + /* + * Tax code of the creditor company + */ + private String paTaxCode; + + /* + * Subscriber ID + */ + private String subscriberId; + + /* + * Creation timestamp + */ + private String creationTimestamp; + + /* + * Status + */ + private String status; + + /* + * Status timestamp + */ + private String statusTimestamp; + + /* + * Tax code of the creditor company + */ + private String noticeTaxCode; + + /* + * Notice number + */ + private String noticeNumber; + + /* + * Payment status + */ + private PaymentTransaction statusDetails; + /** + * @return the id + */ + public String getId() { + return id; + } + + /** + * @param id the id to set + */ + public void setId(String id) { + this.id = id; + } + + /** + * @return the operationType + */ + public String getOperationType() { + return operationType; + } + + /** + * @param operationType the operationType to set + */ + public void setOperationType(String operationType) { + this.operationType = operationType; + } + + /** + * @return the presetId + */ + public String getPresetId() { + return presetId; + } + + /** + * @param presetId the presetId to set + */ + public void setPresetId(String presetId) { + this.presetId = presetId; + } + + /** + * @return the paTaxCode + */ + public String getPaTaxCode() { + return paTaxCode; + } + + /** + * @param paTaxCode the paTaxCode to set + */ + public void setPaTaxCode(String paTaxCode) { + this.paTaxCode = paTaxCode; + } + + /** + * @return the subscriberId + */ + public String getSubscriberId() { + return subscriberId; + } + + /** + * @param subscriberId the subscriberId to set + */ + public void setSubscriberId(String subscriberId) { + this.subscriberId = subscriberId; + } + + /** + * @return the creationTimestamp + */ + public String getCreationTimestamp() { + return creationTimestamp; + } + + /** + * @param creationTimestamp the creationTimestamp to set + */ + public void setCreationTimestamp(String creationTimestamp) { + this.creationTimestamp = creationTimestamp; + } + + /** + * @return the status + */ + public String getStatus() { + return status; + } + + /** + * @param status the status to set + */ + public void setStatus(String status) { + this.status = status; + } + + /** + * @return the statusTimestamp + */ + public String getStatusTimestamp() { + return statusTimestamp; + } + + /** + * @param statusTimestamp the statusTimestamp to set + */ + public void setStatusTimestamp(String statusTimestamp) { + this.statusTimestamp = statusTimestamp; + } + + /** + * @return the noticeTaxCode + */ + public String getNoticeTaxCode() { + return noticeTaxCode; + } + + /** + * @param noticeTaxCode the noticeTaxCode to set + */ + public void setNoticeTaxCode(String noticeTaxCode) { + this.noticeTaxCode = noticeTaxCode; + } + + /** + * @return the noticeNumber + */ + public String getNoticeNumber() { + return noticeNumber; + } + + /** + * @param noticeNumber the noticeNumber to set + */ + public void setNoticeNumber(String noticeNumber) { + this.noticeNumber = noticeNumber; + } + + /** + * @return the statusDetails + */ + public PaymentTransaction getStatusDetails() { + return statusDetails; + } + + /** + * @param statusDetails the statusDetails to set + */ + public void setStatusDetails(PaymentTransaction statusDetails) { + this.statusDetails = statusDetails; + } +} diff --git a/src/main/java/it/pagopa/swclient/mil/preset/dao/SubscriberEntity.java b/src/main/java/it/pagopa/swclient/mil/preset/dao/SubscriberEntity.java new file mode 100644 index 0000000..14d522f --- /dev/null +++ b/src/main/java/it/pagopa/swclient/mil/preset/dao/SubscriberEntity.java @@ -0,0 +1,207 @@ +package it.pagopa.swclient.mil.preset.dao; + +import org.bson.codecs.pojo.annotations.BsonId; + +import io.quarkus.mongodb.panache.common.MongoEntity; +import jakarta.validation.constraints.Pattern; + +/** + * Entity of the Preset service + */ +@MongoEntity(database = "mil", collection = "subscribers") +public class SubscriberEntity { + + /* + * id set as subscriber id + */ + @BsonId + private String id; + + /* + * Acquirer ID assigned by PagoPA + */ + public String acquirerId; + + /* + * Channel originating the request + */ + private String channel; + + /* + * Merchant ID. Mandatory when Channel equals POS + */ + private String merchantId; + + /* + * ID of the terminal originating the transaction. It must be unique per acquirer and channel. + */ + private String terminalId; + + /* + * Tax code of the creditor company + */ + private String paTaxCode; + + /* + * Subscriber ID + */ + private String subscriberId; + + + /* + * Mnemonic terminal label + */ + @Pattern(regexp = "^[\\u0001-\\uD7FF\\uE000-\\uFFFD\\u10000-\\u10FFFF]{1,256}$") + private String label; + + /* + * Subscription timestamp + */ + private String subscriptionTimestamp; + + /* + * Last usage timestamp + */ + private String lastUsageTimestamp; + + /** + * @return the id + */ + public String getId() { + return id; + } + + /** + * @param id the id to set + */ + public void setId(String id) { + this.id = id; + } + + /** + * @return the acquirerId + */ + public String getAcquirerId() { + return acquirerId; + } + + /** + * @param acquirerId the acquirerId to set + */ + public void setAcquirerId(String acquirerId) { + this.acquirerId = acquirerId; + } + + /** + * @return the channel + */ + public String getChannel() { + return channel; + } + + /** + * @param channel the channel to set + */ + public void setChannel(String channel) { + this.channel = channel; + } + + /** + * @return the merchantId + */ + public String getMerchantId() { + return merchantId; + } + + /** + * @param merchantId the merchantId to set + */ + public void setMerchantId(String merchantId) { + this.merchantId = merchantId; + } + + /** + * @return the terminalId + */ + public String getTerminalId() { + return terminalId; + } + + /** + * @param terminalId the terminalId to set + */ + public void setTerminalId(String terminalId) { + this.terminalId = terminalId; + } + + /** + * @return the paTaxCode + */ + public String getPaTaxCode() { + return paTaxCode; + } + + /** + * @param paTaxCode the paTaxCode to set + */ + public void setPaTaxCode(String paTaxCode) { + this.paTaxCode = paTaxCode; + } + + /** + * @return the subscriberId + */ + public String getSubscriberId() { + return subscriberId; + } + + /** + * @param subscriberId the subscriberId to set + */ + public void setSubscriberId(String subscriberId) { + this.subscriberId = subscriberId; + } + + /** + * @return the label + */ + public String getLabel() { + return label; + } + + /** + * @param label the label to set + */ + public void setLabel(String label) { + this.label = label; + } + + /** + * @return the subscriptionTimestamp + */ + public String getSubscriptionTimestamp() { + return subscriptionTimestamp; + } + + /** + * @param subscriptionTimestamp the subscriptionTimestamp to set + */ + public void setSubscriptionTimestamp(String subscriptionTimestamp) { + this.subscriptionTimestamp = subscriptionTimestamp; + } + + /** + * @return the lastUsageTimestamp + */ + public String getLastUsageTimestamp() { + return lastUsageTimestamp; + } + + /** + * @param lastUsageTimestamp the lastUsageTimestamp to set + */ + public void setLastUsageTimestamp(String lastUsageTimestamp) { + this.lastUsageTimestamp = lastUsageTimestamp; + } + +} diff --git a/src/main/java/it/pagopa/swclient/mil/preset/dao/SubscriberRepository.java b/src/main/java/it/pagopa/swclient/mil/preset/dao/SubscriberRepository.java new file mode 100644 index 0000000..944035c --- /dev/null +++ b/src/main/java/it/pagopa/swclient/mil/preset/dao/SubscriberRepository.java @@ -0,0 +1,12 @@ +package it.pagopa.swclient.mil.preset.dao; + +import io.quarkus.mongodb.panache.reactive.ReactivePanacheMongoRepository; +import jakarta.enterprise.context.ApplicationScoped; + +/** + * MongoDB repository to access the preset subscribed terminals, reactive flavor + */ +@ApplicationScoped +public class SubscriberRepository implements ReactivePanacheMongoRepository { + +} \ No newline at end of file diff --git a/src/main/java/it/pagopa/swclient/mil/preset/resource/PresetsResource.java b/src/main/java/it/pagopa/swclient/mil/preset/resource/PresetsResource.java new file mode 100644 index 0000000..fbbc520 --- /dev/null +++ b/src/main/java/it/pagopa/swclient/mil/preset/resource/PresetsResource.java @@ -0,0 +1,308 @@ +/** + * + */ +package it.pagopa.swclient.mil.preset.resource; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import io.quarkus.logging.Log; +import io.quarkus.panache.common.Parameters; +import io.quarkus.panache.common.Sort; +import io.smallrye.mutiny.Uni; +import it.pagopa.swclient.mil.bean.CommonHeader; +import it.pagopa.swclient.mil.bean.Errors; +import it.pagopa.swclient.mil.preset.ErrorCode; +import it.pagopa.swclient.mil.preset.OperationType; +import it.pagopa.swclient.mil.preset.PresetStatus; +import it.pagopa.swclient.mil.preset.bean.PresetHeaders; +import it.pagopa.swclient.mil.preset.bean.PresetRequest; +import it.pagopa.swclient.mil.preset.bean.PresetResponse; +import it.pagopa.swclient.mil.preset.bean.PresetsPathParam; +import it.pagopa.swclient.mil.preset.bean.PresetsResponse; +import it.pagopa.swclient.mil.preset.dao.PresetRepository; +import it.pagopa.swclient.mil.preset.dao.PresetsEntity; +import it.pagopa.swclient.mil.preset.dao.SubscriberEntity; +import it.pagopa.swclient.mil.preset.dao.SubscriberRepository; +import it.pagopa.swclient.mil.preset.utils.DateUtils; +import jakarta.inject.Inject; +import jakarta.validation.Valid; +import jakarta.ws.rs.BeanParam; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.InternalServerErrorException; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.Response.Status; + +@Path("/presets") +public class PresetsResource { + + @Inject + private PresetRepository presetRepository; + + @Inject + private SubscriberRepository subscriberRepository; + + /** + * Creates Preset Operation + * @param headers a set of mandatory headers + * @param presetRequest {@link PresetRequest} containing the request parameters + * @return HttpStatus CREATED. Preset operation created successfully + */ + @POST + public Uni createPreset(@Valid @BeanParam PresetHeaders headers, @Valid PresetRequest presetRequest) { + Log.debugf("createPreset - Input parameters: %s, request: %s", headers, presetRequest); + return findSubscriberByTaxCodeAndSubscriberId(presetRequest.getPaTaxCode(), presetRequest.getSubscriberId()) + .onFailure().transform(f -> f) + .chain(entity -> { + if (entity == null) { + Log.errorf("[%s] No subscriber found", ErrorCode.ERROR_SUBSCRIBER_NOT_FOUND); + return Uni.createFrom().item( + Response.status(Status.BAD_REQUEST) + .entity(new Errors(List.of(ErrorCode.ERROR_SUBSCRIBER_NOT_FOUND))) + .build()); + } else { + Log.debugf("Subscriber found. Update the Last Usage Timestamp"); + entity.setLastUsageTimestamp(DateUtils.getAndFormatCurrentDate()); + return updateSubscriber(entity).chain(m -> { + Log.debugf("Generating new UUID ... "); + final String uuid = UUID.randomUUID().toString(); + Log.debugf("UUID %s generated ", uuid); + return persist(entity, presetRequest, uuid); + }); + + } + }); + } + + /** + * Returns preset Operations for a specific subscriber + * @param headers a set of mandatory headers + * @param pathParams {@link PresetsPathParam} contains the path parameters: paTaxCode and subscriberId + * @return the presets operation for a specific subscriber + */ + @GET + @Path("/{paTaxCode}/{subscriberId}") + public Uni getPresetsOperations(@Valid @BeanParam PresetHeaders headers, @Valid PresetsPathParam pathParams) { + Log.debugf("getPresetsOperations - Input parameters: %s, request: %s", headers, pathParams); + return findPresetsOperationByTaxCodeAndSubscriberId(pathParams.getPaTaxCode(), pathParams.getSubscriberId()) + .onFailure().transform(f -> f) + .map(m -> { + Log.debugf("getPresets Response %s",m); + return Response.status(Status.OK).entity(m).build(); + }); + } + + /** + * Return last preset operation to execute + * @param headers a set of mandatory headers + * @param pathParams pathParams {@link PresetsPathParam} contains the path parameters: paTaxCode and subscriberId + * @return Return last preset operation to execute for a specific subscriber + */ + @GET + @Path("/{paTaxCode}/{subscriberId}/last_to_execute") + public Uni getLastPresetsOperation(@Valid @BeanParam CommonHeader headers, @Valid PresetsPathParam pathParams) { + Log.debugf("getLastPresetsOperation - Input parameters: %s, request: %s", headers, pathParams); + return findPresetsOperationByTaxCodeAndSubscriberIdSortByCreationDate(pathParams.getPaTaxCode(), pathParams.getSubscriberId()) + .onFailure().transform(f -> f) + .chain(m -> { + if (m == null) { + Log.errorf("[%s] No subscriber found", ErrorCode.ERROR_PRESET_OPERATION_NOT_FOUND); + return Uni.createFrom().item( + Response.status(Status.NOT_FOUND) + .entity(new Errors(List.of(ErrorCode. ERROR_PRESET_OPERATION_NOT_FOUND))) + .build()); + } else { + Log.debugf("getPresets Response %s",m); + return Uni.createFrom().item(Response.status(Status.OK).entity(m).build()); + } + }); + } + + /** + * searches the subscriber by paTaxCode and Subscriber Id + * @param paTaxCode Tax code of the creditor company + * @param subscriberId subscriber ID + * @return + */ + private Uni findSubscriberByTaxCodeAndSubscriberId(String paTaxCode, String subscriberId) { + Log.debugf("find By paTaxCode %s And SubscriberId %s",paTaxCode,subscriberId); + return subscriberRepository.list("paTaxCode = :paTaxCode and subscriberId = :subscriberId", + Parameters.with("paTaxCode", paTaxCode).and("subscriberId", subscriberId).map()) + .onFailure().transform(err -> { + Log.errorf(err, "[%s] Error while find subscriber", ErrorCode.ERROR_COMMUNICATION_MONGO_DB); + return new InternalServerErrorException(Response + .status(Status.INTERNAL_SERVER_ERROR) + .entity(new Errors(List.of(ErrorCode.ERROR_COMMUNICATION_MONGO_DB))) + .build()); + } + ).map(entity -> !entity.isEmpty() ? entity.get(0) : null); + } + + /** + * searches the last preset operation by paTaxCode and subscriber ID + * @param paTaxCode Tax code of the creditor company + * @param subscriberId ID assigned to subscribed terminal + * @return the last preset operations + */ + private Uni findPresetsOperationByTaxCodeAndSubscriberIdSortByCreationDate(String paTaxCode, String subscriberId) { + Log.debugf("find last preset Operation By paTaxCode %s And SubscriberId %s",paTaxCode,subscriberId); + return presetRepository.list("paTaxCode = :paTaxCode and subscriberId = :subscriberId", + Sort.by("creationTimestamp").descending(), + Parameters.with("paTaxCode", paTaxCode).and("subscriberId", subscriberId).map() + ) + .onFailure().transform(err -> { + Log.errorf(err, "[%s] Error while find subscriber", ErrorCode.ERROR_COMMUNICATION_MONGO_DB); + return new InternalServerErrorException(Response + .status(Status.INTERNAL_SERVER_ERROR) + .entity(new Errors(List.of(ErrorCode.ERROR_COMMUNICATION_MONGO_DB))) + .build()); + } + ).map(m -> + !m.isEmpty() ? mapPresetOperation(m.get(0)) : null + ); + } + + /** + * searches the last preset operation by paTaxCode and subscriber ID + * @param paTaxCode Tax code of the creditor company + * @param subscriberId ID assigned to subscribed terminal + * @return the last preset operations + */ + private Uni findPresetsOperationByTaxCodeAndSubscriberId(String paTaxCode, String subscriberId) { + Log.debugf("find presets Operation By paTaxCode %s And SubscriberId %s",paTaxCode,subscriberId); + return presetRepository.list("paTaxCode = :paTaxCode and subscriberId = :subscriberId", + Parameters.with("paTaxCode", paTaxCode).and("subscriberId", subscriberId).map()) + .onFailure().transform(err -> { + Log.errorf(err, "[%s] Error while find subscriber", ErrorCode.ERROR_COMMUNICATION_MONGO_DB); + return new InternalServerErrorException(Response + .status(Status.INTERNAL_SERVER_ERROR) + .entity(new Errors(List.of(ErrorCode.ERROR_COMMUNICATION_MONGO_DB))) + .build()); + } + ).map(this::mapPresetsOperationResponse); + } + /** + * Maps the list of {@link PresetsEntity} to {@link PresetsResponse} + * @param listOfPresetsEntity + * @return {@link PresetsResponse} + */ + private PresetsResponse mapPresetsOperationResponse(List listOfPresetsEntity) { + PresetsResponse presetsResponse = new PresetsResponse(); + List presets = new ArrayList<>(); + listOfPresetsEntity.forEach(element -> { + presets.add(mapPresetOperation(element)); + }); + presetsResponse.setPresets(presets); + return presetsResponse; + } + + /** + * Maps the {@link PresetsEntity} to {@link PresetResponse} + * @param presetsEntity + * @return + */ + private PresetResponse mapPresetOperation(PresetsEntity presetsEntity) { + + PresetResponse response = new PresetResponse(); + response.setCreationTimestamp(presetsEntity.getCreationTimestamp()); + response.setNoticeNumber(presetsEntity.getNoticeNumber()); + response.setNoticeTaxCode(presetsEntity.getNoticeTaxCode()); + response.setOperationType(presetsEntity.getOperationType()); + response.setPaTaxCode(presetsEntity.getPaTaxCode()); + response.setPresetId(presetsEntity.getPresetId()); + response.setStatus(presetsEntity.getStatus()); + response.setStatusTimestamp(presetsEntity.getStatusTimestamp()); + response.setSubscriberId(presetsEntity.getSubscriberId()); + response.setStatusDetails(presetsEntity.getStatusDetails()); + return response; + } + + /** + * Update the subscriber + * @param entity + * @return + */ + private Uni updateSubscriber(SubscriberEntity entity) { + Log.debugf("Updating Subscriber"); + return subscriberRepository.update(entity) + .onFailure().retry().withBackOff(Duration.ofSeconds(30), Duration.ofSeconds(30)).atMost(2) + .map(m -> m); + } + + /** + * Save a preset operation + * @param subscriberEntity entity describing the subscriber + * @param presetRequest request of the preset operation + * @param presetId the generated preset ID + * @return + */ + private Uni persist( SubscriberEntity subscriberEntity, + PresetRequest presetRequest, + String presetId ) { + PresetsEntity entity = buildPresetEntity(subscriberEntity, presetRequest, presetId); + Log.debugf("Peristing Preset"); + return presetRepository.persist(entity) + .onFailure().transform( f -> { + Log.errorf(f, "[%s] Error while storing preset %s into db", + ErrorCode.ERROR_STORING_TERMINAL_IN_DB, presetId); + return + new InternalServerErrorException( + Response.status(Status.INTERNAL_SERVER_ERROR) + .entity(new Errors(List.of(ErrorCode.ERROR_STORING_TERMINAL_IN_DB))) + .build()); + }) + .map(m -> { + final String location = buildLocationPath(subscriberEntity.getPaTaxCode(), subscriberEntity.getSubscriberId(), presetId); + Log.debugf("PresetId %s SAVED ", presetId); + return Response.status(Status.CREATED).header(SubscribeResource.LOCATION, location).build(); + }); + } + + /** + * Build the presetEntity object used to persist the preset operation + * @param subscriberEntity entity describing the subscriber + * @param presetRequest request of the preset operation + * @param presetId the generated preset ID + * @return a preset entity + */ + private PresetsEntity buildPresetEntity(SubscriberEntity subscriberEntity, + PresetRequest presetRequest, + String presetId) { + + final String timestamp = DateUtils.getAndFormatCurrentDate(); + PresetsEntity presetEntity = new PresetsEntity(); + presetEntity.setId(presetId); + presetEntity.setPresetId(presetId); + presetEntity.setCreationTimestamp(timestamp); + presetEntity.setNoticeNumber(presetRequest.getNoticeNumber()); + presetEntity.setNoticeTaxCode(presetRequest.getNoticeTaxCode()); + presetEntity.setOperationType(OperationType.PAYMENT_NOTICE.name()); + presetEntity.setPaTaxCode(subscriberEntity.getPaTaxCode()); + presetEntity.setStatus(PresetStatus.TO_EXECUTE.name()); + presetEntity.setStatusTimestamp(timestamp); + presetEntity.setSubscriberId(subscriberEntity.getSubscriberId()); + return presetEntity; + } + + /** + * Utility method used to build the location path + * @param paTaxCode Tax code of the creditor company + * @param subscriberId Subscriber ID + * @param presetId the generated preset ID + * @return + */ + private String buildLocationPath(String paTaxCode, String subscriberId, String presetId) { + final StringBuilder location = new StringBuilder(); + location.append("/presets/"); + location.append(paTaxCode); + location.append("/"); + location.append(subscriberId); + location.append("/"); + location.append(presetId); + return location.toString(); + } +} diff --git a/src/main/java/it/pagopa/swclient/mil/preset/resource/SubscribeResource.java b/src/main/java/it/pagopa/swclient/mil/preset/resource/SubscribeResource.java new file mode 100644 index 0000000..41185d0 --- /dev/null +++ b/src/main/java/it/pagopa/swclient/mil/preset/resource/SubscribeResource.java @@ -0,0 +1,297 @@ +/** + * This module contains the REST endpoints exposed by the microservice. + * + * @author Antonio Tarricone + */ +package it.pagopa.swclient.mil.preset.resource; + +import java.security.SecureRandom; +import java.util.List; + +import org.apache.commons.lang3.RandomStringUtils; + +import io.quarkus.logging.Log; +import io.quarkus.panache.common.Parameters; +import io.smallrye.mutiny.Uni; +import it.pagopa.swclient.mil.bean.CommonHeader; +import it.pagopa.swclient.mil.bean.Errors; +import it.pagopa.swclient.mil.preset.ErrorCode; +import it.pagopa.swclient.mil.preset.bean.PresetHeaders; +import it.pagopa.swclient.mil.preset.bean.SubcribersResponse; +import it.pagopa.swclient.mil.preset.bean.SubscriberRequest; +import it.pagopa.swclient.mil.preset.bean.SubscriberResponse; +import it.pagopa.swclient.mil.preset.bean.SubscribersPathParam; +import it.pagopa.swclient.mil.preset.bean.UnsubscriberHeaders; +import it.pagopa.swclient.mil.preset.bean.UnsubscriberPathParam; +import it.pagopa.swclient.mil.preset.dao.SubscriberEntity; +import it.pagopa.swclient.mil.preset.dao.SubscriberRepository; +import it.pagopa.swclient.mil.preset.utils.DateUtils; +import jakarta.inject.Inject; +import jakarta.validation.Valid; +import jakarta.ws.rs.BeanParam; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.InternalServerErrorException; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.Response.Status; + + +@Path("/terminals") +public class SubscribeResource { + + public static final String LOCATION = "Location"; + + @Inject + private SubscriberRepository subscriberRepository; + + /** + * Returns the list of subscribed terminals + * @param headers a set of mandatory headers + * @param pathParams paTaxCode of the creditor company + * @return List of subscribed terminals + */ + @GET + @Path("/{paTaxCode}") + @Consumes(MediaType.APPLICATION_JSON) + public Uni getSubscribers(@Valid @BeanParam PresetHeaders headers,@Valid SubscribersPathParam pathParams) { + Log.debugf("getSubscribers - Input parameters: %s, taxCode: %s", headers, pathParams.getPaTaxCode()); + + return findSubscribersByPaTaxCode(pathParams.getPaTaxCode()) + .onFailure().transform(f -> f) + .map(m -> { + Log.debugf("getSubscribers Response %s",m); + return Response.status(Status.OK).entity(m).build(); + }); + + } + + /** + * Unsubscribes a terminal to handle preset operations + * @param headers a set of mandatory headers + * @param pathParams paTaxCode and subscriberId + * @return + */ + @DELETE + @Path(value = "/{paTaxCode}/{subscriberId}") + public Uni unsubscriber(@Valid @BeanParam UnsubscriberHeaders headers, UnsubscriberPathParam pathParams) { + return deleteByPaTaxCodeAndSubscriberId(pathParams.getPaTaxCode(),pathParams.getSubscriberId()) + .map(numberOfEntityDeleted -> { + Log.debugf("unbscriber Response - Deleted [%s] entity",numberOfEntityDeleted); + if (numberOfEntityDeleted > 0) { + return Response.status(Status.NO_CONTENT).build(); + } else { + return Response.status(Status.NOT_FOUND).build(); + } + }); + } + + /** + * Subscribes a terminal to handle preset operations + * @param commonHeader a set of mandatory headers + * @param subscriberRequest {@link SubscriberRequest} contains Tax code of the creditor company and a mnemonic terminal label + * @return status of operation + */ + @POST + public Uni subscribe(@Valid @BeanParam CommonHeader commonHeader, @Valid SubscriberRequest subscriberRequest) { + Log.debugf("subscribe - Input parameters: %s, subscriberRequest: %s", commonHeader, subscriberRequest); + return findSubscriber(commonHeader.getAcquirerId(), + commonHeader.getChannel(), + commonHeader.getMerchantId(), + commonHeader.getTerminalId(), + subscriberRequest.getPaTaxCode()) + .chain(subscriberId -> { + if (subscriberId.equals("")) { + Log.debugf("No SubscriberId found "); + Log.debugf("Generating new SubscriberId ... "); + final String subId = RandomStringUtils.random(6, 0, 0, true, true, null, new SecureRandom()).toLowerCase(); + Log.debugf("SubscriberId %s generated ", subId); + return persist(subscriberRequest, commonHeader, subId); + } else { + final String location = buildLocationPath(subscriberRequest.getPaTaxCode(), subscriberId); + Log.debugf("[%s] Error while storing terminal %s into db", ErrorCode.ERROR_CONFLICT_TERMINAL_IN_DB, subscriberId); + + return Uni.createFrom().item( + Response.status(Status.CONFLICT) + .entity(new Errors(List.of(ErrorCode.ERROR_CONFLICT_TERMINAL_IN_DB))) + .header(LOCATION, location).build()); + } + }); + } + + /** + * Perform the persist operation on the database + * @param subscriberRequest {@link SubscriberRequest} contains Tax code of the creditor company and a mnemonic terminal label + * @param commonHeader a set of mandatory headers + * @param subId subscriber Id + * @return the status of the persist + */ + private Uni persist( SubscriberRequest subscriberRequest, + CommonHeader commonHeader, + String subId ) { + SubscriberEntity entity = buildEntity(subscriberRequest, commonHeader, subId); + return subscriberRepository.persist(entity) + .onFailure().transform( f -> { + Log.errorf(f, "[%s] Error while storing terminal %s into db", + ErrorCode.ERROR_STORING_TERMINAL_IN_DB, subId); + return + new InternalServerErrorException( + Response.status(Status.INTERNAL_SERVER_ERROR) + .entity(new Errors(List.of(ErrorCode.ERROR_STORING_TERMINAL_IN_DB))) + .build()); + }) + .map(m -> { + final String location = buildLocationPath(subscriberRequest.getPaTaxCode(), subId); + Log.debugf("SubscriberId %s SAVED ", subId); + return Response.status(Status.CREATED).header(LOCATION, location).build(); + }); + } + + /** + * Retrieves the list of subscribers by paTaxCode + * @param taxCodeToken token returned by the PDV-Tokenizer service + * @param tcVersion T&C version + * @return true if the current version is equals to older one. False otherwise. + */ + private Uni findSubscribersByPaTaxCode(String paTaxCode) { + Log.debugf("findSubscribersByPaTaxCode - find Subscribers by paTaxCode: [%s] ", paTaxCode); + + return subscriberRepository.list("paTaxCode", paTaxCode) + .onFailure().transform(err -> { + Log.errorf(err, "[%s] Error while find subscriber", ErrorCode.ERROR_COMMUNICATION_MONGO_DB); + return new InternalServerErrorException(Response + .status(Status.INTERNAL_SERVER_ERROR) + .entity(new Errors(List.of(ErrorCode.ERROR_COMMUNICATION_MONGO_DB))) + .build()); + } + ).map(entity -> { + SubcribersResponse subscribers = new SubcribersResponse(); + entity.forEach(element -> mapResponse(element, subscribers)); + return subscribers; + }); + } + + + /** + * Make a query to check if the terminal is already subscribed + * @param acquirerId Acquirer ID assigned by PagoPA + * @param channel Channel originating the request + * @param merchantId Merchant ID. Mandatory when Channel equals POS. + * @param terminalId ID of the terminal originating the transaction. It must be unique per acquirer and channel. + * @param paTaxCode Tax code of the creditor company + * @return + */ + private Uni findSubscriber(String acquirerId, + String channel, + String merchantId, + String terminalId, + String paTaxCode + ) { + Log.debugf("findSubscriber - find Subscribers by acquirerId [%s] channel [%s] merchantId [%s] terminalid [%s] paTaxCode: [%s] ", acquirerId, channel, merchantId, terminalId, paTaxCode); + + return subscriberRepository.list("acquirerId = :acquirerId and channel = :channel and merchantId =:merchantId and terminalId =:terminalId and paTaxCode =:paTaxCode", + Parameters.with("acquirerId", acquirerId) + .and("channel", channel) + .and("merchantId", merchantId) + .and("terminalId", terminalId) + .and("paTaxCode", paTaxCode) + .map()) + .onFailure().transform(err -> { + Log.errorf(err, "[%s] Error while list subscribers", ErrorCode.ERROR_COMMUNICATION_MONGO_DB); + return new InternalServerErrorException(Response + .status(Status.INTERNAL_SERVER_ERROR) + .entity(new Errors(List.of(ErrorCode.ERROR_COMMUNICATION_MONGO_DB))) + .build()); + } + ).map(entity -> + !entity.isEmpty() ? entity.get(0).getSubscriberId() : "" + ); + } + + /** + * Delete the subsctiber by paTaxCode and Subscriber Id + * @param paTaxCode Tax code of the creditor company + * @param subscriberId subscriber Id + * @return + */ + private Uni deleteByPaTaxCodeAndSubscriberId(String paTaxCode, String subscriberId) { + Log.debugf("Deleting entity with paTaxCode [%s] and subscriberId [%s]", paTaxCode, subscriberId); + + return subscriberRepository.delete("paTaxCode = :paTaxCode and subscriberId = :subscriberId", + Parameters.with("paTaxCode", paTaxCode).and("subscriberId", subscriberId).map() + ) + .onFailure().transform(err -> { + Log.debugf("Internal server error deleting entity with paTaxCode [%s] and subscriberId [%s]", paTaxCode, subscriberId); + return new InternalServerErrorException(Response + .status(Status.INTERNAL_SERVER_ERROR) + .entity(new Errors(List.of(ErrorCode.ERROR_COMMUNICATION_MONGO_DB))) + .build()); + }).map(f -> f); + } + + /** + * Maps the Entity to the SubcribersResponse + * @param entity entity retrieved form database + * @param subscribersResponse response containing the subscriber info + */ + private void mapResponse(SubscriberEntity entity, SubcribersResponse subscribersResponse) { + SubscriberResponse subscriberResponse = new SubscriberResponse(); + subscriberResponse.setAcquirerId(entity.getAcquirerId()); + subscriberResponse.setChannel(entity.getChannel()); + subscriberResponse.setLabel(entity.getLabel()); + subscriberResponse.setLastUsageTimestamp(entity.getLastUsageTimestamp()); + subscriberResponse.setMerchantId(entity.getMerchantId()); + subscriberResponse.setPaTaxCode(entity.getPaTaxCode()); + subscriberResponse.setSubscriberId(entity.getSubscriberId()); + subscriberResponse.setSubscriptionTimestamp(entity.getSubscriptionTimestamp()); + subscriberResponse.setTerminalId(entity.getTerminalId()); + subscribersResponse.getSubscribers().add(subscriberResponse); + } + + /** + * Maps the input parameters to the {@link SubscriberEntity}, used to persiste the information into the database + * @param subscriberRequest {@link SubscriberRequest} contains Tax code of the creditor company and a mnemonic terminal label + * @param commonHeader a set of mandatory headers + * @param subId subscriber Id + * @return the entity to persist + */ + private SubscriberEntity buildEntity(SubscriberRequest subscriberRequest, + CommonHeader commonHeader, + String subId) { + + final String timestamp = DateUtils.getAndFormatCurrentDate(); + SubscriberEntity entity = new SubscriberEntity(); + //set id as subscriber Id + entity.setId(subId); + entity.setAcquirerId(commonHeader.getAcquirerId()); + entity.setChannel(commonHeader.getChannel()); + entity.setLabel(subscriberRequest.getLabel()); + entity.setLastUsageTimestamp(timestamp); + entity.setMerchantId(commonHeader.getMerchantId()); + entity.setPaTaxCode(subscriberRequest.getPaTaxCode()); + entity.setSubscriberId(subId); + entity.setSubscriptionTimestamp(timestamp); + entity.setTerminalId(commonHeader.getTerminalId()); + + return entity; + } + + /** + * Utility method used to build the location path + * @param paTaxCode Tax code of the creditor company + * @param subscriber subscriber Id + * @return the location path as string + */ + private String buildLocationPath(String paTaxCode, String subscriberId) { + final StringBuilder location = new StringBuilder(); + location.append("/terminals/"); + location.append(paTaxCode); + location.append("/"); + location.append(subscriberId); + return location.toString(); + } + +} \ No newline at end of file diff --git a/src/main/java/it/pagopa/swclient/mil/preset/utils/DateUtils.java b/src/main/java/it/pagopa/swclient/mil/preset/utils/DateUtils.java new file mode 100644 index 0000000..3a449c3 --- /dev/null +++ b/src/main/java/it/pagopa/swclient/mil/preset/utils/DateUtils.java @@ -0,0 +1,24 @@ +/** + * + */ +package it.pagopa.swclient.mil.preset.utils; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; + +public class DateUtils { + + /** + * Utility method. Generate a formatted current date time + * @return formatted current date time. Format yyyy-MM-dd'T'HH:mm:ss.SS + */ + public static String getAndFormatCurrentDate() { + final String pattern = "yyyy-MM-dd'T'HH:mm:ss.SS"; + + DateFormat df = new SimpleDateFormat(pattern); + Date currentDate = Calendar.getInstance().getTime(); + return df.format(currentDate); + } +} diff --git a/src/main/java/it/pagopa/swclient/mil/preset/validation/constraints/MerchantIdNotNullForPos.java b/src/main/java/it/pagopa/swclient/mil/preset/validation/constraints/MerchantIdNotNullForPos.java new file mode 100644 index 0000000..b1b92b8 --- /dev/null +++ b/src/main/java/it/pagopa/swclient/mil/preset/validation/constraints/MerchantIdNotNullForPos.java @@ -0,0 +1,28 @@ +/** + * + */ +package it.pagopa.swclient.mil.preset.validation.constraints; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import jakarta.validation.Constraint; +import jakarta.validation.Payload; + +@Documented +@Retention(RUNTIME) +@Target(TYPE) +@Constraint(validatedBy = { + MerchantIdNotNullForPosValidator.class +}) +public @interface MerchantIdNotNullForPos { + String message() default ""; + + Class[] groups() default {}; + + Class[] payload() default {}; +} diff --git a/src/main/java/it/pagopa/swclient/mil/preset/validation/constraints/MerchantIdNotNullForPosValidator.java b/src/main/java/it/pagopa/swclient/mil/preset/validation/constraints/MerchantIdNotNullForPosValidator.java new file mode 100644 index 0000000..674bb47 --- /dev/null +++ b/src/main/java/it/pagopa/swclient/mil/preset/validation/constraints/MerchantIdNotNullForPosValidator.java @@ -0,0 +1,22 @@ +/** + * + */ +package it.pagopa.swclient.mil.preset.validation.constraints; + +import it.pagopa.swclient.mil.bean.Channel; +import it.pagopa.swclient.mil.preset.bean.UnsubscriberHeaders; + +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; + +public class MerchantIdNotNullForPosValidator implements ConstraintValidator { + /** + * @see jakarta.validation.ConstraintValidator#isValid(Object, ConstraintValidatorContext) + */ + @Override + public boolean isValid(UnsubscriberHeaders unsubscriberHeader, ConstraintValidatorContext context) { + String channel = unsubscriberHeader.getChannel(); + String merchantId = unsubscriberHeader.getMerchantId(); + return !(channel != null && channel.equals(Channel.POS) && merchantId == null); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..be5cdc5 --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1,46 @@ +uarkus.banner.enabled=false + +# ------------------------------------------------------------------------------ +# Logging configuration +# +# quarkus-log-level = ERROR +# app-log-level = DEBUG +# ------------------------------------------------------------------------------ +quarkus.log.console.format=%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{requestId}] [%p] [%c{2}] %m%n + +quarkus.log.min-level=DEBUG +#%dev.quarkus.log.level=DEBUG +%dev.quarkus.log.category."it.pagopa.swclient.mil.preset".level=DEBUG + +%playground.quarkus.log.level=ERROR +%playground.quarkus.log.category."it.pagopa.swclient.mil.preset".level=DEBUG + +%test.quarkus.log.level=DEBUG +%test.quarkus.log.category."it.pagopa.swclient.mil.preset".level=DEBUG + +%prod.quarkus.log.level=${preset.quarkus-log-level} +%prod.quarkus.log.category."it.pagopa.swclient.mil.preset".level=${preset.app-log-level} + + +# ------------------------------------------------------------------------------ +# DB configuration +# +# mongo-connect-timeout = 5s +# mongo-read-timeout = 10s +# mongo-server-selecion-timeout = 5s +# ------------------------------------------------------------------------------ +%playground.quarkus.mongodb.database=test-mongo +%playground.quarkus.mongodb.connection-string=mongodb://test-mongo:27017 + +%dev.quarkus.mongodb.connect-timeout=5 +%dev.quarkus.mongodb.read-timeout=10 +%dev.quarkus.mongodb.server-selection-timeout=5 +%dev.quarkus.mongodb.connection-string = mongodb://localhost:27017 + +%prod.quarkus.mongodb.connect-timeout=${mongo-connect-timeout} +%prod.quarkus.mongodb.read-timeout=${mongo-read-timeout} +%prod.quarkus.mongodb.server-selection-timeout=${mongo-server-selecion-timeout} +%prod.quarkus.mongodb.connection-string=${mongo-connection-string-1},${mongo-connection-string-2} + +quarkus.mongodb.devservices.enabled=false + diff --git a/src/test/java/it/pagopa/swclient/mil/preset/PresetResourceTest.java b/src/test/java/it/pagopa/swclient/mil/preset/PresetResourceTest.java new file mode 100644 index 0000000..2d4db23 --- /dev/null +++ b/src/test/java/it/pagopa/swclient/mil/preset/PresetResourceTest.java @@ -0,0 +1,579 @@ +package it.pagopa.swclient.mil.preset; + +import static io.restassured.RestAssured.given; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.mockito.Mockito; + +import io.quarkus.panache.common.Sort; +import io.quarkus.test.common.http.TestHTTPEndpoint; +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.mockito.InjectMock; +import io.restassured.http.ContentType; +import io.restassured.response.Response; +import io.smallrye.mutiny.Uni; +import it.pagopa.swclient.mil.preset.bean.Notice; +import it.pagopa.swclient.mil.preset.bean.PaymentTransaction; +import it.pagopa.swclient.mil.preset.bean.PresetRequest; +import it.pagopa.swclient.mil.preset.bean.PresetResponse; +import it.pagopa.swclient.mil.preset.dao.PresetRepository; +import it.pagopa.swclient.mil.preset.dao.PresetsEntity; +import it.pagopa.swclient.mil.preset.dao.SubscriberEntity; +import it.pagopa.swclient.mil.preset.dao.SubscriberRepository; +import it.pagopa.swclient.mil.preset.resource.PresetsResource; +import it.pagopa.swclient.mil.preset.resource.SubscribeResource; +import it.pagopa.swclient.mil.preset.utils.DateUtils; +import jakarta.ws.rs.InternalServerErrorException; + + +@QuarkusTest +@TestHTTPEndpoint(PresetsResource.class) +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class PresetResourceTest { + + final static String SESSION_ID = "a6a666e6-97da-4848-b568-99fedccb642c"; + final static String API_VERSION = "1.0.0-alpha-a.b-c-somethinglong+build.1-aef.1-its-okay"; + final static String PA_TAX_CODE = "15376371009"; + final static String SUBSCRIBER_ID = "y46tr3"; + + @InjectMock + SubscriberRepository subscriberRepository; + + @InjectMock + PresetRepository presetRepository; + + Map commonHeaders; + Map presetHeaders; + + @BeforeAll + void createTestObjects() { + presetHeaders = new HashMap<>(); + presetHeaders.put("RequestId", "d0d654e6-97da-4848-b568-99fedccb642b"); + presetHeaders.put("Version", API_VERSION); + + commonHeaders = new HashMap<>(); + commonHeaders.put("RequestId", "d0d654e6-97da-4848-b568-99fedccb642b"); + commonHeaders.put("Version", API_VERSION); + commonHeaders.put("AcquirerId", "4585625"); + commonHeaders.put("Channel", "ATM"); + commonHeaders.put("TerminalId", "0aB9wXyZ"); + commonHeaders.put("SessionId", SESSION_ID); + } + + /* **** preset **** */ + @Test + void createPreset_201() { + + SubscriberEntity subscriberEntity = new SubscriberEntity(); + subscriberEntity.setAcquirerId("4585625"); + subscriberEntity.setChannel("POS"); + subscriberEntity.setLabel("Reception POS"); + subscriberEntity.setLastUsageTimestamp("2023-05-08T10:55:57"); + subscriberEntity.setMerchantId("28405fHfk73x88D"); + subscriberEntity.setPaTaxCode("15376371009"); + subscriberEntity.setSubscriberId("x46tr3"); + subscriberEntity.setSubscriptionTimestamp("2023-05-05T09:31:33"); + subscriberEntity.setTerminalId("0aB9wXyZ"); + List listOfEntities = new ArrayList<>(); + listOfEntities.add(subscriberEntity); + + Mockito + .when(subscriberRepository.list(Mockito.any(String.class), Mockito.any(Map.class))) + .thenReturn(Uni.createFrom().item(listOfEntities)); + + + Mockito + .when(subscriberRepository.update(Mockito.any(SubscriberEntity.class))) + .thenReturn(Uni.createFrom().item(subscriberEntity)); + + final String timestamp = DateUtils.getAndFormatCurrentDate(); + PresetsEntity presetEntity = new PresetsEntity(); + presetEntity.setId("77457c64-0870-407a-b2cb-0f948b04fb9a"); + presetEntity.setPresetId("77457c64-0870-407a-b2cb-0f948b04fb9a"); + presetEntity.setCreationTimestamp(timestamp); + presetEntity.setNoticeNumber("485564829563528563"); + presetEntity.setNoticeTaxCode("15376371009"); + presetEntity.setOperationType(OperationType.PAYMENT_NOTICE.name()); + presetEntity.setPaTaxCode(subscriberEntity.getPaTaxCode()); + presetEntity.setStatus(PresetStatus.TO_EXECUTE.name()); + presetEntity.setStatusTimestamp(timestamp); + presetEntity.setSubscriberId(subscriberEntity.getSubscriberId()); + + Mockito + .when(presetRepository.persist(Mockito.any(PresetsEntity.class))) + .thenReturn(Uni.createFrom().item(presetEntity)); + + PresetRequest request = new PresetRequest(); + request.setNoticeNumber("485564829563528563"); + request.setNoticeTaxCode("15376371009"); + request.setOperationType("PAYMENT_NOTICE"); + request.setPaTaxCode("15376371009"); + request.setSubscriberId("x46tr3"); + + Response response = given() + .contentType(ContentType.JSON) + .headers(presetHeaders) + .body(request) + .and() + .when() + .post() + .then() + .extract() + .response(); + + Assertions.assertEquals(201, response.statusCode()); + + Assertions.assertNotNull(response.getHeader(SubscribeResource.LOCATION)); + } + + @Test + void createPreset_400_subscriberNotFound() { + + Mockito + .when(subscriberRepository.list(Mockito.any(String.class), Mockito.any(Map.class))) + .thenReturn(Uni.createFrom().item(List.of())); + + + PresetRequest request = new PresetRequest(); + request.setNoticeNumber("485564829563528563"); + request.setNoticeTaxCode("15376371009"); + request.setOperationType("PAYMENT_NOTICE"); + request.setPaTaxCode("15376371009"); + request.setSubscriberId("x46tr3"); + + Response response = given() + .contentType(ContentType.JSON) + .headers(presetHeaders) + .body(request) + .and() + .when() + .post() + .then() + .extract() + .response(); + + Assertions.assertEquals(400, response.statusCode()); + + Assertions.assertNull(response.getHeader(SubscribeResource.LOCATION)); + Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_SUBSCRIBER_NOT_FOUND)); + } + + @Test + void createPreset_500_datadaseErrorFindSubscriber() { + + SubscriberEntity subscriberEntity = new SubscriberEntity(); + subscriberEntity.setAcquirerId("4585625"); + subscriberEntity.setChannel("POS"); + subscriberEntity.setLabel("Reception POS"); + subscriberEntity.setLastUsageTimestamp("2023-05-08T10:55:57"); + subscriberEntity.setMerchantId("28405fHfk73x88D"); + subscriberEntity.setPaTaxCode("15376371009"); + subscriberEntity.setSubscriberId("x46tr3"); + subscriberEntity.setSubscriptionTimestamp("2023-05-05T09:31:33"); + subscriberEntity.setTerminalId("0aB9wXyZ"); + List listOfEntities = new ArrayList<>(); + listOfEntities.add(subscriberEntity); + + Mockito + .when(subscriberRepository.list(Mockito.any(String.class), Mockito.any(Map.class))) + .thenReturn(Uni.createFrom().failure(new InternalServerErrorException())); + + PresetRequest request = new PresetRequest(); + request.setNoticeNumber("485564829563528563"); + request.setNoticeTaxCode("15376371009"); + request.setOperationType("PAYMENT_NOTICE"); + request.setPaTaxCode("15376371009"); + request.setSubscriberId("x46tr3"); + + Response response = given() + .contentType(ContentType.JSON) + .headers(presetHeaders) + .body(request) + .and() + .when() + .post() + .then() + .extract() + .response(); + + Assertions.assertEquals(500, response.statusCode()); + Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_COMMUNICATION_MONGO_DB)); + Assertions.assertNull(response.getHeader(SubscribeResource.LOCATION)); + } + + + + @Test + void createPreset_500_datadaseErrorInsertingPreset() { + + SubscriberEntity subscriberEntity = new SubscriberEntity(); + subscriberEntity.setAcquirerId("4585625"); + subscriberEntity.setChannel("POS"); + subscriberEntity.setLabel("Reception POS"); + subscriberEntity.setLastUsageTimestamp("2023-05-08T10:55:57"); + subscriberEntity.setMerchantId("28405fHfk73x88D"); + subscriberEntity.setPaTaxCode("15376371009"); + subscriberEntity.setSubscriberId("x46tr3"); + subscriberEntity.setSubscriptionTimestamp("2023-05-05T09:31:33"); + subscriberEntity.setTerminalId("0aB9wXyZ"); + List listOfEntities = new ArrayList<>(); + listOfEntities.add(subscriberEntity); + + Mockito + .when(subscriberRepository.list(Mockito.any(String.class), Mockito.any(Map.class))) + .thenReturn(Uni.createFrom().item(listOfEntities)); + + + Mockito + .when(subscriberRepository.update(Mockito.any(SubscriberEntity.class))) + .thenReturn(Uni.createFrom().item(subscriberEntity)); + + Mockito + .when(presetRepository.persist(Mockito.any(PresetsEntity.class))) + .thenReturn(Uni.createFrom().failure(new InternalServerErrorException())); + + PresetRequest request = new PresetRequest(); + request.setNoticeNumber("485564829563528563"); + request.setNoticeTaxCode("15376371009"); + request.setOperationType("PAYMENT_NOTICE"); + request.setPaTaxCode("15376371009"); + request.setSubscriberId("x46tr3"); + + Response response = given() + .contentType(ContentType.JSON) + .headers(presetHeaders) + .body(request) + .and() + .when() + .post() + .then() + .extract() + .response(); + + Assertions.assertEquals(500, response.statusCode()); + Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_STORING_TERMINAL_IN_DB)); + Assertions.assertNull(response.getHeader(SubscribeResource.LOCATION)); + } + + @Test + void getPresets_200() { + + final String timestamp = DateUtils.getAndFormatCurrentDate(); + PresetsEntity presetEntity = new PresetsEntity(); + presetEntity.setId("77457c64-0870-407a-b2cb-0f948b04fb9a"); + presetEntity.setPresetId("77457c64-0870-407a-b2cb-0f948b04fb9a"); + presetEntity.setCreationTimestamp(timestamp); + presetEntity.setNoticeNumber("485564829563528563"); + presetEntity.setNoticeTaxCode("15376371009"); + presetEntity.setOperationType(OperationType.PAYMENT_NOTICE.name()); + presetEntity.setPaTaxCode("15376371009"); + presetEntity.setStatus(PresetStatus.TO_EXECUTE.name()); + presetEntity.setStatusTimestamp(timestamp); + presetEntity.setSubscriberId("x46tr3"); + + Notice notice = new Notice(); + notice.setPaymentToken("648fhg36s95jfg7DS"); + notice.setPaTaxCode(PA_TAX_CODE); + notice.setNoticeNumber("485564829563528563"); + notice.setAmount(12345L); + notice.setDescription("Test payment notice"); + notice.setCompany("Test company"); + notice.setOffice("Test office"); + + PaymentTransaction statusDetails = new PaymentTransaction(); + statusDetails.setTransactionId("517a4216840E461fB011036A0fd134E1"); + statusDetails.setAcquirerId("4585625"); + statusDetails.setChannel("POS"); + statusDetails.setMerchantId("28405fHfk73x88D"); + statusDetails.setTerminalId("0aB9wXyZ"); + statusDetails.setInsertTimestamp(timestamp); + List notices = new ArrayList<>(); + notices.add(notice); + statusDetails.setNotices(notices); + statusDetails.setTotalAmount(notices.stream().map(Notice::getAmount).reduce(Long::sum).orElse(0L)); + + statusDetails.setFee(100L); + statusDetails.setStatus("PRE_CLOSE"); + + presetEntity.setStatusDetails(statusDetails); + + List listOfPresetsEntity = new ArrayList<>(); + listOfPresetsEntity.add(presetEntity); + + Mockito + .when(presetRepository.list(Mockito.any(String.class), Mockito.any(Map.class))) + .thenReturn(Uni.createFrom().item(listOfPresetsEntity)); + + Response response = given() + .contentType(ContentType.JSON) + .headers(presetHeaders) + .and() + .when() + .get("/15376371009/x46tr3") + .then() + .extract() + .response(); + + Assertions.assertEquals(200, response.statusCode()); + + Assertions.assertNotNull(response.jsonPath().getJsonObject("presets")); + List arr = response.jsonPath().getList("presets", PresetResponse.class); + + Assertions.assertNotNull(arr.get(0).getCreationTimestamp()); + Assertions.assertNotNull(arr.get(0).getNoticeNumber()); + + Assertions.assertNotNull(arr.get(0).getNoticeTaxCode()); + Assertions.assertNotNull(arr.get(0).getOperationType()); + Assertions.assertNotNull(arr.get(0).getPaTaxCode()); + Assertions.assertNotNull(arr.get(0).getPresetId()); + Assertions.assertNotNull(arr.get(0).getStatus()); + Assertions.assertNotNull(arr.get(0).getStatusTimestamp()); + Assertions.assertNotNull(arr.get(0).getSubscriberId()); + PaymentTransaction statDetails = arr.get(0).getStatusDetails(); + Assertions.assertNotNull(statDetails.getAcquirerId()); + Assertions.assertNotNull(statDetails.getChannel()); + Assertions.assertNotNull(statDetails.getInsertTimestamp()); + Assertions.assertNotNull(statDetails.getAcquirerId()); + Assertions.assertNotNull(statDetails.getStatus()); + Assertions.assertNotNull(statDetails.getNotices()); + List noticesResponse = statDetails.getNotices(); + Assertions.assertNotNull(noticesResponse.get(0).getAmount()); + Assertions.assertNotNull(noticesResponse.get(0).getCompany()); + Assertions.assertNotNull(noticesResponse.get(0).getDescription()); + Assertions.assertNotNull(noticesResponse.get(0).getNoticeNumber()); + Assertions.assertNotNull(noticesResponse.get(0).getOffice()); + Assertions.assertNotNull(noticesResponse.get(0).getPaTaxCode()); + Assertions.assertNotNull(noticesResponse.get(0).getPaymentToken()); + } + + @Test + void getPresets_200_emptyPreset() { + + final String timestamp = DateUtils.getAndFormatCurrentDate(); + PresetsEntity presetEntity = new PresetsEntity(); + presetEntity.setId("77457c64-0870-407a-b2cb-0f948b04fb9a"); + presetEntity.setPresetId("77457c64-0870-407a-b2cb-0f948b04fb9a"); + presetEntity.setCreationTimestamp(timestamp); + presetEntity.setNoticeNumber("485564829563528563"); + presetEntity.setNoticeTaxCode("15376371009"); + presetEntity.setOperationType(OperationType.PAYMENT_NOTICE.name()); + presetEntity.setPaTaxCode("15376371009"); + presetEntity.setStatus(PresetStatus.TO_EXECUTE.name()); + presetEntity.setStatusTimestamp(timestamp); + presetEntity.setSubscriberId("x46tr3"); + + Notice notice = new Notice(); + notice.setPaymentToken("648fhg36s95jfg7DS"); + notice.setPaTaxCode(PA_TAX_CODE); + notice.setNoticeNumber("485564829563528563"); + notice.setAmount(12345L); + notice.setDescription("Test payment notice"); + notice.setCompany("Test company"); + notice.setOffice("Test office"); + + PaymentTransaction statusDetails = new PaymentTransaction(); + statusDetails.setTransactionId("517a4216840E461fB011036A0fd134E1"); + statusDetails.setAcquirerId("4585625"); + statusDetails.setChannel("POS"); + statusDetails.setMerchantId("28405fHfk73x88D"); + statusDetails.setTerminalId("0aB9wXyZ"); + statusDetails.setInsertTimestamp(timestamp); + List notices = new ArrayList<>(); + notices.add(notice); + statusDetails.setNotices(notices); + statusDetails.setTotalAmount(notices.stream().map(Notice::getAmount).reduce(Long::sum).orElse(0L)); + + statusDetails.setFee(100L); + statusDetails.setStatus("PRE_CLOSE"); + + presetEntity.setStatusDetails(statusDetails); + + List listOfPresetsEntity = new ArrayList<>(); +// listOfPresetsEntity.add(presetEntity); + + Mockito + .when(presetRepository.list(Mockito.any(String.class), Mockito.any(Map.class))) + .thenReturn(Uni.createFrom().item(listOfPresetsEntity)); + + Response response = given() + .contentType(ContentType.JSON) + .headers(presetHeaders) + .and() + .when() + .get("/15376371009/x46tr3") + .then() + .extract() + .response(); + + Assertions.assertEquals(200, response.statusCode()); + + Assertions.assertNotNull(response.jsonPath().getJsonObject("presets")); + List arr = response.jsonPath().getList("presets", PresetResponse.class); + + Assertions.assertEquals(0,arr.size()); + } + + @Test + void getLastPreset_200() { + + final String timestamp = DateUtils.getAndFormatCurrentDate(); + PresetsEntity presetEntity = new PresetsEntity(); + presetEntity.setId("77457c64-0870-407a-b2cb-0f948b04fb9a"); + presetEntity.setPresetId("77457c64-0870-407a-b2cb-0f948b04fb9a"); + presetEntity.setCreationTimestamp(timestamp); + presetEntity.setNoticeNumber("485564829563528563"); + presetEntity.setNoticeTaxCode("15376371009"); + presetEntity.setOperationType(OperationType.PAYMENT_NOTICE.name()); + presetEntity.setPaTaxCode("15376371009"); + presetEntity.setStatus(PresetStatus.TO_EXECUTE.name()); + presetEntity.setStatusTimestamp(timestamp); + presetEntity.setSubscriberId("x46tr3"); + + Notice notice = new Notice(); + notice.setPaymentToken("648fhg36s95jfg7DS"); + notice.setPaTaxCode(PA_TAX_CODE); + notice.setNoticeNumber("485564829563528563"); + notice.setAmount(12345L); + notice.setDescription("Test payment notice"); + notice.setCompany("Test company"); + notice.setOffice("Test office"); + + PaymentTransaction statusDetails = new PaymentTransaction(); + statusDetails.setTransactionId("517a4216840E461fB011036A0fd134E1"); + statusDetails.setAcquirerId("4585625"); + statusDetails.setChannel("POS"); + statusDetails.setMerchantId("28405fHfk73x88D"); + statusDetails.setTerminalId("0aB9wXyZ"); + statusDetails.setInsertTimestamp(timestamp); + List notices = new ArrayList<>(); + notices.add(notice); + statusDetails.setNotices(notices); + statusDetails.setTotalAmount(notices.stream().map(Notice::getAmount).reduce(Long::sum).orElse(0L)); + + statusDetails.setFee(100L); + statusDetails.setStatus("PRE_CLOSE"); + + presetEntity.setStatusDetails(statusDetails); + + List listOfPresetsEntity = new ArrayList<>(); + listOfPresetsEntity.add(presetEntity); + + Mockito + .when(presetRepository.list(Mockito.any(String.class), Mockito.any(Sort.class),Mockito.any(Map.class))) + .thenReturn(Uni.createFrom().item(listOfPresetsEntity)); + + Response response = given() + .contentType(ContentType.JSON) + .headers(commonHeaders) + .and() + .when() + .get("/15376371009/x46tr3/last_to_execute") + .then() + .extract() + .response(); + + Assertions.assertEquals(200, response.statusCode()); + + Assertions.assertNotNull(response.jsonPath().getString("creationTimestamp")); + Assertions.assertNotNull(response.jsonPath().getString("noticeNumber")); + Assertions.assertNotNull(response.jsonPath().getString("noticeTaxCode")); + Assertions.assertNotNull(response.jsonPath().getString("operationType")); + Assertions.assertNotNull(response.jsonPath().getString("paTaxCode")); + Assertions.assertNotNull(response.jsonPath().getString("presetId")); + Assertions.assertNotNull(response.jsonPath().getString("status")); + Assertions.assertNotNull(response.jsonPath().getString("statusTimestamp")); + Assertions.assertNotNull(response.jsonPath().getString("subscriberId")); + PaymentTransaction statDetails = response.jsonPath().getObject("statusDetails", PaymentTransaction.class); + Assertions.assertNotNull(statDetails.getAcquirerId()); + Assertions.assertNotNull(statDetails.getChannel()); + Assertions.assertNotNull(statDetails.getInsertTimestamp()); + Assertions.assertNotNull(statDetails.getAcquirerId()); + Assertions.assertNotNull(statDetails.getStatus()); + Assertions.assertNotNull(statDetails.getNotices()); + List noticesResponse = statDetails.getNotices(); + Assertions.assertNotNull(noticesResponse.get(0).getAmount()); + Assertions.assertNotNull(noticesResponse.get(0).getCompany()); + Assertions.assertNotNull(noticesResponse.get(0).getDescription()); + Assertions.assertNotNull(noticesResponse.get(0).getNoticeNumber()); + Assertions.assertNotNull(noticesResponse.get(0).getOffice()); + Assertions.assertNotNull(noticesResponse.get(0).getPaTaxCode()); + Assertions.assertNotNull(noticesResponse.get(0).getPaymentToken()); + } + + @Test + void getLastPreset_404_presetNotFound() { + + List listOfPresetsEntity = new ArrayList<>(); + + Mockito + .when(presetRepository.list(Mockito.any(String.class), Mockito.any(Sort.class),Mockito.any(Map.class))) + .thenReturn(Uni.createFrom().item(listOfPresetsEntity)); + + Response response = given() + .contentType(ContentType.JSON) + .headers(commonHeaders) + .and() + .when() + .get("/15376371009/x46tr3/last_to_execute") + .then() + .extract() + .response(); + + Assertions.assertEquals(404, response.statusCode()); + + Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_PRESET_OPERATION_NOT_FOUND)); + + Assertions.assertNull(response.jsonPath().getString("creationTimestamp")); + Assertions.assertNull(response.jsonPath().getString("noticeNumber")); + Assertions.assertNull(response.jsonPath().getString("noticeTaxCode")); + Assertions.assertNull(response.jsonPath().getString("operationType")); + Assertions.assertNull(response.jsonPath().getString("paTaxCode")); + Assertions.assertNull(response.jsonPath().getString("presetId")); + Assertions.assertNull(response.jsonPath().getString("status")); + Assertions.assertNull(response.jsonPath().getString("statusTimestamp")); + Assertions.assertNull(response.jsonPath().getString("subscriberId")); + Assertions.assertNull(response.jsonPath().getObject("statusDetails", PaymentTransaction.class)); + } + + @Test + void getLastPreset_500() { + + Mockito + .when(presetRepository.list(Mockito.any(String.class), Mockito.any(Sort.class),Mockito.any(Map.class))) + .thenReturn(Uni.createFrom().failure(new InternalServerErrorException())); + + Response response = given() + .contentType(ContentType.JSON) + .headers(commonHeaders) + .and() + .when() + .get("/15376371009/x46tr3/last_to_execute") + .then() + .extract() + .response(); + + Assertions.assertEquals(500, response.statusCode()); + + Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_COMMUNICATION_MONGO_DB)); + + Assertions.assertNull(response.jsonPath().getString("creationTimestamp")); + Assertions.assertNull(response.jsonPath().getString("noticeNumber")); + Assertions.assertNull(response.jsonPath().getString("noticeTaxCode")); + Assertions.assertNull(response.jsonPath().getString("operationType")); + Assertions.assertNull(response.jsonPath().getString("paTaxCode")); + Assertions.assertNull(response.jsonPath().getString("presetId")); + Assertions.assertNull(response.jsonPath().getString("status")); + Assertions.assertNull(response.jsonPath().getString("statusTimestamp")); + Assertions.assertNull(response.jsonPath().getString("subscriberId")); + Assertions.assertNull(response.jsonPath().getObject("statusDetails", PaymentTransaction.class)); + + } +} diff --git a/src/test/java/it/pagopa/swclient/mil/preset/SubscribeResourceTest.java b/src/test/java/it/pagopa/swclient/mil/preset/SubscribeResourceTest.java new file mode 100644 index 0000000..1834887 --- /dev/null +++ b/src/test/java/it/pagopa/swclient/mil/preset/SubscribeResourceTest.java @@ -0,0 +1,325 @@ +package it.pagopa.swclient.mil.preset; + +import static io.restassured.RestAssured.given; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.mockito.Mockito; + +import io.quarkus.test.common.http.TestHTTPEndpoint; +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.mockito.InjectMock; +import io.restassured.http.ContentType; +import io.restassured.response.Response; +import io.smallrye.mutiny.Uni; +import it.pagopa.swclient.mil.preset.bean.SubscriberRequest; +import it.pagopa.swclient.mil.preset.bean.SubscriberResponse; +import it.pagopa.swclient.mil.preset.dao.SubscriberEntity; +import it.pagopa.swclient.mil.preset.dao.SubscriberRepository; +import it.pagopa.swclient.mil.preset.resource.SubscribeResource; +import jakarta.ws.rs.InternalServerErrorException; + + +@QuarkusTest +@TestHTTPEndpoint(SubscribeResource.class) +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class SubscribeResourceTest { + + final static String SESSION_ID = "a6a666e6-97da-4848-b568-99fedccb642c"; + final static String API_VERSION = "1.0.0-alpha-a.b-c-somethinglong+build.1-aef.1-its-okay"; + final static String PA_TAX_CODE = "15376371009"; + final static String SUBSCRIBER_ID = "y46tr3"; + + @InjectMock + SubscriberRepository subscriberRepository; + + Map commonHeaders; + Map presetHeaders; + + @BeforeAll + void createTestObjects() { + presetHeaders = new HashMap<>(); + presetHeaders.put("RequestId", "d0d654e6-97da-4848-b568-99fedccb642b"); + presetHeaders.put("Version", API_VERSION); + + commonHeaders = new HashMap<>(); + commonHeaders.put("RequestId", "d0d654e6-97da-4848-b568-99fedccb642b"); + commonHeaders.put("Version", API_VERSION); + commonHeaders.put("AcquirerId", "4585625"); + commonHeaders.put("Channel", "ATM"); + commonHeaders.put("TerminalId", "0aB9wXyZ"); + commonHeaders.put("SessionId", SESSION_ID); + } + + /* **** get Subscribers **** */ + @Test + void getSubscribers_200() { + + SubscriberEntity subscriberEntity = new SubscriberEntity(); + subscriberEntity.setAcquirerId("4585625"); + subscriberEntity.setChannel("POS"); + subscriberEntity.setLabel("Reception POS"); + subscriberEntity.setLastUsageTimestamp("2023-05-08T10:55:57"); + subscriberEntity.setMerchantId("28405fHfk73x88D"); + subscriberEntity.setPaTaxCode("15376371009"); + subscriberEntity.setSubscriberId("x46tr3"); + subscriberEntity.setSubscriptionTimestamp("2023-05-05T09:31:33"); + subscriberEntity.setTerminalId("0aB9wXyZ"); + List listOfEntities = new ArrayList<>(); + listOfEntities.add(subscriberEntity); + + Mockito + .when(subscriberRepository.list("paTaxCode",PA_TAX_CODE)) + .thenReturn(Uni.createFrom().item(listOfEntities)); + + Response response = given() + .contentType(ContentType.JSON) + .headers(presetHeaders) + .and() + .when() + .get("/" + PA_TAX_CODE) + .then() + .extract() + .response(); + + Assertions.assertEquals(200, response.statusCode()); + + Assertions.assertNotNull(response.jsonPath().getJsonObject("subscribers")); + List res = response.jsonPath().getList("subscribers", SubscriberResponse.class); + + Assertions.assertNotNull(res.get(0).getChannel()); + Assertions.assertNotNull(res.get(0).getMerchantId()); + Assertions.assertNotNull(res.get(0).getTerminalId()); + Assertions.assertNotNull(res.get(0).getPaTaxCode()); + Assertions.assertNotNull(res.get(0).getSubscriberId()); + Assertions.assertNotNull(res.get(0).getLabel()); + Assertions.assertNotNull(res.get(0).getSubscriptionTimestamp()); + Assertions.assertNotNull(res.get(0).getLastUsageTimestamp()); + } + + @Test + void getSubscribers_200_emptyListOfSubribers() { + + List listOfEntities = new ArrayList<>(); + + Mockito + .when(subscriberRepository.list("paTaxCode","")) + .thenReturn(Uni.createFrom().item(listOfEntities)); + + Response response = given() + .contentType(ContentType.JSON) + .headers(presetHeaders) + .and() + .when() + .get("/" + PA_TAX_CODE) + .then() + .extract() + .response(); + + Assertions.assertEquals(200, response.statusCode()); + + Assertions.assertNotNull(response.jsonPath().getJsonObject("subscribers")); + List res = response.jsonPath().getList("subscribers", SubscriberResponse.class); + + Assertions.assertEquals(0,res.size()); + + } + + @Test + void getSubscribers_500_exceptionMongoDb() { + + Mockito + .when(subscriberRepository.list("paTaxCode",PA_TAX_CODE)) + .thenReturn(Uni.createFrom().failure(new InternalServerErrorException())); + + Response response = given() + .contentType(ContentType.JSON) + .headers(presetHeaders) + .and() + .when() + .get("/" + PA_TAX_CODE) + .then() + .extract() + .response(); + + Assertions.assertEquals(500, response.statusCode()); + Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_COMMUNICATION_MONGO_DB)); + Assertions.assertNull(response.jsonPath().getJsonObject("subcribers")); + } + + /* **** unsubscribe **** */ + @Test + void unsubscriber_200() { + + Mockito + .when(subscriberRepository.delete(Mockito.any(String.class),Mockito.any(Map.class))) + .thenReturn(Uni.createFrom().item(1L)); + + Response response = given() + .contentType(ContentType.JSON) + .headers(commonHeaders) + .and() + .when() + .delete("/" + PA_TAX_CODE + "/" + SUBSCRIBER_ID) + .then() + .extract() + .response(); + + Assertions.assertEquals(204, response.statusCode()); + Assertions.assertEquals(0,response.body().asString().length()); + } + + @Test + void unsubscriber_404() { + + Mockito + .when(subscriberRepository.delete(Mockito.any(String.class),Mockito.any(Map.class))) + .thenReturn(Uni.createFrom().item(0L)); + + Response response = given() + .contentType(ContentType.JSON) + .headers(commonHeaders) + .and() + .when() + .delete("/" + PA_TAX_CODE + "/" + SUBSCRIBER_ID) + .then() + .extract() + .response(); + + Assertions.assertEquals(404, response.statusCode()); + Assertions.assertEquals(0,response.body().asString().length()); + } + + @Test + void unsubscriber_500() { + + Mockito + .when(subscriberRepository.delete(Mockito.any(String.class),Mockito.any(Map.class))) + .thenReturn(Uni.createFrom().failure(new InternalServerErrorException())); + + Response response = given() + .contentType(ContentType.JSON) + .headers(commonHeaders) + .and() + .when() + .delete("/" + PA_TAX_CODE + "/" + SUBSCRIBER_ID) + .then() + .extract() + .response(); + + Assertions.assertEquals(500, response.statusCode()); + Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_COMMUNICATION_MONGO_DB)); + } + + /* **** subscribe **** */ + @Test + void subscribe_200() { + SubscriberEntity entity = new SubscriberEntity(); + entity.setAcquirerId("4585625"); + entity.setChannel("POS"); + entity.setLabel("Reception POS"); + entity.setLastUsageTimestamp("2023-05-15T12:08:58.392"); + entity.setSubscriptionTimestamp("2023-05-15T12:08:58.392"); + entity.setMerchantId("28405fHfk73x88D"); + entity.setPaTaxCode("15376371009"); + entity.setTerminalId("0aB9wXyZ"); + + SubscriberRequest request = new SubscriberRequest(); + request.setPaTaxCode("15376371009"); + request.setLabel("Reception POS"); + + Mockito + .when(subscriberRepository.persist(Mockito.any(SubscriberEntity.class))) + .thenReturn(Uni.createFrom().item(entity)); + + Response response = given() + .contentType(ContentType.JSON) + .headers(commonHeaders) + .body(request) + .and() + .when() + .post() + .then() + .extract() + .response(); + + Assertions.assertEquals(201, response.statusCode()); + Assertions.assertEquals(0,response.body().asString().length()); + Assertions.assertNotNull(response.getHeader(SubscribeResource.LOCATION)); + } + + @Test + void subscribe_409() { + SubscriberEntity entity = new SubscriberEntity(); + entity.setAcquirerId("4585625"); + entity.setChannel("POS"); + entity.setLabel("Reception POS"); + entity.setLastUsageTimestamp("2023-05-15T12:08:58.392"); + entity.setSubscriptionTimestamp("2023-05-15T12:08:58.392"); + entity.setMerchantId("28405fHfk73x88D"); + entity.setPaTaxCode("15376371009"); + entity.setTerminalId("0aB9wXyZ"); + entity.setSubscriberId("2Or8Jw"); + + SubscriberRequest request = new SubscriberRequest(); + request.setPaTaxCode("15376371009"); + request.setLabel("Reception POS"); + + Mockito + .when(subscriberRepository.list(Mockito.any(String.class), Mockito.any(Map.class))) + .thenReturn(Uni.createFrom().item(List.of(entity))); + + Response response = given() + .contentType(ContentType.JSON) + .headers(commonHeaders) + .body(request) + .and() + .when() + .post() + .then() + .extract() + .response(); + + Assertions.assertEquals(409, response.statusCode()); + Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_CONFLICT_TERMINAL_IN_DB)); + Assertions.assertNotNull(response.getHeader(SubscribeResource.LOCATION)); + } + + + @Test + void subscribe_500() { + + SubscriberRequest request = new SubscriberRequest(); + request.setPaTaxCode("15376371009"); + request.setLabel("Reception POS"); + + Mockito + .when(subscriberRepository.list(Mockito.any(String.class), Mockito.any(Map.class))) + .thenReturn(Uni.createFrom().item(new ArrayList())); + + Mockito + .when(subscriberRepository.persist(Mockito.any(SubscriberEntity.class))) + .thenReturn(Uni.createFrom().failure(new InternalServerErrorException())); + + Response response = given() + .contentType(ContentType.JSON) + .headers(commonHeaders) + .body(request) + .and() + .when() + .post() + .then() + .extract() + .response(); + + Assertions.assertEquals(500, response.statusCode()); + Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_STORING_TERMINAL_IN_DB)); + } +} diff --git a/src/test/java/it/pagopa/swclient/mil/preset/it/PresetResourceTestIT.java b/src/test/java/it/pagopa/swclient/mil/preset/it/PresetResourceTestIT.java new file mode 100644 index 0000000..03c7a63 --- /dev/null +++ b/src/test/java/it/pagopa/swclient/mil/preset/it/PresetResourceTestIT.java @@ -0,0 +1,216 @@ +package it.pagopa.swclient.mil.preset.it; + +import static io.restassured.RestAssured.given; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; + +import io.quarkus.test.common.QuarkusTestResource; +import io.quarkus.test.common.http.TestHTTPEndpoint; +import io.quarkus.test.junit.QuarkusIntegrationTest; +import io.restassured.http.ContentType; +import io.restassured.response.Response; +import it.pagopa.swclient.mil.preset.ErrorCode; +import it.pagopa.swclient.mil.preset.bean.Notice; +import it.pagopa.swclient.mil.preset.bean.PaymentTransaction; +import it.pagopa.swclient.mil.preset.bean.PresetRequest; +import it.pagopa.swclient.mil.preset.bean.PresetResponse; +import it.pagopa.swclient.mil.preset.resource.MongoTestResource; +import it.pagopa.swclient.mil.preset.resource.PresetsResource; +import it.pagopa.swclient.mil.preset.resource.SubscribeResource; + +@QuarkusIntegrationTest +@QuarkusTestResource(value=MongoTestResource.class,restrictToAnnotatedClass = true) +@TestHTTPEndpoint(PresetsResource.class) +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class PresetResourceTestIT { + final static String SESSION_ID = "a6a666e6-97da-4848-b568-99fedccb642c"; + final static String API_VERSION = "1.0.0-alpha-a.b-c-somethinglong+build.1-aef.1-its-okay"; + final static String PA_TAX_CODE = "15376371009"; + final static String SUBSCRIBER_ID = "a25tr0"; + + Map commonHeaders; + Map presetHeaders; + + @BeforeAll + void createTestObjects() { + presetHeaders = new HashMap<>(); + presetHeaders.put("RequestId", "d0d654e6-97da-4848-b568-99fedccb642b"); + presetHeaders.put("Version", API_VERSION); + + commonHeaders = new HashMap<>(); + commonHeaders.put("RequestId", "d0d654e6-97da-4848-b568-99fedccb642b"); + commonHeaders.put("Version", API_VERSION); + commonHeaders.put("AcquirerId", "4585625"); + commonHeaders.put("Channel", "POS"); + commonHeaders.put("TerminalId", "0aB9wXyZ"); + commonHeaders.put("SessionId", SESSION_ID); + commonHeaders.put("MerchantId", "4585625"); + } + +// @Test + void createPreset_201() { + + PresetRequest request = new PresetRequest(); + request.setNoticeNumber("485564829563528563"); + request.setNoticeTaxCode("15376371009"); + request.setOperationType("PAYMENT_NOTICE"); + request.setPaTaxCode("15376371009"); + request.setSubscriberId("x46tr4"); + + Response response = given() + .contentType(ContentType.JSON) + .headers(presetHeaders) + .body(request) + .and() + .when() + .post() + .then() + .extract() + .response(); + + Assertions.assertEquals(201, response.statusCode()); + + Assertions.assertNotNull(response.getHeader(SubscribeResource.LOCATION)); + } + + @Test + void createPreset_400_subscriberNotFound() { + + PresetRequest request = new PresetRequest(); + request.setNoticeNumber("485564829563528563"); + request.setNoticeTaxCode("15376371009"); + request.setOperationType("PAYMENT_NOTICE"); + request.setPaTaxCode("15376371111"); + request.setSubscriberId("x46tr4"); + + Response response = given() + .contentType(ContentType.JSON) + .headers(presetHeaders) + .body(request) + .and() + .when() + .post() + .then() + .extract() + .response(); + + Assertions.assertEquals(400, response.statusCode()); + + Assertions.assertNull(response.getHeader(SubscribeResource.LOCATION)); + Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_SUBSCRIBER_NOT_FOUND)); + } + @Test + void getPresets_200() { + Response response = given() + .contentType(ContentType.JSON) + .headers(presetHeaders) + .and() + .when() + .get("/15376371009/x46tr3") + .then() + .extract() + .response(); + + Assertions.assertEquals(200, response.statusCode()); + + Assertions.assertNotNull(response.jsonPath().getJsonObject("presets")); + List arr = response.jsonPath().getList("presets", PresetResponse.class); + + Assertions.assertNotNull(arr.get(0).getCreationTimestamp()); + Assertions.assertNotNull(arr.get(0).getNoticeNumber()); + + Assertions.assertNotNull(arr.get(0).getNoticeTaxCode()); + Assertions.assertNotNull(arr.get(0).getOperationType()); + Assertions.assertNotNull(arr.get(0).getPaTaxCode()); + Assertions.assertNotNull(arr.get(0).getPresetId()); + Assertions.assertNotNull(arr.get(0).getStatus()); + Assertions.assertNotNull(arr.get(0).getStatusTimestamp()); + Assertions.assertNotNull(arr.get(0).getSubscriberId()); + PaymentTransaction statDetails = arr.get(0).getStatusDetails(); + Assertions.assertNotNull(statDetails.getAcquirerId()); + Assertions.assertNotNull(statDetails.getChannel()); + Assertions.assertNotNull(statDetails.getInsertTimestamp()); + Assertions.assertNotNull(statDetails.getAcquirerId()); + Assertions.assertNotNull(statDetails.getStatus()); + Assertions.assertNotNull(statDetails.getNotices()); + List noticesResponse = statDetails.getNotices(); + Assertions.assertNotNull(noticesResponse.get(0).getAmount()); + Assertions.assertNotNull(noticesResponse.get(0).getCompany()); + Assertions.assertNotNull(noticesResponse.get(0).getDescription()); + Assertions.assertNotNull(noticesResponse.get(0).getNoticeNumber()); + Assertions.assertNotNull(noticesResponse.get(0).getOffice()); + Assertions.assertNotNull(noticesResponse.get(0).getPaTaxCode()); + Assertions.assertNotNull(noticesResponse.get(0).getPaymentToken()); + } + + @Test + void getPresets_200_emptyPreset() { + + Response response = given() + .contentType(ContentType.JSON) + .headers(presetHeaders) + .and() + .when() + .get("/15376371009/46t000") + .then() + .extract() + .response(); + + Assertions.assertEquals(200, response.statusCode()); + + Assertions.assertNotNull(response.jsonPath().getJsonObject("presets")); + List arr = response.jsonPath().getList("presets", PresetResponse.class); + + Assertions.assertEquals(0,arr.size()); + } + + @Test + void getLastPreset_200() { + + Response response = given() + .contentType(ContentType.JSON) + .headers(commonHeaders) + .and() + .when() + .get("/15376371009/x46tr3/last_to_execute") + .then() + .extract() + .response(); + + Assertions.assertEquals(200, response.statusCode()); + + Assertions.assertNotNull(response.jsonPath().getString("creationTimestamp")); + Assertions.assertNotNull(response.jsonPath().getString("noticeNumber")); + Assertions.assertNotNull(response.jsonPath().getString("noticeTaxCode")); + Assertions.assertNotNull(response.jsonPath().getString("operationType")); + Assertions.assertNotNull(response.jsonPath().getString("paTaxCode")); + Assertions.assertNotNull(response.jsonPath().getString("presetId")); + Assertions.assertNotNull(response.jsonPath().getString("status")); + Assertions.assertNotNull(response.jsonPath().getString("statusTimestamp")); + Assertions.assertNotNull(response.jsonPath().getString("subscriberId")); + System.out.println(">>>>>" + response.jsonPath()); + Assertions.assertNotNull(response.jsonPath().getJsonObject("statusDetails")); + PaymentTransaction statDetails = response.jsonPath().getObject("statusDetails", PaymentTransaction.class); + Assertions.assertNotNull(statDetails.getChannel()); + Assertions.assertNotNull(statDetails.getInsertTimestamp()); + Assertions.assertNotNull(statDetails.getAcquirerId()); + Assertions.assertNotNull(statDetails.getStatus()); + Assertions.assertNotNull(statDetails.getNotices()); + List noticesResponse = statDetails.getNotices(); + Assertions.assertNotNull(noticesResponse.get(0).getAmount()); + Assertions.assertNotNull(noticesResponse.get(0).getCompany()); + Assertions.assertNotNull(noticesResponse.get(0).getDescription()); + Assertions.assertNotNull(noticesResponse.get(0).getNoticeNumber()); + Assertions.assertNotNull(noticesResponse.get(0).getOffice()); + Assertions.assertNotNull(noticesResponse.get(0).getPaTaxCode()); + Assertions.assertNotNull(noticesResponse.get(0).getPaymentToken()); + } + +} diff --git a/src/test/java/it/pagopa/swclient/mil/preset/it/SubscribeResourceTestIT.java b/src/test/java/it/pagopa/swclient/mil/preset/it/SubscribeResourceTestIT.java new file mode 100644 index 0000000..f23aba1 --- /dev/null +++ b/src/test/java/it/pagopa/swclient/mil/preset/it/SubscribeResourceTestIT.java @@ -0,0 +1,190 @@ +package it.pagopa.swclient.mil.preset.it; + + +import static io.restassured.RestAssured.given; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; + +import io.quarkus.test.common.QuarkusTestResource; +import io.quarkus.test.common.http.TestHTTPEndpoint; +import io.quarkus.test.junit.QuarkusIntegrationTest; +import io.restassured.http.ContentType; +import io.restassured.response.Response; +import it.pagopa.swclient.mil.preset.ErrorCode; +import it.pagopa.swclient.mil.preset.bean.SubscriberRequest; +import it.pagopa.swclient.mil.preset.bean.SubscriberResponse; +import it.pagopa.swclient.mil.preset.resource.MongoTestResource; +import it.pagopa.swclient.mil.preset.resource.SubscribeResource; + + +@QuarkusIntegrationTest +@QuarkusTestResource(value=MongoTestResource.class,restrictToAnnotatedClass = true) +@TestHTTPEndpoint(SubscribeResource.class) +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class SubscribeResourceTestIT { + final static String SESSION_ID = "a6a666e6-97da-4848-b568-99fedccb642c"; + final static String API_VERSION = "1.0.0-alpha-a.b-c-somethinglong+build.1-aef.1-its-okay"; + final static String PA_TAX_CODE = "15376371009"; + final static String SUBSCRIBER_ID = "a25tr0"; + + Map commonHeaders; + Map presetHeaders; + + @BeforeAll + void createTestObjects() { + presetHeaders = new HashMap<>(); + presetHeaders.put("RequestId", "d0d654e6-97da-4848-b568-99fedccb642b"); + presetHeaders.put("Version", API_VERSION); + + commonHeaders = new HashMap<>(); + commonHeaders.put("RequestId", "d0d654e6-97da-4848-b568-99fedccb642b"); + commonHeaders.put("Version", API_VERSION); + commonHeaders.put("AcquirerId", "4585625"); + commonHeaders.put("Channel", "POS"); + commonHeaders.put("TerminalId", "0aB9wXyZ"); + commonHeaders.put("SessionId", SESSION_ID); + commonHeaders.put("MerchantId", "4585625"); + } + + + /* **** get Subscribers **** */ + @Test + void getSubscribers_200() { + + + Response response = given() + .contentType(ContentType.JSON) + .headers(presetHeaders) + .and() + .when() + .get("/" + PA_TAX_CODE) + .then() + .extract() + .response(); + + Assertions.assertEquals(200, response.statusCode()); + + Assertions.assertNotNull(response.jsonPath().getJsonObject("subscribers")); + List res = response.jsonPath().getList("subscribers", SubscriberResponse.class); + System.out.println("RESPONSE " + res); + System.out.println("RESPONSE size " + res.size()); + Assertions.assertNotNull(res.get(0).getChannel()); + Assertions.assertNotNull(res.get(0).getMerchantId()); + Assertions.assertNotNull(res.get(0).getTerminalId()); + Assertions.assertNotNull(res.get(0).getPaTaxCode()); + Assertions.assertNotNull(res.get(0).getSubscriberId()); + Assertions.assertNotNull(res.get(0).getLabel()); + Assertions.assertNotNull(res.get(0).getSubscriptionTimestamp()); + Assertions.assertNotNull(res.get(0).getLastUsageTimestamp()); + } + + @Test + void getSubscribers_200_emptyListOfSubribers() { + + Response response = given() + .contentType(ContentType.JSON) + .headers(presetHeaders) + .and() + .when() + .get("/" + "00000000000") + .then() + .extract() + .response(); + + Assertions.assertEquals(200, response.statusCode()); + + Assertions.assertNotNull(response.jsonPath().getJsonObject("subscribers")); + List res = response.jsonPath().getList("subscribers", SubscriberResponse.class); + + Assertions.assertEquals(0,res.size()); + + } + + /* **** unsubscribe **** */ + @Test + void unsubscriber_200() { + + Response response = given() + .contentType(ContentType.JSON) + .headers(commonHeaders) + .and() + .when() + .delete("/11111111111/a25tr0") + .then() + .extract() + .response(); + + Assertions.assertEquals(204, response.statusCode()); + Assertions.assertEquals(0,response.body().asString().length()); + } + + @Test + void unsubscriber_404() { + + Response response = given() + .contentType(ContentType.JSON) + .headers(commonHeaders) + .and() + .when() + .delete("/" + PA_TAX_CODE + "/a00aa0") + .then() + .extract() + .response(); + + Assertions.assertEquals(404, response.statusCode()); + Assertions.assertEquals(0,response.body().asString().length()); + } + + /* **** subscribe **** */ + @Test + void subscribe_200() { + + SubscriberRequest request = new SubscriberRequest(); + request.setPaTaxCode("34576371029"); + request.setLabel("Reception POS"); + + Response response = given() + .contentType(ContentType.JSON) + .headers(commonHeaders) + .body(request) + .and() + .when() + .post() + .then() + .extract() + .response(); + + Assertions.assertEquals(201, response.statusCode()); + Assertions.assertEquals(0,response.body().asString().length()); + Assertions.assertNotNull(response.getHeader(SubscribeResource.LOCATION)); + } + @Test + void subscribe_409() { + + SubscriberRequest request = new SubscriberRequest(); + request.setPaTaxCode("15376371009"); + request.setLabel("Reception POS"); + + Response response = given() + .contentType(ContentType.JSON) + .headers(commonHeaders) + .body(request) + .and() + .when() + .post() + .then() + .extract() + .response(); + + Assertions.assertEquals(409, response.statusCode()); + Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_CONFLICT_TERMINAL_IN_DB)); + Assertions.assertNotNull(response.getHeader(SubscribeResource.LOCATION)); + } +} diff --git a/src/test/java/it/pagopa/swclient/mil/preset/resource/MongoTestResource.java b/src/test/java/it/pagopa/swclient/mil/preset/resource/MongoTestResource.java new file mode 100644 index 0000000..e72f987 --- /dev/null +++ b/src/test/java/it/pagopa/swclient/mil/preset/resource/MongoTestResource.java @@ -0,0 +1,112 @@ +package it.pagopa.swclient.mil.preset.resource; + +import java.util.Iterator; +import java.util.Map; + +import org.junit.runner.Description; +import org.junit.runners.model.Statement; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testcontainers.containers.Container.ExecResult; +import org.testcontainers.containers.GenericContainer; +//import org.testcontainers.containers.MongoDBContainer; +import org.testcontainers.containers.Network; +import org.testcontainers.containers.output.Slf4jLogConsumer; +import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.utility.DockerImageName; + +import com.google.common.collect.ImmutableMap; + +import io.quarkus.test.common.DevServicesContext; +import io.quarkus.test.common.QuarkusTestResourceLifecycleManager; +public class MongoTestResource implements QuarkusTestResourceLifecycleManager,DevServicesContext.ContextAware { + + private static final Logger logger = LoggerFactory.getLogger(MongoTestResource.class); + private static final String MONGO_NETWORK_ALIAS = "mongo-it"; + + private GenericContainer mongoContainer; + + private DevServicesContext devServicesContext; + + @Override + public void setIntegrationTestContext(DevServicesContext devServicesContext){ + this.devServicesContext = devServicesContext; + } + + + @Override + public Map start() { + + // create a "fake" network using the same id as the one that will be used by Quarkus + // using the network is the only way to make the withNetworkAliases work + logger.info("devServicesContext.containerNetworkId() -> " + devServicesContext.containerNetworkId()); + Network testNetwork = new Network() { + @Override + public String getId() { + return devServicesContext.containerNetworkId().get(); + } + + @Override + public void close() { + + } + + @Override + public Statement apply(Statement statement, Description description) { + return null; + } + }; + + mongoContainer = new GenericContainer<>(DockerImageName.parse("mongo:latest")) + .withNetwork(testNetwork) + .withNetworkAliases(MONGO_NETWORK_ALIAS) + //.withNetworkMode(devServicesContext.containerNetworkId().get()) + .waitingFor(Wait.forListeningPort()); + + mongoContainer.withLogConsumer(new Slf4jLogConsumer(logger)); + + mongoContainer.withFileSystemBind("./src/test/resources", "/home/mongo"); +// mongoContainer.setCommand("--verbose"); + mongoContainer.start(); + + try { + logger.info("----------------------execInContainer START ----------------------"); + + + ExecResult result = mongoContainer.execInContainer("mongosh", "<", "/home/mongo/mongoInit.js"); + + logger.info("----------------------script executed {} ----------------------",result); + + + + logger.info("----------------------execInContainer END ----------------------"); + } catch (Exception e) { + logger.error("ERROR ", e); + e.printStackTrace(); + } + + // Pass the configuration to the application under test + + Map map = ImmutableMap.of( + "quarkus.log.level", "DEBUG", + "quarkus.log.category.\"it.pagopa.swclient.mil.preset\".level", "DEBUG", + "quarkus.mongodb.connection-string","mongodb://" + MONGO_NETWORK_ALIAS + ":" + 27017 + ); + + Iterator> itr = map.entrySet().iterator(); + + while (itr.hasNext()) { + System.out.println(itr.next()); + } + return map; + } + + @Override + public void stop() { + if (null != mongoContainer) { + mongoContainer.stop(); + } + + } + +} diff --git a/src/test/resources/mongoInit.js b/src/test/resources/mongoInit.js new file mode 100644 index 0000000..384212f --- /dev/null +++ b/src/test/resources/mongoInit.js @@ -0,0 +1,103 @@ +db = connect( 'mongodb://localhost/mil' ); + +db.subscribers.insertMany([ + { + _id: 'XYZ13243XXYYZZ', + lastUsageTimestamp: '2023-05-08T10:55:57', + acquirerId: '4585625', + channel: 'POS', + merchantId: '4585625', + terminalId: '0aB9wXyZ', + paTaxCode: '15376371009', + subscriberId: 'x46tr3', + label: 'description', + subscriptionTimestamp: '2023-05-05T09:31:33', + }, + { + _id: 'AYZ13243XXYYZA', + lastUsageTimestamp: '2023-05-08T10:55:57', + acquirerId: '4585625', + channel: 'POS', + merchantId: '4585625', + terminalId: '0aB9wXyZ', + paTaxCode: '11111111111', + subscriberId: 'a25tr0', + label: 'description', + subscriptionTimestamp: '2023-05-05T09:31:33', + } + + ]) + +db.presets.insertMany([ + { + "_id": "77457c64-0870-407a-b2cb-0f948b04fb9a", + "creationTimestamp": "2023-05-16T11:13:55.532", + "noticeNumber": "585564829563528562", + "noticeTaxCode": "15376371009", + "operationType": "PAYMENT_NOTICE", + "paTaxCode": "15376371009", + "presetId": "77457c64-0870-407a-b2cb-0f948b04fb9a", + "status": "TO_EXECUTE", + "statusTimestamp": "2023-05-16T11:13:55.532", + "subscriberId": "x46tr3", + "statusDetails": { + "transactionId": "517a4216840E461fB011036A0fd134E1", + "acquirerId": "4585625", + "channel": "POS", + "merchantId": "28405fHfk73x88D", + "terminalId": "0aB9wXyZ", + "insertTimestamp": "2023-04-11T16:20:34", + "notices": [ + { + "paymentToken": "648fhg36s95jfg7DS", + "paTaxCode": "15376371009", + "noticeNumber": "485564829563528563", + "amount": 12345, + "description": "Health ticket for chest x-ray", + "company": "ASL Roma", + "office": "Ufficio di Roma" + } + ], + "totalAmount": 12395, + "fee": 50, + "status": "PRE_CLOSE" + }, + }, + { + "_id": "66657c64-0870-407a-b2cb-0f948b04fb8b", + "creationTimestamp": "2023-05-16T12:12:52.532", + "noticeNumber": "585564829563528562", + "noticeTaxCode": "15376371009", + "operationType": "PAYMENT_NOTICE", + "paTaxCode": "22276371000", + "presetId": "77457c64-0870-407a-b2cb-0f948b04fb9a", + "status": "TO_EXECUTE", + "statusTimestamp": "2023-05-16T12:12:52.532", + "subscriberId": "aal0aa", + "statusDetails": { + "transactionId": "517a4216840E461fB011036A0fd134E1", + "acquirerId": "4585625", + "channel": "POS", + "merchantId": "28405fHfk73x88D", + "terminalId": "0aB9wXyZ", + "insertTimestamp": "2023-04-11T16:20:34", + "notices": [ + { + "paymentToken": "648fhg36s95jfg7DS", + "paTaxCode": "15376371009", + "noticeNumber": "485564829563528563", + "amount": 12345, + "description": "Health ticket for chest x-ray", + "company": "ASL Roma", + "office": "Ufficio di Roma" + } + ], + "totalAmount": 12395, + "fee": 50, + "status": "PRE_CLOSE" + } + } + +]) + + \ No newline at end of file From 9db2d0d5ba9863923bbc28e61649701371274f9f Mon Sep 17 00:00:00 2001 From: "fabrizio.guerrini" Date: Thu, 25 May 2023 11:19:31 +0200 Subject: [PATCH 2/9] update status preset operation --- pom.xml | 14 + .../swclient/mil/preset/PresetStatus.java | 3 +- .../swclient/mil/preset/bean/Notice.java | 11 +- .../mil/preset/bean/PaymentTransaction.java | 117 +++++-- .../swclient/mil/preset/bean/Preset.java | 93 ++++++ .../mil/preset/dao/PresetsEntity.java | 2 +- .../preset/resource/PresetTopicResource.java | 177 ++++++++++ .../mil/preset/utils/PresetDeserializer.java | 13 + .../mil/preset/utils/PresetSerializer.java | 13 + src/main/resources/application.properties | 25 ++ .../mil/preset/PresetTopicResourceTest.java | 159 +++++++++ .../mil/preset/it/PresetResourceTestIT.java | 314 +++++++++--------- .../preset/it/PresetTopicResourceTestIT.java | 76 +++++ .../preset/it/SubscribeResourceTestIT.java | 268 +++++++-------- .../mil/preset/resource/KafkaResource.java | 26 ++ 15 files changed, 991 insertions(+), 320 deletions(-) create mode 100644 src/main/java/it/pagopa/swclient/mil/preset/bean/Preset.java create mode 100644 src/main/java/it/pagopa/swclient/mil/preset/resource/PresetTopicResource.java create mode 100644 src/main/java/it/pagopa/swclient/mil/preset/utils/PresetDeserializer.java create mode 100644 src/main/java/it/pagopa/swclient/mil/preset/utils/PresetSerializer.java create mode 100644 src/test/java/it/pagopa/swclient/mil/preset/PresetTopicResourceTest.java create mode 100644 src/test/java/it/pagopa/swclient/mil/preset/it/PresetTopicResourceTestIT.java create mode 100644 src/test/java/it/pagopa/swclient/mil/preset/resource/KafkaResource.java diff --git a/pom.xml b/pom.xml index cee7798..6d5b4ec 100644 --- a/pom.xml +++ b/pom.xml @@ -115,6 +115,20 @@ io.quarkus quarkus-rest-client-reactive-jackson + + io.quarkus + quarkus-smallrye-reactive-messaging-kafka + + + io.quarkus + quarkus-test-kafka-companion + test + + + io.smallrye.reactive + smallrye-reactive-messaging-in-memory + test + diff --git a/src/main/java/it/pagopa/swclient/mil/preset/PresetStatus.java b/src/main/java/it/pagopa/swclient/mil/preset/PresetStatus.java index 5aa4dbb..913b904 100644 --- a/src/main/java/it/pagopa/swclient/mil/preset/PresetStatus.java +++ b/src/main/java/it/pagopa/swclient/mil/preset/PresetStatus.java @@ -8,5 +8,6 @@ * */ public enum PresetStatus { - TO_EXECUTE + TO_EXECUTE, + EXECUTED } diff --git a/src/main/java/it/pagopa/swclient/mil/preset/bean/Notice.java b/src/main/java/it/pagopa/swclient/mil/preset/bean/Notice.java index 306b5a8..20748e3 100644 --- a/src/main/java/it/pagopa/swclient/mil/preset/bean/Notice.java +++ b/src/main/java/it/pagopa/swclient/mil/preset/bean/Notice.java @@ -1,5 +1,7 @@ package it.pagopa.swclient.mil.preset.bean; +import java.io.Serializable; + import com.fasterxml.jackson.annotation.JsonInclude; import io.quarkus.runtime.annotations.RegisterForReflection; @@ -14,9 +16,14 @@ * Entity bean containing the data of a payment notice as returned by the activatePayment API of the node */ @RegisterForReflection -public class Notice { +public class Notice implements Serializable{ - /** + /** + *Notice.java + */ + private static final long serialVersionUID = -2280229423335568513L; + + /** * The payment token returned by the node */ @NotNull diff --git a/src/main/java/it/pagopa/swclient/mil/preset/bean/PaymentTransaction.java b/src/main/java/it/pagopa/swclient/mil/preset/bean/PaymentTransaction.java index 4ae31fc..0b2c843 100644 --- a/src/main/java/it/pagopa/swclient/mil/preset/bean/PaymentTransaction.java +++ b/src/main/java/it/pagopa/swclient/mil/preset/bean/PaymentTransaction.java @@ -1,21 +1,27 @@ package it.pagopa.swclient.mil.preset.bean; +import java.io.Serializable; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; + import io.quarkus.runtime.annotations.RegisterForReflection; import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Pattern; -import java.util.List; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonInclude.Include; - /** * Entity bean containing the data of a payment transaction */ @RegisterForReflection -public class PaymentTransaction { +public class PaymentTransaction implements Serializable{ + + /** + *PaymentTransaction.java + */ + private static final long serialVersionUID = -381551586658539004L; /** * The identifier of the payment transaction @@ -70,7 +76,7 @@ public class PaymentTransaction { */ @Min(value = 1) @Max(value = 99999999999L) - private long totalAmount; + private Long totalAmount; /** * The total fee for the payment transaction, retrieved by GEC and passed by the client @@ -121,6 +127,12 @@ public class PaymentTransaction { @Max(value = 19) @JsonInclude(Include.NON_NULL) private String callbackTimestamp; + + /* + * Preset information + */ + @JsonInclude(Include.NON_NULL) + private Preset preset; /** * Gets transactionId @@ -362,25 +374,80 @@ public void setCallbackTimestamp(String callbackTimestamp) { this.callbackTimestamp = callbackTimestamp; } + /** + * @return the preset + */ + public Preset getPreset() { + return preset; + } + + /** + * @param preset the preset to set + */ + public void setPreset(Preset preset) { + this.preset = preset; + } + @Override public String toString() { - final StringBuilder sb = new StringBuilder("PaymentTransaction{"); - sb.append("transactionId='").append(transactionId).append('\''); - sb.append(", acquirerId='").append(acquirerId).append('\''); - sb.append(", channel='").append(channel).append('\''); - sb.append(", merchantId='").append(merchantId).append('\''); - sb.append(", terminalId='").append(terminalId).append('\''); - sb.append(", insertTimestamp='").append(insertTimestamp).append('\''); - sb.append(", notices=").append(notices); - sb.append(", totalAmount=").append(totalAmount); - sb.append(", fee=").append(fee); - sb.append(", status='").append(status).append('\''); - sb.append(", paymentMethod='").append(paymentMethod).append('\''); - sb.append(", paymentTimestamp='").append(paymentTimestamp).append('\''); - sb.append(", closeTimestamp='").append(closeTimestamp).append('\''); - sb.append(", paymentDate='").append(paymentDate).append('\''); - sb.append(", callbackTimestamp='").append(callbackTimestamp).append('\''); - sb.append('}'); - return sb.toString(); + StringBuilder builder = new StringBuilder(); + builder.append("PaymentTransaction [transactionId="); + builder.append(transactionId); + builder.append(", acquirerId="); + builder.append(acquirerId); + builder.append(", channel="); + builder.append(channel); + builder.append(", merchantId="); + builder.append(merchantId); + builder.append(", terminalId="); + builder.append(terminalId); + builder.append(", insertTimestamp="); + builder.append(insertTimestamp); + builder.append(", notices="); + builder.append(notices); + builder.append(", totalAmount="); + builder.append(totalAmount); + builder.append(", fee="); + builder.append(fee); + builder.append(", status="); + builder.append(status); + builder.append(", paymentMethod="); + builder.append(paymentMethod); + builder.append(", paymentTimestamp="); + builder.append(paymentTimestamp); + builder.append(", closeTimestamp="); + builder.append(closeTimestamp); + builder.append(", paymentDate="); + builder.append(paymentDate); + builder.append(", callbackTimestamp="); + builder.append(callbackTimestamp); + builder.append(", preset="); + builder.append(preset); + builder.append("]"); + return builder.toString(); } + +// @Override +// public byte[] serialize(String topic, Object data) { +// System.out.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!11"); +// byte[] bytes = null; +// ByteArrayOutputStream bos = new ByteArrayOutputStream(); +// ObjectOutputStream out = null; +// try { +// out = new ObjectOutputStream(bos); +// out.writeObject(data); +// out.flush(); +// bytes = bos.toByteArray(); +// } catch (IOException e) { +// +// } finally { +// try { +// bos.close(); +// } catch (IOException ex) { +// } +// } +// +// return bytes; +// } + } diff --git a/src/main/java/it/pagopa/swclient/mil/preset/bean/Preset.java b/src/main/java/it/pagopa/swclient/mil/preset/bean/Preset.java new file mode 100644 index 0000000..f9ff8a2 --- /dev/null +++ b/src/main/java/it/pagopa/swclient/mil/preset/bean/Preset.java @@ -0,0 +1,93 @@ +/** + * + */ +package it.pagopa.swclient.mil.preset.bean; + +import java.io.Serializable; + +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; + +public class Preset implements Serializable{ + + /** + *Preset.java + */ + private static final long serialVersionUID = -8846393398844116002L; + + /* + * Tax code of the creditor company + */ + @NotNull + @Pattern(regexp = "^[0-9]{11}$") + private String paTaxCode; + + /* + * Subscriber ID + */ + @NotNull + @Pattern(regexp = "^[0-9a-z]{6}$") + private String subscriberId; + + /* + * Preset Id + */ + @NotNull + @Pattern(regexp = "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$") + private String presetId; + + /** + * @return the paTaxCode + */ + public String getPaTaxCode() { + return paTaxCode; + } + + /** + * @param paTaxCode the paTaxCode to set + */ + public void setPaTaxCode(String paTaxCode) { + this.paTaxCode = paTaxCode; + } + + /** + * @return the subscriberId + */ + public String getSubscriberId() { + return subscriberId; + } + + /** + * @param subscriberId the subscriberId to set + */ + public void setSubscriberId(String subscriberId) { + this.subscriberId = subscriberId; + } + + /** + * @return the presetId + */ + public String getPresetId() { + return presetId; + } + + /** + * @param presetId the presetId to set + */ + public void setPresetId(String presetId) { + this.presetId = presetId; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("Preset [paTaxCode="); + builder.append(paTaxCode); + builder.append(", subscriberId="); + builder.append(subscriberId); + builder.append(", presetId="); + builder.append(presetId); + builder.append("]"); + return builder.toString(); + } +} diff --git a/src/main/java/it/pagopa/swclient/mil/preset/dao/PresetsEntity.java b/src/main/java/it/pagopa/swclient/mil/preset/dao/PresetsEntity.java index b9b3b20..ad92650 100644 --- a/src/main/java/it/pagopa/swclient/mil/preset/dao/PresetsEntity.java +++ b/src/main/java/it/pagopa/swclient/mil/preset/dao/PresetsEntity.java @@ -20,7 +20,7 @@ public class PresetsEntity { /* * Operation type */ - public String operationType; + private String operationType; /* * Preset Id diff --git a/src/main/java/it/pagopa/swclient/mil/preset/resource/PresetTopicResource.java b/src/main/java/it/pagopa/swclient/mil/preset/resource/PresetTopicResource.java new file mode 100644 index 0000000..a0e0ab9 --- /dev/null +++ b/src/main/java/it/pagopa/swclient/mil/preset/resource/PresetTopicResource.java @@ -0,0 +1,177 @@ +/** + * + */ +package it.pagopa.swclient.mil.preset.resource; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletionStage; + +import org.eclipse.microprofile.reactive.messaging.Channel; +import org.eclipse.microprofile.reactive.messaging.Emitter; +import org.eclipse.microprofile.reactive.messaging.Incoming; + +import io.quarkus.logging.Log; +import io.quarkus.panache.common.Parameters; +import io.smallrye.mutiny.Uni; +import it.pagopa.swclient.mil.bean.Errors; +import it.pagopa.swclient.mil.preset.ErrorCode; +import it.pagopa.swclient.mil.preset.PresetStatus; +import it.pagopa.swclient.mil.preset.bean.Notice; +import it.pagopa.swclient.mil.preset.bean.PaymentTransaction; +import it.pagopa.swclient.mil.preset.bean.Preset; +import it.pagopa.swclient.mil.preset.dao.PresetRepository; +import it.pagopa.swclient.mil.preset.dao.PresetsEntity; +import it.pagopa.swclient.mil.preset.utils.DateUtils; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import jakarta.transaction.Transactional; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.InternalServerErrorException; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.Response.Status; + +@ApplicationScoped +@Path("/kafka") //TODO: remove only for test +public class PresetTopicResource { + + @Inject + private PresetRepository presetRepository; +// +// @Inject +// @Channel("presets") +// Emitter testEmitter; +// +// @POST +// @Consumes(MediaType.TEXT_PLAIN) +// public void addPrice() { +// PaymentTransaction transaction = new PaymentTransaction(); +// transaction.setTransactionId("517a4216840E461fB011036A0fd134E1"); +// transaction.setAcquirerId("4585625"); +// transaction.setChannel("POS"); +// transaction.setMerchantId("28405fHfk73x88D"); +// transaction.setTerminalId("0aB9wXyZ"); +// transaction.setInsertTimestamp("2023-04-11T16:20:34"); +// +// Notice notice = new Notice(); +// notice.setPaymentToken("648fhg36s95jfg7DS"); +// notice.setPaTaxCode("15376371009"); +// notice.setNoticeNumber("485564829563528563"); +// notice.setAmount(Long.valueOf("12345")); +// notice.setDescription("Health ticket for chest x-ray"); +// notice.setCompany("ASL Roma 2"); +// notice.setOffice("Office RoMA"); +// List notices = new ArrayList<>(); +// notices.add(notice); +// +// Preset preset = new Preset(); +// preset.setPaTaxCode("15376371009"); +// preset.setSubscriberId("csl0kq"); +// preset.setPresetId("77457c64-0870-407a-b2cb-0f948b04fb9a"); +// transaction.setPreset(preset); +// +// transaction.setNotices(notices); +// +// transaction.setTotalAmount(1000L); +// transaction.setFee(Long.valueOf("50")); +// transaction.setStatus("SSS"); +// transaction.setPaymentMethod("CASH"); +// transaction.setPaymentTimestamp("2023-05-21T09:29:34.526"); +// transaction.setCloseTimestamp("2023-05-21T10:29:34.526"); +// +// +// CompletionStage ack = testEmitter.send(transaction); +// } + + /** + * Update the status and details of a preset operation with type: payment notice + * @param paymentTransaction {@link PaymentTransaction} the data of the payment transaction + * @return + */ + @Incoming("presets") + public Uni consume(PaymentTransaction paymentTransaction) { +// PaymentTransaction paymentTransaction = SerializationUtils.deserialize(data); + Log.debugf("consume Message %s", paymentTransaction); + return findPresetsOperationByPaTaxCodeSubscriberIdAndPresetId(paymentTransaction); + } + + /** + * Finds a preset operation by paTaxCode SubscriberId and PresetId + * @param paymentTransaction {@link PaymentTransaction} the data of the payment transaction + * @return + */ + private Uni findPresetsOperationByPaTaxCodeSubscriberIdAndPresetId(PaymentTransaction paymentTransaction) { + + final String paTaxCode = paymentTransaction.getPreset().getPaTaxCode(); + final String presetId = paymentTransaction.getPreset().getPresetId(); + final String subscriberId = paymentTransaction.getPreset().getSubscriberId(); + Log.debugf("Find Preset Operation By paTaxCode %s, subscriberId %s, presetId %s",paTaxCode,subscriberId,presetId); + return presetRepository.list("paTaxCode = :paTaxCode and subscriberId = :subscriberId and presetId = :presetId", + Parameters.with("paTaxCode", paTaxCode) + .and("subscriberId", subscriberId) + .and("presetId", presetId).map() + ) + .onFailure().transform(err -> { + Log.errorf(err, "[%s] Error while find subscriber", ErrorCode.ERROR_COMMUNICATION_MONGO_DB); + return new InternalServerErrorException(Response + .status(Status.INTERNAL_SERVER_ERROR) + .entity(new Errors(List.of(ErrorCode.ERROR_COMMUNICATION_MONGO_DB))) + .build()); + } + ).chain(m -> { + Log.debugf("Entity Found with paTaxCode %s", m.get(0).getPaTaxCode()); + return !m.isEmpty() ? updatePreset(paymentTransaction,m.get(0)) : null; + }); +// return Uni.createFrom().voidItem(); + } + + + /** + * Update the preset operation with the payment notices, set the status as EXECUTED and update the status timestamp with the current datetime + * @param inputPaymentTransaction {@link PaymentTransaction} the data of the payment transaction + * @param presetEntity {@link PresetsEntity} the preset operation to update + */ + private void mapPresetEntityInformation(PaymentTransaction inputPaymentTransaction, PresetsEntity presetEntity) { + PaymentTransaction paymentTransaction =new PaymentTransaction(); + paymentTransaction.setTransactionId(inputPaymentTransaction.getTransactionId()); + paymentTransaction.setAcquirerId(inputPaymentTransaction.getAcquirerId()); + paymentTransaction.setChannel(inputPaymentTransaction.getChannel()); + paymentTransaction.setMerchantId(inputPaymentTransaction.getMerchantId()); + paymentTransaction.setTerminalId(inputPaymentTransaction.getTerminalId()); + paymentTransaction.setInsertTimestamp(inputPaymentTransaction.getInsertTimestamp()); + paymentTransaction.setNotices(inputPaymentTransaction.getNotices()); + paymentTransaction.setTotalAmount(inputPaymentTransaction.getTotalAmount()); + paymentTransaction.setFee(inputPaymentTransaction.getFee()); + paymentTransaction.setStatus(inputPaymentTransaction.getStatus()); + paymentTransaction.setPaymentMethod(inputPaymentTransaction.getPaymentMethod()); + paymentTransaction.setPaymentTimestamp(inputPaymentTransaction.getPaymentTimestamp()); + paymentTransaction.setCloseTimestamp(inputPaymentTransaction.getCloseTimestamp()); + + + presetEntity.setStatusDetails(paymentTransaction); + presetEntity.setStatus(PresetStatus.EXECUTED.name()); + presetEntity.setStatusTimestamp(DateUtils.getAndFormatCurrentDate()); + } + + /** + * Performs the update on the preset operation + * @param inputPaymentTransaction {@link PaymentTransaction} the data of the payment transaction + * @param presetEntity {@link PresetsEntity} the preset operation to update + * @return + */ + private Uni updatePreset(PaymentTransaction inputPaymentTransaction, PresetsEntity presetEntity) { + Log.debugf("Updating Preset"); + mapPresetEntityInformation(inputPaymentTransaction, presetEntity); + return presetRepository.update(presetEntity) + .onFailure().retry().withBackOff(Duration.ofSeconds(30), Duration.ofSeconds(30)).atMost(2) + .map(m -> { + Log.debugf("Preset Operation By paTaxCode %s, SubscriberId %s, presetId %s",presetEntity.getPaTaxCode(),presetEntity.getSubscriberId(),presetEntity.getPresetId()); +// testEmitter.send("ok"); + return m; + }); + } +} diff --git a/src/main/java/it/pagopa/swclient/mil/preset/utils/PresetDeserializer.java b/src/main/java/it/pagopa/swclient/mil/preset/utils/PresetDeserializer.java new file mode 100644 index 0000000..e38b423 --- /dev/null +++ b/src/main/java/it/pagopa/swclient/mil/preset/utils/PresetDeserializer.java @@ -0,0 +1,13 @@ +/** + * + */ +package it.pagopa.swclient.mil.preset.utils; + +import io.quarkus.kafka.client.serialization.ObjectMapperDeserializer; +import it.pagopa.swclient.mil.preset.bean.PaymentTransaction; + +public class PresetDeserializer extends ObjectMapperDeserializer { + public PresetDeserializer() { + super(PaymentTransaction.class); + } +} diff --git a/src/main/java/it/pagopa/swclient/mil/preset/utils/PresetSerializer.java b/src/main/java/it/pagopa/swclient/mil/preset/utils/PresetSerializer.java new file mode 100644 index 0000000..6699fcf --- /dev/null +++ b/src/main/java/it/pagopa/swclient/mil/preset/utils/PresetSerializer.java @@ -0,0 +1,13 @@ +/** + * + */ +package it.pagopa.swclient.mil.preset.utils; + +import io.quarkus.kafka.client.serialization.ObjectMapperSerializer; +import it.pagopa.swclient.mil.preset.bean.PaymentTransaction; + +public class PresetSerializer extends ObjectMapperSerializer{ + public PresetSerializer() { + super(); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index be5cdc5..fda14a9 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -44,3 +44,28 @@ quarkus.log.min-level=DEBUG quarkus.mongodb.devservices.enabled=false +#%dev.kafka.bootstrap.servers=kafka:9092 +#%prod.kafka.bootstrap.servers=${kafka-bootsrtap-server} +#%test.kafka.bootstrap.servers=kafka:9092 +#mp.messaging.incoming.prices.connector=smallrye-kafka +#quarkus.kafka.devservices.enabled=false + +#%prod.kafka.bootstrap.servers=kafka:9092 +#mp.messaging.outgoing.prices-out.connector=smallrye-kafka +#mp.messaging.outgoing.prices-out.topic=prestes + +#quarkus.reactive-messaging.auto-connector-attachment=false + +#kafka.bootstrap.servers=kafka:9092 +#mp.messaging.incoming.presets.connector=smallrye-kafka +#mp.messaging.incoming.presets.auto.offset.reset=earliest +#mp.messaging.incoming.presets.topic=presets + +#mp.messaging.outgoing.preset-result.connector=smallrye-kafka +#mp.messaging.outgoing.preset-result.topic=preset-result + +#mp.messaging.incoming.presets.connector=smallrye-kafka +#mp.messaging.incoming.presets.topic=presets +#mp.messaging.incoming.presets.value.deserializer=it.pagopa.swclient.mil.preset.utils.PresetDeserializer + +quarkus.http.port=8081 diff --git a/src/test/java/it/pagopa/swclient/mil/preset/PresetTopicResourceTest.java b/src/test/java/it/pagopa/swclient/mil/preset/PresetTopicResourceTest.java new file mode 100644 index 0000000..4f83744 --- /dev/null +++ b/src/test/java/it/pagopa/swclient/mil/preset/PresetTopicResourceTest.java @@ -0,0 +1,159 @@ +package it.pagopa.swclient.mil.preset; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.apache.kafka.clients.producer.ProducerRecord; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.mockito.Mockito; + +import io.quarkus.test.common.QuarkusTestResource; +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.mockito.InjectMock; +import io.quarkus.test.kafka.InjectKafkaCompanion; +import io.quarkus.test.kafka.KafkaCompanionResource; +import io.smallrye.mutiny.Uni; +import io.smallrye.reactive.messaging.kafka.companion.KafkaCompanion; +import io.smallrye.reactive.messaging.kafka.companion.ProducerTask; +import it.pagopa.swclient.mil.preset.bean.Notice; +import it.pagopa.swclient.mil.preset.bean.PaymentTransaction; +import it.pagopa.swclient.mil.preset.bean.Preset; +import it.pagopa.swclient.mil.preset.dao.PresetRepository; +import it.pagopa.swclient.mil.preset.dao.PresetsEntity; +import it.pagopa.swclient.mil.preset.resource.PresetTopicResource; +import it.pagopa.swclient.mil.preset.utils.DateUtils; +import it.pagopa.swclient.mil.preset.utils.PresetSerializer; + + +@QuarkusTest +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +@QuarkusTestResource(KafkaCompanionResource.class) +class PresetTopicResourceTest{ +// + @InjectKafkaCompanion + KafkaCompanion companion; + +// @Inject +// @Channel("presets") +// Emitter emitter; + + @InjectMock + PresetRepository presetRepository; + + @Test + void preset_200() { + + final String timestamp = DateUtils.getAndFormatCurrentDate(); + PresetsEntity presetEntity = new PresetsEntity(); + presetEntity.setId("77457c64-0870-407a-b2cb-0f948b04fb9a"); + presetEntity.setPresetId("77457c64-0870-407a-b2cb-0f948b04fb9a"); + presetEntity.setCreationTimestamp(timestamp); + presetEntity.setNoticeNumber("485564829563528563"); + presetEntity.setNoticeTaxCode("15376371009"); + presetEntity.setOperationType(OperationType.PAYMENT_NOTICE.name()); + presetEntity.setPaTaxCode("15376371009"); + presetEntity.setStatus(PresetStatus.TO_EXECUTE.name()); + presetEntity.setStatusTimestamp(timestamp); + presetEntity.setSubscriberId("csl0kq"); + + Mockito + .when(presetRepository.list(Mockito.any(String.class), Mockito.any(Map.class))) + .thenReturn(Uni.createFrom().item(presetEntity)); + + +// CompletionStage ack = emitter.send(getPaymentTransaction()); + PresetSerializer s = new PresetSerializer(); + ProducerTask producerTask = companion.produce(byte[].class).usingGenerator(i -> new ProducerRecord<>("presets",s.serialize("presets", getPaymentTransaction())),2); + + + +// ProducerTask producerTask = companion.produce(byte[].class).usingGenerator(i -> new ProducerRecord<>("presets",SerializationUtils.serialize(getPaymentTransaction())),1); + long count = producerTask.awaitCompletion().count(); + + System.out.println(">[" + count + "]<"); + +// System.out.println(">>>>b"); +// ConsumerTask consumerTask = companion.consume(byte[].class).fromTopics("preset-result", 1); +// System.out.println(">>>>c"); +// ConsumerRecord lastRecord = consumerTask.awaitCompletion().getLastRecord(); +// +// System.out.println(">>>>d " + lastRecord.topic()); + + + + } + +/* + @Test + void preset_200() { + + CompletionStage ack = testEmitter.send(getPaymentTransaction()); + System.out.println(">>>>a"); + +// ProducerTask producerTask = companion.produce(byte[].class).usingGenerator(i -> new ProducerRecord<>("presets",SerializationUtils.serialize(getPaymentTransaction())),1); +// long count = producerTask.awaitCompletion().count(); +// System.out.println(">[" + count + "]<"); + +// System.out.println(">>>>b"); +// ConsumerTask consumerTask = companion.consume(byte[].class).fromTopics("presets", 1); +// ConsumerRecord lastRecord = consumerTask.awaitCompletion().getLastRecord(); +// +// System.out.println(">>>>c " + new String(lastRecord.value())); + + + +// System.out.println(">>>>"); +// ConsumerTask orders = companion.consumeStrings().fromTopics("presets", 10); +// orders.awaitCompletion(); +// System.out.println(">>>><<<<"); +// assertEquals(10, orders.count()); + +// ProducerRecord p = new ProducerRecord("presets", getPaymentTransaction()); +// companion.produce(p.getClass()); +// +// companion.topics().create("presets", 1); +// +// companion.registerSerde(PaymentTransaction.class, new PaymentTransaction())); +// companion.produce(getPaymentTransaction().getClass()); + } + */ + private PaymentTransaction getPaymentTransaction() { + PaymentTransaction transaction = new PaymentTransaction(); + transaction.setTransactionId("517a4216840E461fB011036A0fd134E1"); + transaction.setAcquirerId("4585625"); + transaction.setChannel("POS"); + transaction.setMerchantId("28405fHfk73x88D"); + transaction.setTerminalId("0aB9wXyZ"); + transaction.setInsertTimestamp("2023-04-11T16:20:34"); + + Notice notice = new Notice(); + notice.setPaymentToken("648fhg36s95jfg7DS"); + notice.setPaTaxCode("15376371009"); + notice.setNoticeNumber("485564829563528563"); + notice.setAmount(Long.valueOf("12345")); + notice.setDescription("Health ticket for chest x-ray"); + notice.setCompany("ASL Roma 2"); + notice.setOffice("Office RoMA"); + List notices = new ArrayList<>(); + notices.add(notice); + + Preset preset = new Preset(); + preset.setPaTaxCode("15376371009"); + preset.setSubscriberId("csl0kq"); + preset.setPresetId("77457c64-0870-407a-b2cb-0f948b04fb9a"); + transaction.setPreset(preset); + + transaction.setNotices(notices); + + transaction.setTotalAmount(1000L); + transaction.setFee(Long.valueOf("50")); + transaction.setStatus("SSS"); + transaction.setPaymentMethod("CASH"); + transaction.setPaymentTimestamp("2023-05-21T09:29:34.526"); + transaction.setCloseTimestamp("2023-05-21T10:29:34.526"); + return transaction; + } + +} diff --git a/src/test/java/it/pagopa/swclient/mil/preset/it/PresetResourceTestIT.java b/src/test/java/it/pagopa/swclient/mil/preset/it/PresetResourceTestIT.java index 03c7a63..dcd038d 100644 --- a/src/test/java/it/pagopa/swclient/mil/preset/it/PresetResourceTestIT.java +++ b/src/test/java/it/pagopa/swclient/mil/preset/it/PresetResourceTestIT.java @@ -55,162 +55,162 @@ void createTestObjects() { } // @Test - void createPreset_201() { - - PresetRequest request = new PresetRequest(); - request.setNoticeNumber("485564829563528563"); - request.setNoticeTaxCode("15376371009"); - request.setOperationType("PAYMENT_NOTICE"); - request.setPaTaxCode("15376371009"); - request.setSubscriberId("x46tr4"); - - Response response = given() - .contentType(ContentType.JSON) - .headers(presetHeaders) - .body(request) - .and() - .when() - .post() - .then() - .extract() - .response(); - - Assertions.assertEquals(201, response.statusCode()); - - Assertions.assertNotNull(response.getHeader(SubscribeResource.LOCATION)); - } - - @Test - void createPreset_400_subscriberNotFound() { - - PresetRequest request = new PresetRequest(); - request.setNoticeNumber("485564829563528563"); - request.setNoticeTaxCode("15376371009"); - request.setOperationType("PAYMENT_NOTICE"); - request.setPaTaxCode("15376371111"); - request.setSubscriberId("x46tr4"); - - Response response = given() - .contentType(ContentType.JSON) - .headers(presetHeaders) - .body(request) - .and() - .when() - .post() - .then() - .extract() - .response(); - - Assertions.assertEquals(400, response.statusCode()); - - Assertions.assertNull(response.getHeader(SubscribeResource.LOCATION)); - Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_SUBSCRIBER_NOT_FOUND)); - } - @Test - void getPresets_200() { - Response response = given() - .contentType(ContentType.JSON) - .headers(presetHeaders) - .and() - .when() - .get("/15376371009/x46tr3") - .then() - .extract() - .response(); - - Assertions.assertEquals(200, response.statusCode()); - - Assertions.assertNotNull(response.jsonPath().getJsonObject("presets")); - List arr = response.jsonPath().getList("presets", PresetResponse.class); - - Assertions.assertNotNull(arr.get(0).getCreationTimestamp()); - Assertions.assertNotNull(arr.get(0).getNoticeNumber()); - - Assertions.assertNotNull(arr.get(0).getNoticeTaxCode()); - Assertions.assertNotNull(arr.get(0).getOperationType()); - Assertions.assertNotNull(arr.get(0).getPaTaxCode()); - Assertions.assertNotNull(arr.get(0).getPresetId()); - Assertions.assertNotNull(arr.get(0).getStatus()); - Assertions.assertNotNull(arr.get(0).getStatusTimestamp()); - Assertions.assertNotNull(arr.get(0).getSubscriberId()); - PaymentTransaction statDetails = arr.get(0).getStatusDetails(); - Assertions.assertNotNull(statDetails.getAcquirerId()); - Assertions.assertNotNull(statDetails.getChannel()); - Assertions.assertNotNull(statDetails.getInsertTimestamp()); - Assertions.assertNotNull(statDetails.getAcquirerId()); - Assertions.assertNotNull(statDetails.getStatus()); - Assertions.assertNotNull(statDetails.getNotices()); - List noticesResponse = statDetails.getNotices(); - Assertions.assertNotNull(noticesResponse.get(0).getAmount()); - Assertions.assertNotNull(noticesResponse.get(0).getCompany()); - Assertions.assertNotNull(noticesResponse.get(0).getDescription()); - Assertions.assertNotNull(noticesResponse.get(0).getNoticeNumber()); - Assertions.assertNotNull(noticesResponse.get(0).getOffice()); - Assertions.assertNotNull(noticesResponse.get(0).getPaTaxCode()); - Assertions.assertNotNull(noticesResponse.get(0).getPaymentToken()); - } - - @Test - void getPresets_200_emptyPreset() { - - Response response = given() - .contentType(ContentType.JSON) - .headers(presetHeaders) - .and() - .when() - .get("/15376371009/46t000") - .then() - .extract() - .response(); - - Assertions.assertEquals(200, response.statusCode()); - - Assertions.assertNotNull(response.jsonPath().getJsonObject("presets")); - List arr = response.jsonPath().getList("presets", PresetResponse.class); - - Assertions.assertEquals(0,arr.size()); - } - - @Test - void getLastPreset_200() { - - Response response = given() - .contentType(ContentType.JSON) - .headers(commonHeaders) - .and() - .when() - .get("/15376371009/x46tr3/last_to_execute") - .then() - .extract() - .response(); - - Assertions.assertEquals(200, response.statusCode()); - - Assertions.assertNotNull(response.jsonPath().getString("creationTimestamp")); - Assertions.assertNotNull(response.jsonPath().getString("noticeNumber")); - Assertions.assertNotNull(response.jsonPath().getString("noticeTaxCode")); - Assertions.assertNotNull(response.jsonPath().getString("operationType")); - Assertions.assertNotNull(response.jsonPath().getString("paTaxCode")); - Assertions.assertNotNull(response.jsonPath().getString("presetId")); - Assertions.assertNotNull(response.jsonPath().getString("status")); - Assertions.assertNotNull(response.jsonPath().getString("statusTimestamp")); - Assertions.assertNotNull(response.jsonPath().getString("subscriberId")); - System.out.println(">>>>>" + response.jsonPath()); - Assertions.assertNotNull(response.jsonPath().getJsonObject("statusDetails")); - PaymentTransaction statDetails = response.jsonPath().getObject("statusDetails", PaymentTransaction.class); - Assertions.assertNotNull(statDetails.getChannel()); - Assertions.assertNotNull(statDetails.getInsertTimestamp()); - Assertions.assertNotNull(statDetails.getAcquirerId()); - Assertions.assertNotNull(statDetails.getStatus()); - Assertions.assertNotNull(statDetails.getNotices()); - List noticesResponse = statDetails.getNotices(); - Assertions.assertNotNull(noticesResponse.get(0).getAmount()); - Assertions.assertNotNull(noticesResponse.get(0).getCompany()); - Assertions.assertNotNull(noticesResponse.get(0).getDescription()); - Assertions.assertNotNull(noticesResponse.get(0).getNoticeNumber()); - Assertions.assertNotNull(noticesResponse.get(0).getOffice()); - Assertions.assertNotNull(noticesResponse.get(0).getPaTaxCode()); - Assertions.assertNotNull(noticesResponse.get(0).getPaymentToken()); - } +// void createPreset_201() { +// +// PresetRequest request = new PresetRequest(); +// request.setNoticeNumber("485564829563528563"); +// request.setNoticeTaxCode("15376371009"); +// request.setOperationType("PAYMENT_NOTICE"); +// request.setPaTaxCode("15376371009"); +// request.setSubscriberId("x46tr4"); +// +// Response response = given() +// .contentType(ContentType.JSON) +// .headers(presetHeaders) +// .body(request) +// .and() +// .when() +// .post() +// .then() +// .extract() +// .response(); +// +// Assertions.assertEquals(201, response.statusCode()); +// +// Assertions.assertNotNull(response.getHeader(SubscribeResource.LOCATION)); +// } +// +// @Test +// void createPreset_400_subscriberNotFound() { +// +// PresetRequest request = new PresetRequest(); +// request.setNoticeNumber("485564829563528563"); +// request.setNoticeTaxCode("15376371009"); +// request.setOperationType("PAYMENT_NOTICE"); +// request.setPaTaxCode("15376371111"); +// request.setSubscriberId("x46tr4"); +// +// Response response = given() +// .contentType(ContentType.JSON) +// .headers(presetHeaders) +// .body(request) +// .and() +// .when() +// .post() +// .then() +// .extract() +// .response(); +// +// Assertions.assertEquals(400, response.statusCode()); +// +// Assertions.assertNull(response.getHeader(SubscribeResource.LOCATION)); +// Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_SUBSCRIBER_NOT_FOUND)); +// } +// @Test +// void getPresets_200() { +// Response response = given() +// .contentType(ContentType.JSON) +// .headers(presetHeaders) +// .and() +// .when() +// .get("/15376371009/x46tr3") +// .then() +// .extract() +// .response(); +// +// Assertions.assertEquals(200, response.statusCode()); +// +// Assertions.assertNotNull(response.jsonPath().getJsonObject("presets")); +// List arr = response.jsonPath().getList("presets", PresetResponse.class); +// +// Assertions.assertNotNull(arr.get(0).getCreationTimestamp()); +// Assertions.assertNotNull(arr.get(0).getNoticeNumber()); +// +// Assertions.assertNotNull(arr.get(0).getNoticeTaxCode()); +// Assertions.assertNotNull(arr.get(0).getOperationType()); +// Assertions.assertNotNull(arr.get(0).getPaTaxCode()); +// Assertions.assertNotNull(arr.get(0).getPresetId()); +// Assertions.assertNotNull(arr.get(0).getStatus()); +// Assertions.assertNotNull(arr.get(0).getStatusTimestamp()); +// Assertions.assertNotNull(arr.get(0).getSubscriberId()); +// PaymentTransaction statDetails = arr.get(0).getStatusDetails(); +// Assertions.assertNotNull(statDetails.getAcquirerId()); +// Assertions.assertNotNull(statDetails.getChannel()); +// Assertions.assertNotNull(statDetails.getInsertTimestamp()); +// Assertions.assertNotNull(statDetails.getAcquirerId()); +// Assertions.assertNotNull(statDetails.getStatus()); +// Assertions.assertNotNull(statDetails.getNotices()); +// List noticesResponse = statDetails.getNotices(); +// Assertions.assertNotNull(noticesResponse.get(0).getAmount()); +// Assertions.assertNotNull(noticesResponse.get(0).getCompany()); +// Assertions.assertNotNull(noticesResponse.get(0).getDescription()); +// Assertions.assertNotNull(noticesResponse.get(0).getNoticeNumber()); +// Assertions.assertNotNull(noticesResponse.get(0).getOffice()); +// Assertions.assertNotNull(noticesResponse.get(0).getPaTaxCode()); +// Assertions.assertNotNull(noticesResponse.get(0).getPaymentToken()); +// } +// +// @Test +// void getPresets_200_emptyPreset() { +// +// Response response = given() +// .contentType(ContentType.JSON) +// .headers(presetHeaders) +// .and() +// .when() +// .get("/15376371009/46t000") +// .then() +// .extract() +// .response(); +// +// Assertions.assertEquals(200, response.statusCode()); +// +// Assertions.assertNotNull(response.jsonPath().getJsonObject("presets")); +// List arr = response.jsonPath().getList("presets", PresetResponse.class); +// +// Assertions.assertEquals(0,arr.size()); +// } +// +// @Test +// void getLastPreset_200() { +// +// Response response = given() +// .contentType(ContentType.JSON) +// .headers(commonHeaders) +// .and() +// .when() +// .get("/15376371009/x46tr3/last_to_execute") +// .then() +// .extract() +// .response(); +// +// Assertions.assertEquals(200, response.statusCode()); +// +// Assertions.assertNotNull(response.jsonPath().getString("creationTimestamp")); +// Assertions.assertNotNull(response.jsonPath().getString("noticeNumber")); +// Assertions.assertNotNull(response.jsonPath().getString("noticeTaxCode")); +// Assertions.assertNotNull(response.jsonPath().getString("operationType")); +// Assertions.assertNotNull(response.jsonPath().getString("paTaxCode")); +// Assertions.assertNotNull(response.jsonPath().getString("presetId")); +// Assertions.assertNotNull(response.jsonPath().getString("status")); +// Assertions.assertNotNull(response.jsonPath().getString("statusTimestamp")); +// Assertions.assertNotNull(response.jsonPath().getString("subscriberId")); +// System.out.println(">>>>>" + response.jsonPath()); +// Assertions.assertNotNull(response.jsonPath().getJsonObject("statusDetails")); +// PaymentTransaction statDetails = response.jsonPath().getObject("statusDetails", PaymentTransaction.class); +// Assertions.assertNotNull(statDetails.getChannel()); +// Assertions.assertNotNull(statDetails.getInsertTimestamp()); +// Assertions.assertNotNull(statDetails.getAcquirerId()); +// Assertions.assertNotNull(statDetails.getStatus()); +// Assertions.assertNotNull(statDetails.getNotices()); +// List noticesResponse = statDetails.getNotices(); +// Assertions.assertNotNull(noticesResponse.get(0).getAmount()); +// Assertions.assertNotNull(noticesResponse.get(0).getCompany()); +// Assertions.assertNotNull(noticesResponse.get(0).getDescription()); +// Assertions.assertNotNull(noticesResponse.get(0).getNoticeNumber()); +// Assertions.assertNotNull(noticesResponse.get(0).getOffice()); +// Assertions.assertNotNull(noticesResponse.get(0).getPaTaxCode()); +// Assertions.assertNotNull(noticesResponse.get(0).getPaymentToken()); +// } } diff --git a/src/test/java/it/pagopa/swclient/mil/preset/it/PresetTopicResourceTestIT.java b/src/test/java/it/pagopa/swclient/mil/preset/it/PresetTopicResourceTestIT.java new file mode 100644 index 0000000..862e84c --- /dev/null +++ b/src/test/java/it/pagopa/swclient/mil/preset/it/PresetTopicResourceTestIT.java @@ -0,0 +1,76 @@ +package it.pagopa.swclient.mil.preset.it; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang3.SerializationUtils; +import org.apache.kafka.clients.producer.ProducerRecord; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; + +import io.quarkus.test.common.QuarkusTestResource; +import io.quarkus.test.junit.QuarkusIntegrationTest; +import io.quarkus.test.kafka.InjectKafkaCompanion; +import io.quarkus.test.kafka.KafkaCompanionResource; +import io.smallrye.reactive.messaging.kafka.companion.KafkaCompanion; +import io.smallrye.reactive.messaging.kafka.companion.ProducerTask; +import it.pagopa.swclient.mil.preset.bean.Notice; +import it.pagopa.swclient.mil.preset.bean.PaymentTransaction; +import it.pagopa.swclient.mil.preset.bean.Preset; + +@QuarkusIntegrationTest +//@QuarkusTestResource(value=MongoTestResource.class,restrictToAnnotatedClass = true) +//@TestHTTPEndpoint(PresetsResource.class) +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +@QuarkusTestResource(KafkaCompanionResource.class) +class PresetTopicResourceTestIT { + @InjectKafkaCompanion + KafkaCompanion companion; + + @Test + void preset_200() { + + ProducerTask producerTask = companion.produce(byte[].class).usingGenerator(i -> new ProducerRecord<>("presets",SerializationUtils.serialize(getPaymentTransaction())),1); + long count = producerTask.awaitCompletion().count(); + System.out.println(">[" + count + "]<"); + System.out.println(">>>>a"); + } + + private PaymentTransaction getPaymentTransaction() { + PaymentTransaction transaction = new PaymentTransaction(); + transaction.setTransactionId("517a4216840E461fB011036A0fd134E1"); + transaction.setAcquirerId("4585625"); + transaction.setChannel("POS"); + transaction.setMerchantId("28405fHfk73x88D"); + transaction.setTerminalId("0aB9wXyZ"); + transaction.setInsertTimestamp("2023-04-11T16:20:34"); + + Notice notice = new Notice(); + notice.setPaymentToken("648fhg36s95jfg7DS"); + notice.setPaTaxCode("15376371009"); + notice.setNoticeNumber("485564829563528563"); + notice.setAmount(Long.valueOf("12345")); + notice.setDescription("Health ticket for chest x-ray"); + notice.setCompany("ASL Roma 2"); + notice.setOffice("Office RoMA"); + List notices = new ArrayList<>(); + notices.add(notice); + + Preset preset = new Preset(); + preset.setPaTaxCode("15376371009"); + preset.setSubscriberId("csl0kq"); + preset.setPresetId("77457c64-0870-407a-b2cb-0f948b04fb9a"); + transaction.setPreset(preset); + + transaction.setNotices(notices); + + transaction.setTotalAmount(1000L); + transaction.setFee(Long.valueOf("50")); + transaction.setStatus("SSS"); + transaction.setPaymentMethod("CASH"); + transaction.setPaymentTimestamp("2023-05-21T09:29:34.526"); + transaction.setCloseTimestamp("2023-05-21T10:29:34.526"); + return transaction; + } + +} diff --git a/src/test/java/it/pagopa/swclient/mil/preset/it/SubscribeResourceTestIT.java b/src/test/java/it/pagopa/swclient/mil/preset/it/SubscribeResourceTestIT.java index f23aba1..f604231 100644 --- a/src/test/java/it/pagopa/swclient/mil/preset/it/SubscribeResourceTestIT.java +++ b/src/test/java/it/pagopa/swclient/mil/preset/it/SubscribeResourceTestIT.java @@ -53,138 +53,138 @@ void createTestObjects() { commonHeaders.put("MerchantId", "4585625"); } - - /* **** get Subscribers **** */ - @Test - void getSubscribers_200() { - - - Response response = given() - .contentType(ContentType.JSON) - .headers(presetHeaders) - .and() - .when() - .get("/" + PA_TAX_CODE) - .then() - .extract() - .response(); - - Assertions.assertEquals(200, response.statusCode()); - - Assertions.assertNotNull(response.jsonPath().getJsonObject("subscribers")); - List res = response.jsonPath().getList("subscribers", SubscriberResponse.class); - System.out.println("RESPONSE " + res); - System.out.println("RESPONSE size " + res.size()); - Assertions.assertNotNull(res.get(0).getChannel()); - Assertions.assertNotNull(res.get(0).getMerchantId()); - Assertions.assertNotNull(res.get(0).getTerminalId()); - Assertions.assertNotNull(res.get(0).getPaTaxCode()); - Assertions.assertNotNull(res.get(0).getSubscriberId()); - Assertions.assertNotNull(res.get(0).getLabel()); - Assertions.assertNotNull(res.get(0).getSubscriptionTimestamp()); - Assertions.assertNotNull(res.get(0).getLastUsageTimestamp()); - } - - @Test - void getSubscribers_200_emptyListOfSubribers() { - - Response response = given() - .contentType(ContentType.JSON) - .headers(presetHeaders) - .and() - .when() - .get("/" + "00000000000") - .then() - .extract() - .response(); - - Assertions.assertEquals(200, response.statusCode()); - - Assertions.assertNotNull(response.jsonPath().getJsonObject("subscribers")); - List res = response.jsonPath().getList("subscribers", SubscriberResponse.class); - - Assertions.assertEquals(0,res.size()); - - } - - /* **** unsubscribe **** */ - @Test - void unsubscriber_200() { - - Response response = given() - .contentType(ContentType.JSON) - .headers(commonHeaders) - .and() - .when() - .delete("/11111111111/a25tr0") - .then() - .extract() - .response(); - - Assertions.assertEquals(204, response.statusCode()); - Assertions.assertEquals(0,response.body().asString().length()); - } - - @Test - void unsubscriber_404() { - - Response response = given() - .contentType(ContentType.JSON) - .headers(commonHeaders) - .and() - .when() - .delete("/" + PA_TAX_CODE + "/a00aa0") - .then() - .extract() - .response(); - - Assertions.assertEquals(404, response.statusCode()); - Assertions.assertEquals(0,response.body().asString().length()); - } - - /* **** subscribe **** */ - @Test - void subscribe_200() { - - SubscriberRequest request = new SubscriberRequest(); - request.setPaTaxCode("34576371029"); - request.setLabel("Reception POS"); - - Response response = given() - .contentType(ContentType.JSON) - .headers(commonHeaders) - .body(request) - .and() - .when() - .post() - .then() - .extract() - .response(); - - Assertions.assertEquals(201, response.statusCode()); - Assertions.assertEquals(0,response.body().asString().length()); - Assertions.assertNotNull(response.getHeader(SubscribeResource.LOCATION)); - } - @Test - void subscribe_409() { - - SubscriberRequest request = new SubscriberRequest(); - request.setPaTaxCode("15376371009"); - request.setLabel("Reception POS"); - - Response response = given() - .contentType(ContentType.JSON) - .headers(commonHeaders) - .body(request) - .and() - .when() - .post() - .then() - .extract() - .response(); - - Assertions.assertEquals(409, response.statusCode()); - Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_CONFLICT_TERMINAL_IN_DB)); - Assertions.assertNotNull(response.getHeader(SubscribeResource.LOCATION)); - } +// +// /* **** get Subscribers **** */ +// @Test +// void getSubscribers_200() { +// +// +// Response response = given() +// .contentType(ContentType.JSON) +// .headers(presetHeaders) +// .and() +// .when() +// .get("/" + PA_TAX_CODE) +// .then() +// .extract() +// .response(); +// +// Assertions.assertEquals(200, response.statusCode()); +// +// Assertions.assertNotNull(response.jsonPath().getJsonObject("subscribers")); +// List res = response.jsonPath().getList("subscribers", SubscriberResponse.class); +// System.out.println("RESPONSE " + res); +// System.out.println("RESPONSE size " + res.size()); +// Assertions.assertNotNull(res.get(0).getChannel()); +// Assertions.assertNotNull(res.get(0).getMerchantId()); +// Assertions.assertNotNull(res.get(0).getTerminalId()); +// Assertions.assertNotNull(res.get(0).getPaTaxCode()); +// Assertions.assertNotNull(res.get(0).getSubscriberId()); +// Assertions.assertNotNull(res.get(0).getLabel()); +// Assertions.assertNotNull(res.get(0).getSubscriptionTimestamp()); +// Assertions.assertNotNull(res.get(0).getLastUsageTimestamp()); +// } +// +// @Test +// void getSubscribers_200_emptyListOfSubribers() { +// +// Response response = given() +// .contentType(ContentType.JSON) +// .headers(presetHeaders) +// .and() +// .when() +// .get("/" + "00000000000") +// .then() +// .extract() +// .response(); +// +// Assertions.assertEquals(200, response.statusCode()); +// +// Assertions.assertNotNull(response.jsonPath().getJsonObject("subscribers")); +// List res = response.jsonPath().getList("subscribers", SubscriberResponse.class); +// +// Assertions.assertEquals(0,res.size()); +// +// } +// +// /* **** unsubscribe **** */ +// @Test +// void unsubscriber_200() { +// +// Response response = given() +// .contentType(ContentType.JSON) +// .headers(commonHeaders) +// .and() +// .when() +// .delete("/11111111111/a25tr0") +// .then() +// .extract() +// .response(); +// +// Assertions.assertEquals(204, response.statusCode()); +// Assertions.assertEquals(0,response.body().asString().length()); +// } +// +// @Test +// void unsubscriber_404() { +// +// Response response = given() +// .contentType(ContentType.JSON) +// .headers(commonHeaders) +// .and() +// .when() +// .delete("/" + PA_TAX_CODE + "/a00aa0") +// .then() +// .extract() +// .response(); +// +// Assertions.assertEquals(404, response.statusCode()); +// Assertions.assertEquals(0,response.body().asString().length()); +// } +// +// /* **** subscribe **** */ +// @Test +// void subscribe_200() { +// +// SubscriberRequest request = new SubscriberRequest(); +// request.setPaTaxCode("34576371029"); +// request.setLabel("Reception POS"); +// +// Response response = given() +// .contentType(ContentType.JSON) +// .headers(commonHeaders) +// .body(request) +// .and() +// .when() +// .post() +// .then() +// .extract() +// .response(); +// +// Assertions.assertEquals(201, response.statusCode()); +// Assertions.assertEquals(0,response.body().asString().length()); +// Assertions.assertNotNull(response.getHeader(SubscribeResource.LOCATION)); +// } +// @Test +// void subscribe_409() { +// +// SubscriberRequest request = new SubscriberRequest(); +// request.setPaTaxCode("15376371009"); +// request.setLabel("Reception POS"); +// +// Response response = given() +// .contentType(ContentType.JSON) +// .headers(commonHeaders) +// .body(request) +// .and() +// .when() +// .post() +// .then() +// .extract() +// .response(); +// +// Assertions.assertEquals(409, response.statusCode()); +// Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_CONFLICT_TERMINAL_IN_DB)); +// Assertions.assertNotNull(response.getHeader(SubscribeResource.LOCATION)); +// } } diff --git a/src/test/java/it/pagopa/swclient/mil/preset/resource/KafkaResource.java b/src/test/java/it/pagopa/swclient/mil/preset/resource/KafkaResource.java new file mode 100644 index 0000000..dcb25a1 --- /dev/null +++ b/src/test/java/it/pagopa/swclient/mil/preset/resource/KafkaResource.java @@ -0,0 +1,26 @@ +/** + * + */ +package it.pagopa.swclient.mil.preset.resource; + +import java.util.HashMap; +import java.util.Map; + +import io.quarkus.test.common.QuarkusTestResourceLifecycleManager; +import io.smallrye.reactive.messaging.memory.InMemoryConnector; + +public class KafkaResource implements QuarkusTestResourceLifecycleManager { + + @Override + public Map start() { + Map env = new HashMap<>(); + Map props1 = InMemoryConnector.switchIncomingChannelsToInMemory("orders"); + env.putAll(props1); + return env; + } + + @Override + public void stop() { + InMemoryConnector.clear(); + } +} From 6373a9147575b64029f09c02636d24636095f48d Mon Sep 17 00:00:00 2001 From: "d.sabatini" Date: Fri, 26 May 2023 22:55:29 +0200 Subject: [PATCH 3/9] Code and test cleanup --- pom.xml | 68 +- .../pagopa/swclient/mil/preset/ErrorCode.java | 14 +- ...tRequest.java => CreatePresetRequest.java} | 8 +- ...sResponse.java => GetPresetsResponse.java} | 15 +- ...ponse.java => GetSubscribersResponse.java} | 25 +- ...ers.java => InstitutionPortalHeaders.java} | 3 +- .../swclient/mil/preset/bean/Notice.java | 13 +- .../mil/preset/bean/PaymentTransaction.java | 40 +- .../preset/bean/PaymentTransactionStatus.java | 16 + .../swclient/mil/preset/bean/Preset.java | 9 +- ...esetResponse.java => PresetOperation.java} | 4 +- .../mil/preset/bean/PresetsPathParam.java | 64 -- ...iberRequest.java => SubscribeRequest.java} | 4 +- ...ubscriberResponse.java => Subscriber.java} | 7 +- ...thParam.java => SubscriberPathParams.java} | 8 +- .../mil/preset/bean/SubscribersPathParam.java | 41 - ...erHeaders.java => UnsubscribeHeaders.java} | 5 +- .../swclient/mil/preset/dao/PresetEntity.java | 25 + .../mil/preset/dao/PresetRepository.java | 2 +- .../mil/preset/dao/PresetsEntity.java | 222 ---- .../mil/preset/dao/SubscriberEntity.java | 199 +--- .../preset/resource/PresetTopicResource.java | 224 ++-- .../mil/preset/resource/PresetsResource.java | 554 +++++----- .../preset/resource/SubscribeResource.java | 297 ------ .../preset/resource/TerminalsResource.java | 255 +++++ .../swclient/mil/preset/utils/DateUtils.java | 26 +- .../constraints/MerchantIdNotNullForPos.java | 8 +- .../MerchantIdNotNullForPosValidator.java | 7 +- src/main/resources/application.properties | 21 +- .../mil/preset/PresetResourceTest.java | 992 +++++++++--------- .../mil/preset/PresetTopicResourceTest.java | 227 ++-- .../mil/preset/SubscribeResourceTest.java | 325 ------ .../mil/preset/TerminalsResourceTest.java | 415 ++++++++ .../mil/preset/it/PresetResourceTestIT.java | 24 +- .../preset/it/PresetTopicResourceTestIT.java | 39 +- .../preset/it/SubscribeResourceTestIT.java | 25 +- .../mil/preset/resource/KafkaResource.java | 26 - .../KafkaTestResourceLifecycleManager.java | 27 + .../preset/resource/MongoTestResource.java | 14 +- .../mil/preset/util/PresetTestData.java | 147 +++ .../swclient/mil/preset/util/TestUtils.java | 206 ++++ 41 files changed, 2182 insertions(+), 2469 deletions(-) rename src/main/java/it/pagopa/swclient/mil/preset/bean/{PresetRequest.java => CreatePresetRequest.java} (89%) rename src/main/java/it/pagopa/swclient/mil/preset/bean/{PresetsResponse.java => GetPresetsResponse.java} (71%) rename src/main/java/it/pagopa/swclient/mil/preset/bean/{SubcribersResponse.java => GetSubscribersResponse.java} (57%) rename src/main/java/it/pagopa/swclient/mil/preset/bean/{PresetHeaders.java => InstitutionPortalHeaders.java} (97%) create mode 100644 src/main/java/it/pagopa/swclient/mil/preset/bean/PaymentTransactionStatus.java rename src/main/java/it/pagopa/swclient/mil/preset/bean/{PresetResponse.java => PresetOperation.java} (98%) delete mode 100644 src/main/java/it/pagopa/swclient/mil/preset/bean/PresetsPathParam.java rename src/main/java/it/pagopa/swclient/mil/preset/bean/{SubscriberRequest.java => SubscribeRequest.java} (86%) rename src/main/java/it/pagopa/swclient/mil/preset/bean/{SubscriberResponse.java => Subscriber.java} (98%) rename src/main/java/it/pagopa/swclient/mil/preset/bean/{UnsubscriberPathParam.java => SubscriberPathParams.java} (81%) delete mode 100644 src/main/java/it/pagopa/swclient/mil/preset/bean/SubscribersPathParam.java rename src/main/java/it/pagopa/swclient/mil/preset/bean/{UnsubscriberHeaders.java => UnsubscribeHeaders.java} (98%) create mode 100644 src/main/java/it/pagopa/swclient/mil/preset/dao/PresetEntity.java delete mode 100644 src/main/java/it/pagopa/swclient/mil/preset/dao/PresetsEntity.java delete mode 100644 src/main/java/it/pagopa/swclient/mil/preset/resource/SubscribeResource.java create mode 100644 src/main/java/it/pagopa/swclient/mil/preset/resource/TerminalsResource.java delete mode 100644 src/test/java/it/pagopa/swclient/mil/preset/SubscribeResourceTest.java create mode 100644 src/test/java/it/pagopa/swclient/mil/preset/TerminalsResourceTest.java delete mode 100644 src/test/java/it/pagopa/swclient/mil/preset/resource/KafkaResource.java create mode 100644 src/test/java/it/pagopa/swclient/mil/preset/resource/KafkaTestResourceLifecycleManager.java create mode 100644 src/test/java/it/pagopa/swclient/mil/preset/util/PresetTestData.java create mode 100644 src/test/java/it/pagopa/swclient/mil/preset/util/TestUtils.java diff --git a/pom.xml b/pom.xml index 6d5b4ec..a83ae56 100644 --- a/pom.xml +++ b/pom.xml @@ -62,19 +62,8 @@ quarkus-mongodb-panache - io.quarkus - quarkus-junit5 - test - - - io.rest-assured - rest-assured - test - - - io.quarkus - quarkus-junit5-mockito - test + org.apache.commons + commons-lang3 it.pagopa.swclient.mil @@ -83,51 +72,50 @@ io.quarkus - quarkus-panache-mock - test + quarkus-container-image-docker - io.quarkus - quarkus-jacoco - test + io.quarkus + quarkus-rest-client-reactive-jackson + + + io.quarkus + quarkus-smallrye-reactive-messaging-kafka - org.jacoco - jacoco-maven-plugin - 0.8.6 + io.smallrye.reactive + smallrye-reactive-messaging-in-memory + test - io.quarkus - quarkus-container-image-docker + org.testcontainers + testcontainers + test - com.github.tomakehurst - wiremock-jre8 - 2.35.0 + io.quarkus + quarkus-junit5 test - org.testcontainers - testcontainers + io.rest-assured + rest-assured test - io.quarkus - quarkus-rest-client-reactive-jackson - - - io.quarkus - quarkus-smallrye-reactive-messaging-kafka + io.quarkus + quarkus-junit5-mockito + test - io.quarkus - quarkus-test-kafka-companion - test + io.quarkus + quarkus-panache-mock + test - io.smallrye.reactive - smallrye-reactive-messaging-in-memory - test + io.quarkus + quarkus-jacoco + test diff --git a/src/main/java/it/pagopa/swclient/mil/preset/ErrorCode.java b/src/main/java/it/pagopa/swclient/mil/preset/ErrorCode.java index 63ed212..49fd1b3 100644 --- a/src/main/java/it/pagopa/swclient/mil/preset/ErrorCode.java +++ b/src/main/java/it/pagopa/swclient/mil/preset/ErrorCode.java @@ -1,20 +1,10 @@ -/* - * ErrorCode.java - * - * 12 dec 2022 - */ - package it.pagopa.swclient.mil.preset; -/** - * - * @author Antonio Tarricone - */ public final class ErrorCode { public static final String MODULE_ID = "00A"; - public static final String PATAX_CODE_MUST_NOT_BE_NULL = MODULE_ID + "000001"; - public static final String PATAX_CODE_MUST_MATCH_REGEXP = MODULE_ID + "000002"; + public static final String PA_TAX_CODE_MUST_NOT_BE_NULL = MODULE_ID + "000001"; + public static final String PA_TAX_CODE_MUST_MATCH_REGEXP = MODULE_ID + "000002"; public static final String ERROR_COMMUNICATION_MONGO_DB = MODULE_ID + "000003"; diff --git a/src/main/java/it/pagopa/swclient/mil/preset/bean/PresetRequest.java b/src/main/java/it/pagopa/swclient/mil/preset/bean/CreatePresetRequest.java similarity index 89% rename from src/main/java/it/pagopa/swclient/mil/preset/bean/PresetRequest.java rename to src/main/java/it/pagopa/swclient/mil/preset/bean/CreatePresetRequest.java index 7579c85..7c902cf 100644 --- a/src/main/java/it/pagopa/swclient/mil/preset/bean/PresetRequest.java +++ b/src/main/java/it/pagopa/swclient/mil/preset/bean/CreatePresetRequest.java @@ -7,12 +7,12 @@ import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Pattern; -public class PresetRequest { +public class CreatePresetRequest { /* * Operation of payment of a notice */ - @NotNull(message = "[" + ErrorCode.PATAX_CODE_MUST_NOT_BE_NULL + "] operationType must not be null") + @NotNull(message = "[" + ErrorCode.PA_TAX_CODE_MUST_NOT_BE_NULL + "] operationType must not be null") @Pattern(regexp = "PAYMENT_NOTICE", message = "[" + ErrorCode.OPERATION_TYPE_MUST_MATCH_REGEXP + "] operationType must match \"{regexp}\"") private String operationType; @@ -20,8 +20,8 @@ public class PresetRequest { /* * Tax code of the creditor company */ - @NotNull(message = "[" + ErrorCode.PATAX_CODE_MUST_NOT_BE_NULL + "] paTaxCode must not be null") - @Pattern(regexp = "^[0-9]{11}$", message = "[" + ErrorCode.PATAX_CODE_MUST_MATCH_REGEXP + "] paTaxCode must match \"{regexp}\"") + @NotNull(message = "[" + ErrorCode.PA_TAX_CODE_MUST_NOT_BE_NULL + "] paTaxCode must not be null") + @Pattern(regexp = "^[0-9]{11}$", message = "[" + ErrorCode.PA_TAX_CODE_MUST_MATCH_REGEXP + "] paTaxCode must match \"{regexp}\"") private String paTaxCode; diff --git a/src/main/java/it/pagopa/swclient/mil/preset/bean/PresetsResponse.java b/src/main/java/it/pagopa/swclient/mil/preset/bean/GetPresetsResponse.java similarity index 71% rename from src/main/java/it/pagopa/swclient/mil/preset/bean/PresetsResponse.java rename to src/main/java/it/pagopa/swclient/mil/preset/bean/GetPresetsResponse.java index 6e41224..6ef21bd 100644 --- a/src/main/java/it/pagopa/swclient/mil/preset/bean/PresetsResponse.java +++ b/src/main/java/it/pagopa/swclient/mil/preset/bean/GetPresetsResponse.java @@ -3,37 +3,38 @@ */ package it.pagopa.swclient.mil.preset.bean; -import java.util.List; - import io.quarkus.runtime.annotations.RegisterForReflection; import jakarta.validation.constraints.NotNull; +import java.util.List; + @RegisterForReflection -public class PresetsResponse { +public class GetPresetsResponse { + /* * List of preset operations */ @NotNull - private List presets; + private List presets; /** * @return the presets */ - public List getPresets() { + public List getPresets() { return presets; } /** * @param presets the presets to set */ - public void setPresets(List presets) { + public void setPresets(List presets) { this.presets = presets; } @Override public String toString() { StringBuilder builder = new StringBuilder(); - builder.append("PresetsResponse [presets="); + builder.append("GetPresetsResponse [presets="); builder.append(presets); builder.append("]"); return builder.toString(); diff --git a/src/main/java/it/pagopa/swclient/mil/preset/bean/SubcribersResponse.java b/src/main/java/it/pagopa/swclient/mil/preset/bean/GetSubscribersResponse.java similarity index 57% rename from src/main/java/it/pagopa/swclient/mil/preset/bean/SubcribersResponse.java rename to src/main/java/it/pagopa/swclient/mil/preset/bean/GetSubscribersResponse.java index 720ea78..d95545e 100644 --- a/src/main/java/it/pagopa/swclient/mil/preset/bean/SubcribersResponse.java +++ b/src/main/java/it/pagopa/swclient/mil/preset/bean/GetSubscribersResponse.java @@ -1,42 +1,41 @@ -/** - * - */ package it.pagopa.swclient.mil.preset.bean; -import java.util.ArrayList; -import java.util.List; - import io.quarkus.runtime.annotations.RegisterForReflection; import jakarta.validation.constraints.NotNull; +import java.util.ArrayList; +import java.util.List; + @RegisterForReflection -public class SubcribersResponse { +public class GetSubscribersResponse { + /* * List of subscribed terminals */ @NotNull - private List subscribers = new ArrayList<>(); + private List subscribers = new ArrayList<>(); /** * @return the subscribers */ - public List getSubscribers() { + public List getSubscribers() { return subscribers; } /** - * @param subscriberResponses the subscribers to set + * @param subscribers the subscribers to set */ - public void setSubscribers(List subscriberResponses) { - this.subscribers = subscriberResponses; + public void setSubscribers(List subscribers) { + this.subscribers = subscribers; } @Override public String toString() { StringBuilder builder = new StringBuilder(); - builder.append("SubcribersResponse [subscribers="); + builder.append("GetSubscribersResponse [subscribers="); builder.append(subscribers); builder.append("]"); return builder.toString(); } + } diff --git a/src/main/java/it/pagopa/swclient/mil/preset/bean/PresetHeaders.java b/src/main/java/it/pagopa/swclient/mil/preset/bean/InstitutionPortalHeaders.java similarity index 97% rename from src/main/java/it/pagopa/swclient/mil/preset/bean/PresetHeaders.java rename to src/main/java/it/pagopa/swclient/mil/preset/bean/InstitutionPortalHeaders.java index a229fbc..0779ff3 100644 --- a/src/main/java/it/pagopa/swclient/mil/preset/bean/PresetHeaders.java +++ b/src/main/java/it/pagopa/swclient/mil/preset/bean/InstitutionPortalHeaders.java @@ -9,7 +9,8 @@ import jakarta.validation.constraints.Size; import jakarta.ws.rs.HeaderParam; -public class PresetHeaders { +public class InstitutionPortalHeaders { + /* * Request ID */ diff --git a/src/main/java/it/pagopa/swclient/mil/preset/bean/Notice.java b/src/main/java/it/pagopa/swclient/mil/preset/bean/Notice.java index 20748e3..c9a2e1c 100644 --- a/src/main/java/it/pagopa/swclient/mil/preset/bean/Notice.java +++ b/src/main/java/it/pagopa/swclient/mil/preset/bean/Notice.java @@ -1,27 +1,18 @@ package it.pagopa.swclient.mil.preset.bean; -import java.io.Serializable; - import com.fasterxml.jackson.annotation.JsonInclude; - +import com.fasterxml.jackson.annotation.JsonInclude.Include; import io.quarkus.runtime.annotations.RegisterForReflection; import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Pattern; -import com.fasterxml.jackson.annotation.JsonInclude.Include; - /** * Entity bean containing the data of a payment notice as returned by the activatePayment API of the node */ @RegisterForReflection -public class Notice implements Serializable{ - - /** - *Notice.java - */ - private static final long serialVersionUID = -2280229423335568513L; +public class Notice { /** * The payment token returned by the node diff --git a/src/main/java/it/pagopa/swclient/mil/preset/bean/PaymentTransaction.java b/src/main/java/it/pagopa/swclient/mil/preset/bean/PaymentTransaction.java index 0b2c843..5d4b27d 100644 --- a/src/main/java/it/pagopa/swclient/mil/preset/bean/PaymentTransaction.java +++ b/src/main/java/it/pagopa/swclient/mil/preset/bean/PaymentTransaction.java @@ -1,27 +1,21 @@ package it.pagopa.swclient.mil.preset.bean; -import java.io.Serializable; -import java.util.List; - import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; - import io.quarkus.runtime.annotations.RegisterForReflection; import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Pattern; +import org.bson.codecs.pojo.annotations.BsonIgnore; + +import java.util.List; /** * Entity bean containing the data of a payment transaction */ @RegisterForReflection -public class PaymentTransaction implements Serializable{ - - /** - *PaymentTransaction.java - */ - private static final long serialVersionUID = -381551586658539004L; +public class PaymentTransaction { /** * The identifier of the payment transaction @@ -87,7 +81,7 @@ public class PaymentTransaction implements Serializable{ private Long fee; /** - * The status of this payment transaction. Can be one of {@link PaymentTransactionStatus} + * The status of this payment transaction */ @NotNull @Pattern(regexp = "PRE_CLOSE|PENDING|ERROR_ON_CLOSE|CLOSED|ERROR_ON_RESULT|ERROR_ON_PAYMENT|ABORTED") @@ -132,6 +126,7 @@ public class PaymentTransaction implements Serializable{ * Preset information */ @JsonInclude(Include.NON_NULL) + @BsonIgnore private Preset preset; /** @@ -427,27 +422,4 @@ public String toString() { return builder.toString(); } -// @Override -// public byte[] serialize(String topic, Object data) { -// System.out.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!11"); -// byte[] bytes = null; -// ByteArrayOutputStream bos = new ByteArrayOutputStream(); -// ObjectOutputStream out = null; -// try { -// out = new ObjectOutputStream(bos); -// out.writeObject(data); -// out.flush(); -// bytes = bos.toByteArray(); -// } catch (IOException e) { -// -// } finally { -// try { -// bos.close(); -// } catch (IOException ex) { -// } -// } -// -// return bytes; -// } - } diff --git a/src/main/java/it/pagopa/swclient/mil/preset/bean/PaymentTransactionStatus.java b/src/main/java/it/pagopa/swclient/mil/preset/bean/PaymentTransactionStatus.java new file mode 100644 index 0000000..61c9165 --- /dev/null +++ b/src/main/java/it/pagopa/swclient/mil/preset/bean/PaymentTransactionStatus.java @@ -0,0 +1,16 @@ +package it.pagopa.swclient.mil.preset.bean; + +/** + * Possible status of a payment transaction + */ +public enum PaymentTransactionStatus { + + PRE_CLOSE, + ERROR_ON_PAYMENT, + PENDING, + CLOSED, + ERROR_ON_CLOSE, + ERROR_ON_RESULT, + ABORTED + +} diff --git a/src/main/java/it/pagopa/swclient/mil/preset/bean/Preset.java b/src/main/java/it/pagopa/swclient/mil/preset/bean/Preset.java index f9ff8a2..12d800e 100644 --- a/src/main/java/it/pagopa/swclient/mil/preset/bean/Preset.java +++ b/src/main/java/it/pagopa/swclient/mil/preset/bean/Preset.java @@ -3,17 +3,10 @@ */ package it.pagopa.swclient.mil.preset.bean; -import java.io.Serializable; - import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Pattern; -public class Preset implements Serializable{ - - /** - *Preset.java - */ - private static final long serialVersionUID = -8846393398844116002L; +public class Preset { /* * Tax code of the creditor company diff --git a/src/main/java/it/pagopa/swclient/mil/preset/bean/PresetResponse.java b/src/main/java/it/pagopa/swclient/mil/preset/bean/PresetOperation.java similarity index 98% rename from src/main/java/it/pagopa/swclient/mil/preset/bean/PresetResponse.java rename to src/main/java/it/pagopa/swclient/mil/preset/bean/PresetOperation.java index e306516..25de49a 100644 --- a/src/main/java/it/pagopa/swclient/mil/preset/bean/PresetResponse.java +++ b/src/main/java/it/pagopa/swclient/mil/preset/bean/PresetOperation.java @@ -9,7 +9,7 @@ import jakarta.validation.constraints.Pattern; @RegisterForReflection -public class PresetResponse { +public class PresetOperation { /* * Operation type */ @@ -221,7 +221,7 @@ public void setStatusDetails(PaymentTransaction statusDetails) { @Override public String toString() { StringBuilder builder = new StringBuilder(); - builder.append("PresetResponse [operationType="); + builder.append("PresetOperation [operationType="); builder.append(operationType); builder.append(", presetId="); builder.append(presetId); diff --git a/src/main/java/it/pagopa/swclient/mil/preset/bean/PresetsPathParam.java b/src/main/java/it/pagopa/swclient/mil/preset/bean/PresetsPathParam.java deleted file mode 100644 index 605ea76..0000000 --- a/src/main/java/it/pagopa/swclient/mil/preset/bean/PresetsPathParam.java +++ /dev/null @@ -1,64 +0,0 @@ -package it.pagopa.swclient.mil.preset.bean; - -import it.pagopa.swclient.mil.preset.ErrorCode; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Pattern; -import jakarta.ws.rs.PathParam; - -public class PresetsPathParam { - - /* - * Tax code of the creditor company - */ - @PathParam(value = "paTaxCode") - @NotNull(message = "[" + ErrorCode.PATAX_CODE_MUST_NOT_BE_NULL + "] paTaxCode must not be null") - @Pattern(regexp = "^[0-9]{11}$", message = "[" + ErrorCode.PATAX_CODE_MUST_MATCH_REGEXP + "] paTaxCode must match \"{regexp}\"") - private String paTaxCode; - - /* - * Subscriber ID - */ - @PathParam(value = "subscriberId") - @NotNull(message = "[" + ErrorCode.SUBSCRIBER_ID_MUST_NOT_BE_NULL + "] subscriberId must not be null") - @Pattern(regexp = "^[0-9a-z]{6}$", message = "[" + ErrorCode.SUBSCRIBER_ID_MUST_MATCH_REGEXP + "] subscriberId must match \"{regexp}\"") - private String subscriberId; - - /** - * @return the paTaxCode - */ - public String getPaTaxCode() { - return paTaxCode; - } - - /** - * @param paTaxCode the paTaxCode to set - */ - public void setPaTaxCode(String paTaxCode) { - this.paTaxCode = paTaxCode; - } - - /** - * @return the subscriberId - */ - public String getSubscriberId() { - return subscriberId; - } - - /** - * @param subscriberId the subscriberId to set - */ - public void setSubscriberId(String subscriberId) { - this.subscriberId = subscriberId; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("PresetsPathParam [paTaxCode="); - builder.append(paTaxCode); - builder.append(", subscriberId="); - builder.append(subscriberId); - builder.append("]"); - return builder.toString(); - } -} diff --git a/src/main/java/it/pagopa/swclient/mil/preset/bean/SubscriberRequest.java b/src/main/java/it/pagopa/swclient/mil/preset/bean/SubscribeRequest.java similarity index 86% rename from src/main/java/it/pagopa/swclient/mil/preset/bean/SubscriberRequest.java rename to src/main/java/it/pagopa/swclient/mil/preset/bean/SubscribeRequest.java index 263a03d..ef5b44e 100644 --- a/src/main/java/it/pagopa/swclient/mil/preset/bean/SubscriberRequest.java +++ b/src/main/java/it/pagopa/swclient/mil/preset/bean/SubscribeRequest.java @@ -6,11 +6,11 @@ import it.pagopa.swclient.mil.preset.ErrorCode; import jakarta.validation.constraints.Pattern; -public class SubscriberRequest { +public class SubscribeRequest { /* * Tax code of the creditor company */ - @Pattern(regexp = "^[0-9]{11}$", message = "[" + ErrorCode.PATAX_CODE_MUST_MATCH_REGEXP + "] paTaxCode must match \"{regexp}\"") + @Pattern(regexp = "^[0-9]{11}$", message = "[" + ErrorCode.PA_TAX_CODE_MUST_MATCH_REGEXP + "] paTaxCode must match \"{regexp}\"") private String paTaxCode; /* diff --git a/src/main/java/it/pagopa/swclient/mil/preset/bean/SubscriberResponse.java b/src/main/java/it/pagopa/swclient/mil/preset/bean/Subscriber.java similarity index 98% rename from src/main/java/it/pagopa/swclient/mil/preset/bean/SubscriberResponse.java rename to src/main/java/it/pagopa/swclient/mil/preset/bean/Subscriber.java index 1a22113..27bfc0f 100644 --- a/src/main/java/it/pagopa/swclient/mil/preset/bean/SubscriberResponse.java +++ b/src/main/java/it/pagopa/swclient/mil/preset/bean/Subscriber.java @@ -1,6 +1,3 @@ -/** - * - */ package it.pagopa.swclient.mil.preset.bean; import io.quarkus.runtime.annotations.RegisterForReflection; @@ -9,14 +6,14 @@ import jakarta.validation.constraints.Pattern; @RegisterForReflection -public class SubscriberResponse { +public class Subscriber { /* * Acquirer ID assigned by PagoPA */ @NotNull @Pattern(regexp = "^\\d{1,11}$") - public String acquirerId; + private String acquirerId; /* * Channel originating the request diff --git a/src/main/java/it/pagopa/swclient/mil/preset/bean/UnsubscriberPathParam.java b/src/main/java/it/pagopa/swclient/mil/preset/bean/SubscriberPathParams.java similarity index 81% rename from src/main/java/it/pagopa/swclient/mil/preset/bean/UnsubscriberPathParam.java rename to src/main/java/it/pagopa/swclient/mil/preset/bean/SubscriberPathParams.java index f91beb1..a4a84c1 100644 --- a/src/main/java/it/pagopa/swclient/mil/preset/bean/UnsubscriberPathParam.java +++ b/src/main/java/it/pagopa/swclient/mil/preset/bean/SubscriberPathParams.java @@ -5,14 +5,14 @@ import jakarta.validation.constraints.Pattern; import jakarta.ws.rs.PathParam; -public class UnsubscriberPathParam { +public class SubscriberPathParams { /* * Tax code of the creditor company */ @PathParam(value = "paTaxCode") - @NotNull(message = "[" + ErrorCode.PATAX_CODE_MUST_NOT_BE_NULL + "] paTaxCode must not be null") - @Pattern(regexp = "^[0-9]{11}$", message = "[" + ErrorCode.PATAX_CODE_MUST_MATCH_REGEXP + "] paTaxCode must match \"{regexp}\"") + @NotNull(message = "[" + ErrorCode.PA_TAX_CODE_MUST_NOT_BE_NULL + "] paTaxCode must not be null") + @Pattern(regexp = "^[0-9]{11}$", message = "[" + ErrorCode.PA_TAX_CODE_MUST_MATCH_REGEXP + "] paTaxCode must match \"{regexp}\"") private String paTaxCode; /* @@ -54,7 +54,7 @@ public void setSubscriberId(String subscriberId) { @Override public String toString() { StringBuilder builder = new StringBuilder(); - builder.append("UnsubscriberPathParam [paTaxCode="); + builder.append("SubscriberPathParams [paTaxCode="); builder.append(paTaxCode); builder.append(", subscriberId="); builder.append(subscriberId); diff --git a/src/main/java/it/pagopa/swclient/mil/preset/bean/SubscribersPathParam.java b/src/main/java/it/pagopa/swclient/mil/preset/bean/SubscribersPathParam.java deleted file mode 100644 index 7c12bcd..0000000 --- a/src/main/java/it/pagopa/swclient/mil/preset/bean/SubscribersPathParam.java +++ /dev/null @@ -1,41 +0,0 @@ -package it.pagopa.swclient.mil.preset.bean; - -import it.pagopa.swclient.mil.preset.ErrorCode; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Pattern; -import jakarta.ws.rs.PathParam; - -public class SubscribersPathParam { - - /* - * Tax code of the creditor company - */ - @PathParam(value = "paTaxCode") - @NotNull(message = "[" + ErrorCode.PATAX_CODE_MUST_NOT_BE_NULL + "] paTaxCode must not be null") - @Pattern(regexp = "^[0-9]{11}$", message = "[" + ErrorCode.PATAX_CODE_MUST_MATCH_REGEXP + "] paTaxCode must match \"{regexp}\"") - private String paTaxCode; - - /** - * @return the paTaxCode - */ - public String getPaTaxCode() { - return paTaxCode; - } - - /** - * @param paTaxCode the paTaxCode to set - */ - public void setPaTaxCode(String paTaxCode) { - this.paTaxCode = paTaxCode; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("SubscribersPathParam [paTaxCode="); - builder.append(paTaxCode); - builder.append("]"); - return builder.toString(); - } - -} diff --git a/src/main/java/it/pagopa/swclient/mil/preset/bean/UnsubscriberHeaders.java b/src/main/java/it/pagopa/swclient/mil/preset/bean/UnsubscribeHeaders.java similarity index 98% rename from src/main/java/it/pagopa/swclient/mil/preset/bean/UnsubscriberHeaders.java rename to src/main/java/it/pagopa/swclient/mil/preset/bean/UnsubscribeHeaders.java index 680e9db..5eba225 100644 --- a/src/main/java/it/pagopa/swclient/mil/preset/bean/UnsubscriberHeaders.java +++ b/src/main/java/it/pagopa/swclient/mil/preset/bean/UnsubscribeHeaders.java @@ -1,6 +1,3 @@ -/** - * - */ package it.pagopa.swclient.mil.preset.bean; import it.pagopa.swclient.mil.ErrorCode; @@ -12,7 +9,7 @@ import jakarta.ws.rs.HeaderParam; @MerchantIdNotNullForPos(message = ErrorCode.MERCHANT_ID_MUST_NOT_BE_NULL_FOR_POS_MSG) -public class UnsubscriberHeaders { +public class UnsubscribeHeaders { /* * Request ID */ diff --git a/src/main/java/it/pagopa/swclient/mil/preset/dao/PresetEntity.java b/src/main/java/it/pagopa/swclient/mil/preset/dao/PresetEntity.java new file mode 100644 index 0000000..124f34d --- /dev/null +++ b/src/main/java/it/pagopa/swclient/mil/preset/dao/PresetEntity.java @@ -0,0 +1,25 @@ +package it.pagopa.swclient.mil.preset.dao; + +import io.quarkus.mongodb.panache.common.MongoEntity; +import it.pagopa.swclient.mil.preset.bean.PresetOperation; +import org.bson.codecs.pojo.annotations.BsonId; + +/** + * Entity of the Preset service + */ +@MongoEntity(database = "mil", collection = "presets") +public class PresetEntity { + + /** + * The preset identifier + */ + @BsonId + public String id; + + /** + * Bean containing the preset operation data + */ + public PresetOperation presetOperation; + +} + diff --git a/src/main/java/it/pagopa/swclient/mil/preset/dao/PresetRepository.java b/src/main/java/it/pagopa/swclient/mil/preset/dao/PresetRepository.java index 7e1b2ee..4d2d186 100644 --- a/src/main/java/it/pagopa/swclient/mil/preset/dao/PresetRepository.java +++ b/src/main/java/it/pagopa/swclient/mil/preset/dao/PresetRepository.java @@ -7,6 +7,6 @@ * MongoDB repository to access the preset information, reactive flavor */ @ApplicationScoped -public class PresetRepository implements ReactivePanacheMongoRepository { +public class PresetRepository implements ReactivePanacheMongoRepository { } \ No newline at end of file diff --git a/src/main/java/it/pagopa/swclient/mil/preset/dao/PresetsEntity.java b/src/main/java/it/pagopa/swclient/mil/preset/dao/PresetsEntity.java deleted file mode 100644 index ad92650..0000000 --- a/src/main/java/it/pagopa/swclient/mil/preset/dao/PresetsEntity.java +++ /dev/null @@ -1,222 +0,0 @@ -package it.pagopa.swclient.mil.preset.dao; - -import org.bson.codecs.pojo.annotations.BsonId; - -import io.quarkus.mongodb.panache.common.MongoEntity; -import it.pagopa.swclient.mil.preset.bean.PaymentTransaction; - -/** - * Entity of the Preset service - */ -@MongoEntity(database = "mil", collection = "presets") -public class PresetsEntity { - - /* - * id set as presetId - */ - @BsonId - private String id; - - /* - * Operation type - */ - private String operationType; - - /* - * Preset Id - */ - private String presetId; - - /* - * Tax code of the creditor company - */ - private String paTaxCode; - - /* - * Subscriber ID - */ - private String subscriberId; - - /* - * Creation timestamp - */ - private String creationTimestamp; - - /* - * Status - */ - private String status; - - /* - * Status timestamp - */ - private String statusTimestamp; - - /* - * Tax code of the creditor company - */ - private String noticeTaxCode; - - /* - * Notice number - */ - private String noticeNumber; - - /* - * Payment status - */ - private PaymentTransaction statusDetails; - /** - * @return the id - */ - public String getId() { - return id; - } - - /** - * @param id the id to set - */ - public void setId(String id) { - this.id = id; - } - - /** - * @return the operationType - */ - public String getOperationType() { - return operationType; - } - - /** - * @param operationType the operationType to set - */ - public void setOperationType(String operationType) { - this.operationType = operationType; - } - - /** - * @return the presetId - */ - public String getPresetId() { - return presetId; - } - - /** - * @param presetId the presetId to set - */ - public void setPresetId(String presetId) { - this.presetId = presetId; - } - - /** - * @return the paTaxCode - */ - public String getPaTaxCode() { - return paTaxCode; - } - - /** - * @param paTaxCode the paTaxCode to set - */ - public void setPaTaxCode(String paTaxCode) { - this.paTaxCode = paTaxCode; - } - - /** - * @return the subscriberId - */ - public String getSubscriberId() { - return subscriberId; - } - - /** - * @param subscriberId the subscriberId to set - */ - public void setSubscriberId(String subscriberId) { - this.subscriberId = subscriberId; - } - - /** - * @return the creationTimestamp - */ - public String getCreationTimestamp() { - return creationTimestamp; - } - - /** - * @param creationTimestamp the creationTimestamp to set - */ - public void setCreationTimestamp(String creationTimestamp) { - this.creationTimestamp = creationTimestamp; - } - - /** - * @return the status - */ - public String getStatus() { - return status; - } - - /** - * @param status the status to set - */ - public void setStatus(String status) { - this.status = status; - } - - /** - * @return the statusTimestamp - */ - public String getStatusTimestamp() { - return statusTimestamp; - } - - /** - * @param statusTimestamp the statusTimestamp to set - */ - public void setStatusTimestamp(String statusTimestamp) { - this.statusTimestamp = statusTimestamp; - } - - /** - * @return the noticeTaxCode - */ - public String getNoticeTaxCode() { - return noticeTaxCode; - } - - /** - * @param noticeTaxCode the noticeTaxCode to set - */ - public void setNoticeTaxCode(String noticeTaxCode) { - this.noticeTaxCode = noticeTaxCode; - } - - /** - * @return the noticeNumber - */ - public String getNoticeNumber() { - return noticeNumber; - } - - /** - * @param noticeNumber the noticeNumber to set - */ - public void setNoticeNumber(String noticeNumber) { - this.noticeNumber = noticeNumber; - } - - /** - * @return the statusDetails - */ - public PaymentTransaction getStatusDetails() { - return statusDetails; - } - - /** - * @param statusDetails the statusDetails to set - */ - public void setStatusDetails(PaymentTransaction statusDetails) { - this.statusDetails = statusDetails; - } -} diff --git a/src/main/java/it/pagopa/swclient/mil/preset/dao/SubscriberEntity.java b/src/main/java/it/pagopa/swclient/mil/preset/dao/SubscriberEntity.java index 14d522f..f19f66f 100644 --- a/src/main/java/it/pagopa/swclient/mil/preset/dao/SubscriberEntity.java +++ b/src/main/java/it/pagopa/swclient/mil/preset/dao/SubscriberEntity.java @@ -1,207 +1,24 @@ package it.pagopa.swclient.mil.preset.dao; -import org.bson.codecs.pojo.annotations.BsonId; - import io.quarkus.mongodb.panache.common.MongoEntity; -import jakarta.validation.constraints.Pattern; +import it.pagopa.swclient.mil.preset.bean.Subscriber; +import org.bson.codecs.pojo.annotations.BsonId; /** - * Entity of the Preset service + * Entity mapping a terminal subscribed for executing preset operations */ @MongoEntity(database = "mil", collection = "subscribers") public class SubscriberEntity { - /* - * id set as subscriber id - */ - @BsonId - private String id; - - /* - * Acquirer ID assigned by PagoPA - */ - public String acquirerId; - - /* - * Channel originating the request - */ - private String channel; - - /* - * Merchant ID. Mandatory when Channel equals POS - */ - private String merchantId; - - /* - * ID of the terminal originating the transaction. It must be unique per acquirer and channel. - */ - private String terminalId; - - /* - * Tax code of the creditor company - */ - private String paTaxCode; - - /* - * Subscriber ID - */ - private String subscriberId; - - - /* - * Mnemonic terminal label - */ - @Pattern(regexp = "^[\\u0001-\\uD7FF\\uE000-\\uFFFD\\u10000-\\u10FFFF]{1,256}$") - private String label; - - /* - * Subscription timestamp - */ - private String subscriptionTimestamp; - - /* - * Last usage timestamp - */ - private String lastUsageTimestamp; - - /** - * @return the id - */ - public String getId() { - return id; - } - - /** - * @param id the id to set - */ - public void setId(String id) { - this.id = id; - } - - /** - * @return the acquirerId - */ - public String getAcquirerId() { - return acquirerId; - } - - /** - * @param acquirerId the acquirerId to set - */ - public void setAcquirerId(String acquirerId) { - this.acquirerId = acquirerId; - } - - /** - * @return the channel - */ - public String getChannel() { - return channel; - } - /** - * @param channel the channel to set + * The id of the subscribed terminal */ - public void setChannel(String channel) { - this.channel = channel; - } - - /** - * @return the merchantId - */ - public String getMerchantId() { - return merchantId; - } - - /** - * @param merchantId the merchantId to set - */ - public void setMerchantId(String merchantId) { - this.merchantId = merchantId; - } - - /** - * @return the terminalId - */ - public String getTerminalId() { - return terminalId; - } - - /** - * @param terminalId the terminalId to set - */ - public void setTerminalId(String terminalId) { - this.terminalId = terminalId; - } - - /** - * @return the paTaxCode - */ - public String getPaTaxCode() { - return paTaxCode; - } - - /** - * @param paTaxCode the paTaxCode to set - */ - public void setPaTaxCode(String paTaxCode) { - this.paTaxCode = paTaxCode; - } - - /** - * @return the subscriberId - */ - public String getSubscriberId() { - return subscriberId; - } - - /** - * @param subscriberId the subscriberId to set - */ - public void setSubscriberId(String subscriberId) { - this.subscriberId = subscriberId; - } - - /** - * @return the label - */ - public String getLabel() { - return label; - } - - /** - * @param label the label to set - */ - public void setLabel(String label) { - this.label = label; - } - - /** - * @return the subscriptionTimestamp - */ - public String getSubscriptionTimestamp() { - return subscriptionTimestamp; - } - - /** - * @param subscriptionTimestamp the subscriptionTimestamp to set - */ - public void setSubscriptionTimestamp(String subscriptionTimestamp) { - this.subscriptionTimestamp = subscriptionTimestamp; - } - - /** - * @return the lastUsageTimestamp - */ - public String getLastUsageTimestamp() { - return lastUsageTimestamp; - } + @BsonId + public String id; /** - * @param lastUsageTimestamp the lastUsageTimestamp to set + * Bean containing the terminal data */ - public void setLastUsageTimestamp(String lastUsageTimestamp) { - this.lastUsageTimestamp = lastUsageTimestamp; - } + public Subscriber subscriber; } diff --git a/src/main/java/it/pagopa/swclient/mil/preset/resource/PresetTopicResource.java b/src/main/java/it/pagopa/swclient/mil/preset/resource/PresetTopicResource.java index a0e0ab9..4c28518 100644 --- a/src/main/java/it/pagopa/swclient/mil/preset/resource/PresetTopicResource.java +++ b/src/main/java/it/pagopa/swclient/mil/preset/resource/PresetTopicResource.java @@ -1,177 +1,95 @@ -/** - * - */ package it.pagopa.swclient.mil.preset.resource; -import java.time.Duration; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CompletionStage; - -import org.eclipse.microprofile.reactive.messaging.Channel; -import org.eclipse.microprofile.reactive.messaging.Emitter; -import org.eclipse.microprofile.reactive.messaging.Incoming; - import io.quarkus.logging.Log; import io.quarkus.panache.common.Parameters; import io.smallrye.mutiny.Uni; -import it.pagopa.swclient.mil.bean.Errors; -import it.pagopa.swclient.mil.preset.ErrorCode; +import io.smallrye.mutiny.unchecked.Unchecked; import it.pagopa.swclient.mil.preset.PresetStatus; -import it.pagopa.swclient.mil.preset.bean.Notice; import it.pagopa.swclient.mil.preset.bean.PaymentTransaction; -import it.pagopa.swclient.mil.preset.bean.Preset; +import it.pagopa.swclient.mil.preset.bean.PaymentTransactionStatus; +import it.pagopa.swclient.mil.preset.dao.PresetEntity; import it.pagopa.swclient.mil.preset.dao.PresetRepository; -import it.pagopa.swclient.mil.preset.dao.PresetsEntity; import it.pagopa.swclient.mil.preset.utils.DateUtils; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; -import jakarta.transaction.Transactional; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.InternalServerErrorException; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.core.Response.Status; +import jakarta.ws.rs.NotFoundException; +import org.eclipse.microprofile.reactive.messaging.Incoming; + +import java.time.Duration; @ApplicationScoped -@Path("/kafka") //TODO: remove only for test public class PresetTopicResource { @Inject - private PresetRepository presetRepository; -// -// @Inject -// @Channel("presets") -// Emitter testEmitter; -// -// @POST -// @Consumes(MediaType.TEXT_PLAIN) -// public void addPrice() { -// PaymentTransaction transaction = new PaymentTransaction(); -// transaction.setTransactionId("517a4216840E461fB011036A0fd134E1"); -// transaction.setAcquirerId("4585625"); -// transaction.setChannel("POS"); -// transaction.setMerchantId("28405fHfk73x88D"); -// transaction.setTerminalId("0aB9wXyZ"); -// transaction.setInsertTimestamp("2023-04-11T16:20:34"); -// -// Notice notice = new Notice(); -// notice.setPaymentToken("648fhg36s95jfg7DS"); -// notice.setPaTaxCode("15376371009"); -// notice.setNoticeNumber("485564829563528563"); -// notice.setAmount(Long.valueOf("12345")); -// notice.setDescription("Health ticket for chest x-ray"); -// notice.setCompany("ASL Roma 2"); -// notice.setOffice("Office RoMA"); -// List notices = new ArrayList<>(); -// notices.add(notice); -// -// Preset preset = new Preset(); -// preset.setPaTaxCode("15376371009"); -// preset.setSubscriberId("csl0kq"); -// preset.setPresetId("77457c64-0870-407a-b2cb-0f948b04fb9a"); -// transaction.setPreset(preset); -// -// transaction.setNotices(notices); -// -// transaction.setTotalAmount(1000L); -// transaction.setFee(Long.valueOf("50")); -// transaction.setStatus("SSS"); -// transaction.setPaymentMethod("CASH"); -// transaction.setPaymentTimestamp("2023-05-21T09:29:34.526"); -// transaction.setCloseTimestamp("2023-05-21T10:29:34.526"); -// -// -// CompletionStage ack = testEmitter.send(transaction); -// } - - /** - * Update the status and details of a preset operation with type: payment notice - * @param paymentTransaction {@link PaymentTransaction} the data of the payment transaction - * @return - */ - @Incoming("presets") - public Uni consume(PaymentTransaction paymentTransaction) { -// PaymentTransaction paymentTransaction = SerializationUtils.deserialize(data); - Log.debugf("consume Message %s", paymentTransaction); - return findPresetsOperationByPaTaxCodeSubscriberIdAndPresetId(paymentTransaction); - } - - /** - * Finds a preset operation by paTaxCode SubscriberId and PresetId - * @param paymentTransaction {@link PaymentTransaction} the data of the payment transaction - * @return - */ - private Uni findPresetsOperationByPaTaxCodeSubscriberIdAndPresetId(PaymentTransaction paymentTransaction) { - - final String paTaxCode = paymentTransaction.getPreset().getPaTaxCode(); - final String presetId = paymentTransaction.getPreset().getPresetId(); - final String subscriberId = paymentTransaction.getPreset().getSubscriberId(); - Log.debugf("Find Preset Operation By paTaxCode %s, subscriberId %s, presetId %s",paTaxCode,subscriberId,presetId); - return presetRepository.list("paTaxCode = :paTaxCode and subscriberId = :subscriberId and presetId = :presetId", - Parameters.with("paTaxCode", paTaxCode) - .and("subscriberId", subscriberId) - .and("presetId", presetId).map() - ) - .onFailure().transform(err -> { - Log.errorf(err, "[%s] Error while find subscriber", ErrorCode.ERROR_COMMUNICATION_MONGO_DB); - return new InternalServerErrorException(Response - .status(Status.INTERNAL_SERVER_ERROR) - .entity(new Errors(List.of(ErrorCode.ERROR_COMMUNICATION_MONGO_DB))) - .build()); - } - ).chain(m -> { - Log.debugf("Entity Found with paTaxCode %s", m.get(0).getPaTaxCode()); - return !m.isEmpty() ? updatePreset(paymentTransaction,m.get(0)) : null; - }); -// return Uni.createFrom().voidItem(); + PresetRepository presetRepository; + + /** + * Update the status and details of a preset operation with type: payment notice + * + * @param paymentTransaction {@link PaymentTransaction} the data of the payment transaction + */ + @Incoming("presets") + public void consume(PaymentTransaction paymentTransaction) { + Log.debugf("Consume Message %s", paymentTransaction); + findPresetsOperation(paymentTransaction) + .chain(entity -> updatePreset(paymentTransaction, entity)) + .subscribe() + .with( + item -> { + Log.debugf("Item updated %s", item); + }, + error -> { + Log.debugf("Error while updating item", error); + } + ); } - - /** - * Update the preset operation with the payment notices, set the status as EXECUTED and update the status timestamp with the current datetime - * @param inputPaymentTransaction {@link PaymentTransaction} the data of the payment transaction - * @param presetEntity {@link PresetsEntity} the preset operation to update - */ - private void mapPresetEntityInformation(PaymentTransaction inputPaymentTransaction, PresetsEntity presetEntity) { - PaymentTransaction paymentTransaction =new PaymentTransaction(); - paymentTransaction.setTransactionId(inputPaymentTransaction.getTransactionId()); - paymentTransaction.setAcquirerId(inputPaymentTransaction.getAcquirerId()); - paymentTransaction.setChannel(inputPaymentTransaction.getChannel()); - paymentTransaction.setMerchantId(inputPaymentTransaction.getMerchantId()); - paymentTransaction.setTerminalId(inputPaymentTransaction.getTerminalId()); - paymentTransaction.setInsertTimestamp(inputPaymentTransaction.getInsertTimestamp()); - paymentTransaction.setNotices(inputPaymentTransaction.getNotices()); - paymentTransaction.setTotalAmount(inputPaymentTransaction.getTotalAmount()); - paymentTransaction.setFee(inputPaymentTransaction.getFee()); - paymentTransaction.setStatus(inputPaymentTransaction.getStatus()); - paymentTransaction.setPaymentMethod(inputPaymentTransaction.getPaymentMethod()); - paymentTransaction.setPaymentTimestamp(inputPaymentTransaction.getPaymentTimestamp()); - paymentTransaction.setCloseTimestamp(inputPaymentTransaction.getCloseTimestamp()); + /** + * Finds a preset operation by paTaxCode SubscriberId and PresetId + * + * @param paymentTransaction {@link PaymentTransaction} the data of the payment transaction + * @return an {@link Uni} emitting the found {@link PresetEntity} + */ + private Uni findPresetsOperation(PaymentTransaction paymentTransaction) { + + final String paTaxCode = paymentTransaction.getPreset().getPaTaxCode(); + final String presetId = paymentTransaction.getPreset().getPresetId(); + final String subscriberId = paymentTransaction.getPreset().getSubscriberId(); + Log.debugf("Find preset operation By paTaxCode %s, subscriberId %s, presetId %s", paTaxCode, subscriberId, presetId); + + return presetRepository.list("presetOperation.paTaxCode = :paTaxCode and presetOperation.subscriberId = :subscriberId and presetOperation.presetId = :presetId", + Parameters.with("paTaxCode", paTaxCode) + .and("subscriberId", subscriberId) + .and("presetId", presetId) + .map()) + .onItem().transform(Unchecked.function(e -> { + if (e.isEmpty()) { + Log.errorf("No preset found with id %s", presetId); + throw new NotFoundException(); + } + else return e.get(0); + })); + } - presetEntity.setStatusDetails(paymentTransaction); - presetEntity.setStatus(PresetStatus.EXECUTED.name()); - presetEntity.setStatusTimestamp(DateUtils.getAndFormatCurrentDate()); - } - - /** - * Performs the update on the preset operation - * @param inputPaymentTransaction {@link PaymentTransaction} the data of the payment transaction - * @param presetEntity {@link PresetsEntity} the preset operation to update - * @return - */ - private Uni updatePreset(PaymentTransaction inputPaymentTransaction, PresetsEntity presetEntity) { + /** + * Performs the update on the preset operation + * + * @param inputPaymentTransaction {@link PaymentTransaction} the data of the payment transaction + * @param presetEntity {@link PresetEntity} the preset operation to update + * @return + */ + private Uni updatePreset(PaymentTransaction inputPaymentTransaction, PresetEntity presetEntity) { Log.debugf("Updating Preset"); - mapPresetEntityInformation(inputPaymentTransaction, presetEntity); + + if (!PaymentTransactionStatus.PRE_CLOSE.name().equals(inputPaymentTransaction.getStatus())) { + presetEntity.presetOperation.setStatus(PresetStatus.EXECUTED.name()); + } + presetEntity.presetOperation.setStatusTimestamp(DateUtils.getCurrentTimestamp()); + presetEntity.presetOperation.setStatusDetails(inputPaymentTransaction); + return presetRepository.update(presetEntity) - .onFailure().retry().withBackOff(Duration.ofSeconds(30), Duration.ofSeconds(30)).atMost(2) - .map(m -> { - Log.debugf("Preset Operation By paTaxCode %s, SubscriberId %s, presetId %s",presetEntity.getPaTaxCode(),presetEntity.getSubscriberId(),presetEntity.getPresetId()); -// testEmitter.send("ok"); - return m; - }); + .onFailure().retry().withBackOff(Duration.ofSeconds(30), Duration.ofSeconds(30)).atMost(2); } + } diff --git a/src/main/java/it/pagopa/swclient/mil/preset/resource/PresetsResource.java b/src/main/java/it/pagopa/swclient/mil/preset/resource/PresetsResource.java index fbbc520..16d75f6 100644 --- a/src/main/java/it/pagopa/swclient/mil/preset/resource/PresetsResource.java +++ b/src/main/java/it/pagopa/swclient/mil/preset/resource/PresetsResource.java @@ -1,13 +1,5 @@ -/** - * - */ package it.pagopa.swclient.mil.preset.resource; -import java.time.Duration; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - import io.quarkus.logging.Log; import io.quarkus.panache.common.Parameters; import io.quarkus.panache.common.Sort; @@ -17,292 +9,298 @@ import it.pagopa.swclient.mil.preset.ErrorCode; import it.pagopa.swclient.mil.preset.OperationType; import it.pagopa.swclient.mil.preset.PresetStatus; -import it.pagopa.swclient.mil.preset.bean.PresetHeaders; -import it.pagopa.swclient.mil.preset.bean.PresetRequest; -import it.pagopa.swclient.mil.preset.bean.PresetResponse; -import it.pagopa.swclient.mil.preset.bean.PresetsPathParam; -import it.pagopa.swclient.mil.preset.bean.PresetsResponse; +import it.pagopa.swclient.mil.preset.bean.CreatePresetRequest; +import it.pagopa.swclient.mil.preset.bean.GetPresetsResponse; +import it.pagopa.swclient.mil.preset.bean.InstitutionPortalHeaders; +import it.pagopa.swclient.mil.preset.bean.PresetOperation; +import it.pagopa.swclient.mil.preset.bean.Subscriber; +import it.pagopa.swclient.mil.preset.bean.SubscriberPathParams; +import it.pagopa.swclient.mil.preset.dao.PresetEntity; import it.pagopa.swclient.mil.preset.dao.PresetRepository; -import it.pagopa.swclient.mil.preset.dao.PresetsEntity; import it.pagopa.swclient.mil.preset.dao.SubscriberEntity; import it.pagopa.swclient.mil.preset.dao.SubscriberRepository; import it.pagopa.swclient.mil.preset.utils.DateUtils; import jakarta.inject.Inject; import jakarta.validation.Valid; import jakarta.ws.rs.BeanParam; +import jakarta.ws.rs.Consumes; import jakarta.ws.rs.GET; import jakarta.ws.rs.InternalServerErrorException; import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.Response.Status; +import org.eclipse.microprofile.config.inject.ConfigProperty; + +import java.net.URI; +import java.util.List; +import java.util.UUID; @Path("/presets") public class PresetsResource { - + + public static final String SUBSCRIBER_FILTER = "subscriber.paTaxCode = :paTaxCode and subscriber.subscriberId = :subscriberId"; + public static final String PRESET_FILTER = "presetOperation.paTaxCode = :paTaxCode and presetOperation.subscriberId = :subscriberId"; + + public static final String LAST_PRESET_FILTER = PRESET_FILTER + " and presetOperation.status = 'TO_EXECUTE'"; + + /** + * The base URL for the location header returned by the createPreset API (i.e. the API management base URL) + */ + @ConfigProperty(name="preset.location.base-url") + String presetLocationBaseURL; + + @Inject - private PresetRepository presetRepository; - - @Inject - private SubscriberRepository subscriberRepository; - - /** - * Creates Preset Operation - * @param headers a set of mandatory headers - * @param presetRequest {@link PresetRequest} containing the request parameters - * @return HttpStatus CREATED. Preset operation created successfully - */ - @POST - public Uni createPreset(@Valid @BeanParam PresetHeaders headers, @Valid PresetRequest presetRequest) { - Log.debugf("createPreset - Input parameters: %s, request: %s", headers, presetRequest); - return findSubscriberByTaxCodeAndSubscriberId(presetRequest.getPaTaxCode(), presetRequest.getSubscriberId()) - .onFailure().transform(f -> f) - .chain(entity -> { - if (entity == null) { - Log.errorf("[%s] No subscriber found", ErrorCode.ERROR_SUBSCRIBER_NOT_FOUND); - return Uni.createFrom().item( - Response.status(Status.BAD_REQUEST) - .entity(new Errors(List.of(ErrorCode.ERROR_SUBSCRIBER_NOT_FOUND))) - .build()); - } else { - Log.debugf("Subscriber found. Update the Last Usage Timestamp"); - entity.setLastUsageTimestamp(DateUtils.getAndFormatCurrentDate()); - return updateSubscriber(entity).chain(m -> { - Log.debugf("Generating new UUID ... "); - final String uuid = UUID.randomUUID().toString(); - Log.debugf("UUID %s generated ", uuid); - return persist(entity, presetRequest, uuid); - }); - - } - }); - } - - /** - * Returns preset Operations for a specific subscriber - * @param headers a set of mandatory headers - * @param pathParams {@link PresetsPathParam} contains the path parameters: paTaxCode and subscriberId - * @return the presets operation for a specific subscriber - */ - @GET - @Path("/{paTaxCode}/{subscriberId}") - public Uni getPresetsOperations(@Valid @BeanParam PresetHeaders headers, @Valid PresetsPathParam pathParams) { - Log.debugf("getPresetsOperations - Input parameters: %s, request: %s", headers, pathParams); - return findPresetsOperationByTaxCodeAndSubscriberId(pathParams.getPaTaxCode(), pathParams.getSubscriberId()) - .onFailure().transform(f -> f) - .map(m -> { - Log.debugf("getPresets Response %s",m); - return Response.status(Status.OK).entity(m).build(); - }); - } - - /** - * Return last preset operation to execute - * @param headers a set of mandatory headers - * @param pathParams pathParams {@link PresetsPathParam} contains the path parameters: paTaxCode and subscriberId - * @return Return last preset operation to execute for a specific subscriber - */ - @GET - @Path("/{paTaxCode}/{subscriberId}/last_to_execute") - public Uni getLastPresetsOperation(@Valid @BeanParam CommonHeader headers, @Valid PresetsPathParam pathParams) { - Log.debugf("getLastPresetsOperation - Input parameters: %s, request: %s", headers, pathParams); - return findPresetsOperationByTaxCodeAndSubscriberIdSortByCreationDate(pathParams.getPaTaxCode(), pathParams.getSubscriberId()) - .onFailure().transform(f -> f) + PresetRepository presetRepository; + + @Inject + SubscriberRepository subscriberRepository; + + /** + * Creates a preset operation + * + * @param portalHeaders a set of mandatory headers sent by the institution portal + * @param createPresetRequest {@link CreatePresetRequest} containing the request parameters + * @return an {@link Uni} emitting an empty 201 Created response with the Location header populated + */ + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Uni createPreset(@Valid @BeanParam InstitutionPortalHeaders portalHeaders, @Valid CreatePresetRequest createPresetRequest) { + + Log.debugf("createPreset - Input parameters: %s,: %s", portalHeaders, createPresetRequest); + + return findSubscriber(createPresetRequest.getPaTaxCode(), createPresetRequest.getSubscriberId()) + .chain(subscriberEntity -> { + if (subscriberEntity == null) { + Log.errorf("[%s] No subscriber found on DB", ErrorCode.ERROR_SUBSCRIBER_NOT_FOUND); + return Uni.createFrom().item( + Response.status(Status.BAD_REQUEST) + .entity(new Errors(List.of(ErrorCode.ERROR_SUBSCRIBER_NOT_FOUND))) + .build()); + } else { + // update last usage timestamp + subscriberEntity.subscriber.setLastUsageTimestamp(DateUtils.getCurrentTimestamp()); + return updateSubscriber(subscriberEntity) + // save preset operation on DB + .chain(se -> persistPreset(se.subscriber, createPresetRequest)) + .map(pe -> { + final URI locationURI = buildLocationPath(subscriberEntity.subscriber.getPaTaxCode(), + subscriberEntity.subscriber.getSubscriberId(), pe.presetOperation.getPresetId()); + Log.debugf("createPreset - Response presetId %s ", pe.presetOperation.getPresetId()); + return Response.status(Status.CREATED).location(locationURI).build(); + }); + } + }); + } + + /** + * Returns the list of preset operations configured for a subscriber + * + * @param headers a set of mandatory headers sent by the institution portal + * @param pathParams {@link SubscriberPathParams} contains the path parameters paTaxCode and subscriberId + * @return an {@link Uni} emitting the list of {@link PresetOperation} configured for the subscriber + */ + @GET + @Produces(MediaType.APPLICATION_JSON) + @Path("/{paTaxCode}/{subscriberId}") + public Uni getPresets(@Valid @BeanParam InstitutionPortalHeaders headers, @Valid @BeanParam SubscriberPathParams pathParams) { + + Log.debugf("getPresets - Input parameters: %s, %s", headers, pathParams); + + return findPresetOperations(pathParams.getPaTaxCode(), pathParams.getSubscriberId()) + .map(presets -> { + GetPresetsResponse response = new GetPresetsResponse(); + response.setPresets(presets); + Log.debugf("getPresets - Response %s", response); + return Response.status(Status.OK).entity(response).build(); + }); + } + + /** + * Returns the last preset operation to be executed by a subscriber + * + * @param headers a set of mandatory headers + * @param pathParams pathParams {@link SubscriberPathParams} contains the path parameters: paTaxCode and subscriberId + * @return an {@link Uni} emitting the latest {@link PresetOperation} configured for the subscriber + */ + @GET + @Produces(MediaType.APPLICATION_JSON) + @Path("/{paTaxCode}/{subscriberId}/last_to_execute") + public Uni getLastPresetsOperation(@Valid @BeanParam CommonHeader headers, @Valid @BeanParam SubscriberPathParams pathParams) { + + Log.debugf("getLastPresetsOperation - Input parameters: %s, %s", headers, pathParams); + + return findLatestPresetOperation(pathParams.getPaTaxCode(), pathParams.getSubscriberId()) .chain(m -> { - if (m == null) { - Log.errorf("[%s] No subscriber found", ErrorCode.ERROR_PRESET_OPERATION_NOT_FOUND); - return Uni.createFrom().item( - Response.status(Status.NOT_FOUND) - .entity(new Errors(List.of(ErrorCode. ERROR_PRESET_OPERATION_NOT_FOUND))) - .build()); - } else { - Log.debugf("getPresets Response %s",m); - return Uni.createFrom().item(Response.status(Status.OK).entity(m).build()); - } - }); - } - - /** - * searches the subscriber by paTaxCode and Subscriber Id - * @param paTaxCode Tax code of the creditor company - * @param subscriberId subscriber ID - * @return - */ - private Uni findSubscriberByTaxCodeAndSubscriberId(String paTaxCode, String subscriberId) { - Log.debugf("find By paTaxCode %s And SubscriberId %s",paTaxCode,subscriberId); - return subscriberRepository.list("paTaxCode = :paTaxCode and subscriberId = :subscriberId", - Parameters.with("paTaxCode", paTaxCode).and("subscriberId", subscriberId).map()) - .onFailure().transform(err -> { - Log.errorf(err, "[%s] Error while find subscriber", ErrorCode.ERROR_COMMUNICATION_MONGO_DB); - return new InternalServerErrorException(Response - .status(Status.INTERNAL_SERVER_ERROR) - .entity(new Errors(List.of(ErrorCode.ERROR_COMMUNICATION_MONGO_DB))) - .build()); - } - ).map(entity -> !entity.isEmpty() ? entity.get(0) : null); - } - - /** - * searches the last preset operation by paTaxCode and subscriber ID - * @param paTaxCode Tax code of the creditor company - * @param subscriberId ID assigned to subscribed terminal - * @return the last preset operations - */ - private Uni findPresetsOperationByTaxCodeAndSubscriberIdSortByCreationDate(String paTaxCode, String subscriberId) { - Log.debugf("find last preset Operation By paTaxCode %s And SubscriberId %s",paTaxCode,subscriberId); - return presetRepository.list("paTaxCode = :paTaxCode and subscriberId = :subscriberId", - Sort.by("creationTimestamp").descending(), - Parameters.with("paTaxCode", paTaxCode).and("subscriberId", subscriberId).map() - ) - .onFailure().transform(err -> { - Log.errorf(err, "[%s] Error while find subscriber", ErrorCode.ERROR_COMMUNICATION_MONGO_DB); - return new InternalServerErrorException(Response - .status(Status.INTERNAL_SERVER_ERROR) - .entity(new Errors(List.of(ErrorCode.ERROR_COMMUNICATION_MONGO_DB))) - .build()); - } - ).map(m -> - !m.isEmpty() ? mapPresetOperation(m.get(0)) : null - ); - } - - /** - * searches the last preset operation by paTaxCode and subscriber ID - * @param paTaxCode Tax code of the creditor company - * @param subscriberId ID assigned to subscribed terminal - * @return the last preset operations - */ - private Uni findPresetsOperationByTaxCodeAndSubscriberId(String paTaxCode, String subscriberId) { - Log.debugf("find presets Operation By paTaxCode %s And SubscriberId %s",paTaxCode,subscriberId); - return presetRepository.list("paTaxCode = :paTaxCode and subscriberId = :subscriberId", - Parameters.with("paTaxCode", paTaxCode).and("subscriberId", subscriberId).map()) - .onFailure().transform(err -> { - Log.errorf(err, "[%s] Error while find subscriber", ErrorCode.ERROR_COMMUNICATION_MONGO_DB); - return new InternalServerErrorException(Response - .status(Status.INTERNAL_SERVER_ERROR) - .entity(new Errors(List.of(ErrorCode.ERROR_COMMUNICATION_MONGO_DB))) - .build()); - } - ).map(this::mapPresetsOperationResponse); - } - /** - * Maps the list of {@link PresetsEntity} to {@link PresetsResponse} - * @param listOfPresetsEntity - * @return {@link PresetsResponse} - */ - private PresetsResponse mapPresetsOperationResponse(List listOfPresetsEntity) { - PresetsResponse presetsResponse = new PresetsResponse(); - List presets = new ArrayList<>(); - listOfPresetsEntity.forEach(element -> { - presets.add(mapPresetOperation(element)); - }); - presetsResponse.setPresets(presets); - return presetsResponse; - } - - /** - * Maps the {@link PresetsEntity} to {@link PresetResponse} - * @param presetsEntity - * @return - */ - private PresetResponse mapPresetOperation(PresetsEntity presetsEntity) { - - PresetResponse response = new PresetResponse(); - response.setCreationTimestamp(presetsEntity.getCreationTimestamp()); - response.setNoticeNumber(presetsEntity.getNoticeNumber()); - response.setNoticeTaxCode(presetsEntity.getNoticeTaxCode()); - response.setOperationType(presetsEntity.getOperationType()); - response.setPaTaxCode(presetsEntity.getPaTaxCode()); - response.setPresetId(presetsEntity.getPresetId()); - response.setStatus(presetsEntity.getStatus()); - response.setStatusTimestamp(presetsEntity.getStatusTimestamp()); - response.setSubscriberId(presetsEntity.getSubscriberId()); - response.setStatusDetails(presetsEntity.getStatusDetails()); - return response; - } - - /** - * Update the subscriber - * @param entity - * @return - */ - private Uni updateSubscriber(SubscriberEntity entity) { - Log.debugf("Updating Subscriber"); - return subscriberRepository.update(entity) - .onFailure().retry().withBackOff(Duration.ofSeconds(30), Duration.ofSeconds(30)).atMost(2) - .map(m -> m); - } - - /** - * Save a preset operation - * @param subscriberEntity entity describing the subscriber - * @param presetRequest request of the preset operation - * @param presetId the generated preset ID - * @return - */ - private Uni persist( SubscriberEntity subscriberEntity, - PresetRequest presetRequest, - String presetId ) { - PresetsEntity entity = buildPresetEntity(subscriberEntity, presetRequest, presetId); - Log.debugf("Peristing Preset"); - return presetRepository.persist(entity) - .onFailure().transform( f -> { - Log.errorf(f, "[%s] Error while storing preset %s into db", - ErrorCode.ERROR_STORING_TERMINAL_IN_DB, presetId); - return - new InternalServerErrorException( - Response.status(Status.INTERNAL_SERVER_ERROR) - .entity(new Errors(List.of(ErrorCode.ERROR_STORING_TERMINAL_IN_DB))) - .build()); - }) - .map(m -> { - final String location = buildLocationPath(subscriberEntity.getPaTaxCode(), subscriberEntity.getSubscriberId(), presetId); - Log.debugf("PresetId %s SAVED ", presetId); - return Response.status(Status.CREATED).header(SubscribeResource.LOCATION, location).build(); - }); - } - - /** - * Build the presetEntity object used to persist the preset operation - * @param subscriberEntity entity describing the subscriber - * @param presetRequest request of the preset operation - * @param presetId the generated preset ID - * @return a preset entity - */ - private PresetsEntity buildPresetEntity(SubscriberEntity subscriberEntity, - PresetRequest presetRequest, - String presetId) { - - final String timestamp = DateUtils.getAndFormatCurrentDate(); - PresetsEntity presetEntity = new PresetsEntity(); - presetEntity.setId(presetId); - presetEntity.setPresetId(presetId); - presetEntity.setCreationTimestamp(timestamp); - presetEntity.setNoticeNumber(presetRequest.getNoticeNumber()); - presetEntity.setNoticeTaxCode(presetRequest.getNoticeTaxCode()); - presetEntity.setOperationType(OperationType.PAYMENT_NOTICE.name()); - presetEntity.setPaTaxCode(subscriberEntity.getPaTaxCode()); - presetEntity.setStatus(PresetStatus.TO_EXECUTE.name()); - presetEntity.setStatusTimestamp(timestamp); - presetEntity.setSubscriberId(subscriberEntity.getSubscriberId()); - return presetEntity; - } - - /** - * Utility method used to build the location path - * @param paTaxCode Tax code of the creditor company - * @param subscriberId Subscriber ID - * @param presetId the generated preset ID - * @return - */ - private String buildLocationPath(String paTaxCode, String subscriberId, String presetId) { - final StringBuilder location = new StringBuilder(); - location.append("/presets/"); - location.append(paTaxCode); - location.append("/"); - location.append(subscriberId); - location.append("/"); - location.append(presetId); - return location.toString(); - } + if (m == null) { + Log.debugf("getLastPresetsOperation - Response %s", Status.NOT_FOUND); + return Uni.createFrom().item(Response.status(Status.NOT_FOUND).build()); + } + else { + Log.debugf("getLastPresetsOperation - Response %s", m); + return Uni.createFrom().item(Response.status(Status.OK).entity(m).build()); + } + }); + } + + /** + * Retrieves the subscriber by tax code and its id + * + * @param paTaxCode Tax code of the creditor company + * @param subscriberId the id of the subscriber + * @return the subscriber entity + */ + private Uni findSubscriber(String paTaxCode, String subscriberId) { + + return subscriberRepository.list(SUBSCRIBER_FILTER, Parameters.with("paTaxCode", paTaxCode).and("subscriberId", subscriberId).map()) + .onFailure().transform(err -> { + Log.errorf(err, "[%s] Error while retrieving data from DB", ErrorCode.ERROR_COMMUNICATION_MONGO_DB); + return new InternalServerErrorException( + Response.status(Status.INTERNAL_SERVER_ERROR) + .entity(new Errors(List.of(ErrorCode.ERROR_COMMUNICATION_MONGO_DB))) + .build()); + }) + .map(entityList -> entityList.isEmpty() ? null : entityList.get(0)); + } + + /** + * Retrieves all the preset operations configured for a subscriber + * + * @param paTaxCode tax code of the creditor company + * @param subscriberId ID assigned to subscribed terminal + * @return the list of the preset operations + */ + private Uni> findPresetOperations(String paTaxCode, String subscriberId) { + + return presetRepository.list(PRESET_FILTER, Parameters.with("paTaxCode", paTaxCode).and("subscriberId", subscriberId).map()) + .onFailure().transform(err -> { + Log.errorf(err, "[%s] Error while retrieving data from DB", ErrorCode.ERROR_COMMUNICATION_MONGO_DB); + return new InternalServerErrorException( + Response.status(Status.INTERNAL_SERVER_ERROR) + .entity(new Errors(List.of(ErrorCode.ERROR_COMMUNICATION_MONGO_DB))) + .build()); + }) + .map(entities -> entities.stream().map(entity -> entity.presetOperation).toList()); + } + + /** + * Retrieves the latest preset operation configured for a subscriber + * + * @param paTaxCode Tax code of the creditor company + * @param subscriberId ID assigned to subscribed terminal + * @return the last preset operation + */ + private Uni findLatestPresetOperation(String paTaxCode, String subscriberId) { + + return presetRepository.find(LAST_PRESET_FILTER, + Sort.by("creationTimestamp").descending(), + Parameters + .with("paTaxCode", paTaxCode) + .and("subscriberId", subscriberId) + .map() + ) + .firstResult() + .onFailure().transform(err -> { + Log.errorf(err, "[%s] Error while retrieving data from DB", ErrorCode.ERROR_COMMUNICATION_MONGO_DB); + return new InternalServerErrorException( + Response.status(Status.INTERNAL_SERVER_ERROR) + .entity(new Errors(List.of(ErrorCode.ERROR_COMMUNICATION_MONGO_DB))) + .build()); + } + ) + .map(presetEntity -> presetEntity != null ? presetEntity.presetOperation : null); + } + + + /** + * Update the subscriber info + * + * @param entity the subscriber entity to update + * @return the updated entity + */ + private Uni updateSubscriber(SubscriberEntity entity) { + Log.debugf("Updating Subscriber"); + return subscriberRepository.update(entity) + // ignoring update error + .onFailure().recoverWithItem(entity); + } + + /** + * Save a preset operation on the database + * + * @param subscriber bean containing the subscriber data + * @param createPresetRequest request of the create preset operation + * @return an {@link Uni} emitting the persisted {@link PresetEntity} + */ + private Uni persistPreset(Subscriber subscriber, + CreatePresetRequest createPresetRequest) { + + final String presetId = UUID.randomUUID().toString(); + PresetEntity entity = buildPresetEntity(subscriber, createPresetRequest, presetId); + + return presetRepository.persist(entity) + .onFailure().transform(f -> { + Log.errorf(f, "[%s] Error while storing data in the DB", ErrorCode.ERROR_STORING_TERMINAL_IN_DB); + return new InternalServerErrorException( + Response.status(Status.INTERNAL_SERVER_ERROR) + .entity(new Errors(List.of(ErrorCode.ERROR_STORING_TERMINAL_IN_DB))) + .build()); + }); + + } + + /** + * Build the preset entity object to be persisted the {@link #persistPreset(Subscriber, CreatePresetRequest)} operation + * + * @param subscriber bean containing the subscriber data + * @param createPresetRequest request of the create preset operation + * @param presetId the generated preset identifier + * @return the {@link PresetEntity} instance + */ + private PresetEntity buildPresetEntity(Subscriber subscriber, + CreatePresetRequest createPresetRequest, + String presetId) { + + final String timestamp = DateUtils.getCurrentTimestamp(); + PresetOperation presetOperation = new PresetOperation(); + presetOperation.setPresetId(presetId); + presetOperation.setCreationTimestamp(timestamp); + presetOperation.setNoticeNumber(createPresetRequest.getNoticeNumber()); + presetOperation.setNoticeTaxCode(createPresetRequest.getNoticeTaxCode()); + presetOperation.setOperationType(OperationType.PAYMENT_NOTICE.name()); + presetOperation.setPaTaxCode(subscriber.getPaTaxCode()); + presetOperation.setStatus(PresetStatus.TO_EXECUTE.name()); + presetOperation.setStatusTimestamp(timestamp); + presetOperation.setSubscriberId(subscriber.getSubscriberId()); + + PresetEntity presetEntity = new PresetEntity(); + presetEntity.id = presetId; + presetEntity.presetOperation = presetOperation; + + return presetEntity; + } + + /** + * Utility method used to build the location header path to be returned in the + * {@link #getLastPresetsOperation(CommonHeader, SubscriberPathParams)} + * + * @param paTaxCode tax code of the creditor company + * @param subscriberId the subscriber id + * @param presetId the generated preset id + * @return an {@link URI} representing the location header + */ + private URI buildLocationPath(String paTaxCode, String subscriberId, String presetId) { + final StringBuilder location = new StringBuilder(); + location.append("/presets/"); + location.append(paTaxCode); + location.append("/"); + location.append(subscriberId); + location.append("/"); + location.append(presetId); + return URI.create(presetLocationBaseURL + location.toString()); + } } diff --git a/src/main/java/it/pagopa/swclient/mil/preset/resource/SubscribeResource.java b/src/main/java/it/pagopa/swclient/mil/preset/resource/SubscribeResource.java deleted file mode 100644 index 41185d0..0000000 --- a/src/main/java/it/pagopa/swclient/mil/preset/resource/SubscribeResource.java +++ /dev/null @@ -1,297 +0,0 @@ -/** - * This module contains the REST endpoints exposed by the microservice. - * - * @author Antonio Tarricone - */ -package it.pagopa.swclient.mil.preset.resource; - -import java.security.SecureRandom; -import java.util.List; - -import org.apache.commons.lang3.RandomStringUtils; - -import io.quarkus.logging.Log; -import io.quarkus.panache.common.Parameters; -import io.smallrye.mutiny.Uni; -import it.pagopa.swclient.mil.bean.CommonHeader; -import it.pagopa.swclient.mil.bean.Errors; -import it.pagopa.swclient.mil.preset.ErrorCode; -import it.pagopa.swclient.mil.preset.bean.PresetHeaders; -import it.pagopa.swclient.mil.preset.bean.SubcribersResponse; -import it.pagopa.swclient.mil.preset.bean.SubscriberRequest; -import it.pagopa.swclient.mil.preset.bean.SubscriberResponse; -import it.pagopa.swclient.mil.preset.bean.SubscribersPathParam; -import it.pagopa.swclient.mil.preset.bean.UnsubscriberHeaders; -import it.pagopa.swclient.mil.preset.bean.UnsubscriberPathParam; -import it.pagopa.swclient.mil.preset.dao.SubscriberEntity; -import it.pagopa.swclient.mil.preset.dao.SubscriberRepository; -import it.pagopa.swclient.mil.preset.utils.DateUtils; -import jakarta.inject.Inject; -import jakarta.validation.Valid; -import jakarta.ws.rs.BeanParam; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.InternalServerErrorException; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.core.Response.Status; - - -@Path("/terminals") -public class SubscribeResource { - - public static final String LOCATION = "Location"; - - @Inject - private SubscriberRepository subscriberRepository; - - /** - * Returns the list of subscribed terminals - * @param headers a set of mandatory headers - * @param pathParams paTaxCode of the creditor company - * @return List of subscribed terminals - */ - @GET - @Path("/{paTaxCode}") - @Consumes(MediaType.APPLICATION_JSON) - public Uni getSubscribers(@Valid @BeanParam PresetHeaders headers,@Valid SubscribersPathParam pathParams) { - Log.debugf("getSubscribers - Input parameters: %s, taxCode: %s", headers, pathParams.getPaTaxCode()); - - return findSubscribersByPaTaxCode(pathParams.getPaTaxCode()) - .onFailure().transform(f -> f) - .map(m -> { - Log.debugf("getSubscribers Response %s",m); - return Response.status(Status.OK).entity(m).build(); - }); - - } - - /** - * Unsubscribes a terminal to handle preset operations - * @param headers a set of mandatory headers - * @param pathParams paTaxCode and subscriberId - * @return - */ - @DELETE - @Path(value = "/{paTaxCode}/{subscriberId}") - public Uni unsubscriber(@Valid @BeanParam UnsubscriberHeaders headers, UnsubscriberPathParam pathParams) { - return deleteByPaTaxCodeAndSubscriberId(pathParams.getPaTaxCode(),pathParams.getSubscriberId()) - .map(numberOfEntityDeleted -> { - Log.debugf("unbscriber Response - Deleted [%s] entity",numberOfEntityDeleted); - if (numberOfEntityDeleted > 0) { - return Response.status(Status.NO_CONTENT).build(); - } else { - return Response.status(Status.NOT_FOUND).build(); - } - }); - } - - /** - * Subscribes a terminal to handle preset operations - * @param commonHeader a set of mandatory headers - * @param subscriberRequest {@link SubscriberRequest} contains Tax code of the creditor company and a mnemonic terminal label - * @return status of operation - */ - @POST - public Uni subscribe(@Valid @BeanParam CommonHeader commonHeader, @Valid SubscriberRequest subscriberRequest) { - Log.debugf("subscribe - Input parameters: %s, subscriberRequest: %s", commonHeader, subscriberRequest); - return findSubscriber(commonHeader.getAcquirerId(), - commonHeader.getChannel(), - commonHeader.getMerchantId(), - commonHeader.getTerminalId(), - subscriberRequest.getPaTaxCode()) - .chain(subscriberId -> { - if (subscriberId.equals("")) { - Log.debugf("No SubscriberId found "); - Log.debugf("Generating new SubscriberId ... "); - final String subId = RandomStringUtils.random(6, 0, 0, true, true, null, new SecureRandom()).toLowerCase(); - Log.debugf("SubscriberId %s generated ", subId); - return persist(subscriberRequest, commonHeader, subId); - } else { - final String location = buildLocationPath(subscriberRequest.getPaTaxCode(), subscriberId); - Log.debugf("[%s] Error while storing terminal %s into db", ErrorCode.ERROR_CONFLICT_TERMINAL_IN_DB, subscriberId); - - return Uni.createFrom().item( - Response.status(Status.CONFLICT) - .entity(new Errors(List.of(ErrorCode.ERROR_CONFLICT_TERMINAL_IN_DB))) - .header(LOCATION, location).build()); - } - }); - } - - /** - * Perform the persist operation on the database - * @param subscriberRequest {@link SubscriberRequest} contains Tax code of the creditor company and a mnemonic terminal label - * @param commonHeader a set of mandatory headers - * @param subId subscriber Id - * @return the status of the persist - */ - private Uni persist( SubscriberRequest subscriberRequest, - CommonHeader commonHeader, - String subId ) { - SubscriberEntity entity = buildEntity(subscriberRequest, commonHeader, subId); - return subscriberRepository.persist(entity) - .onFailure().transform( f -> { - Log.errorf(f, "[%s] Error while storing terminal %s into db", - ErrorCode.ERROR_STORING_TERMINAL_IN_DB, subId); - return - new InternalServerErrorException( - Response.status(Status.INTERNAL_SERVER_ERROR) - .entity(new Errors(List.of(ErrorCode.ERROR_STORING_TERMINAL_IN_DB))) - .build()); - }) - .map(m -> { - final String location = buildLocationPath(subscriberRequest.getPaTaxCode(), subId); - Log.debugf("SubscriberId %s SAVED ", subId); - return Response.status(Status.CREATED).header(LOCATION, location).build(); - }); - } - - /** - * Retrieves the list of subscribers by paTaxCode - * @param taxCodeToken token returned by the PDV-Tokenizer service - * @param tcVersion T&C version - * @return true if the current version is equals to older one. False otherwise. - */ - private Uni findSubscribersByPaTaxCode(String paTaxCode) { - Log.debugf("findSubscribersByPaTaxCode - find Subscribers by paTaxCode: [%s] ", paTaxCode); - - return subscriberRepository.list("paTaxCode", paTaxCode) - .onFailure().transform(err -> { - Log.errorf(err, "[%s] Error while find subscriber", ErrorCode.ERROR_COMMUNICATION_MONGO_DB); - return new InternalServerErrorException(Response - .status(Status.INTERNAL_SERVER_ERROR) - .entity(new Errors(List.of(ErrorCode.ERROR_COMMUNICATION_MONGO_DB))) - .build()); - } - ).map(entity -> { - SubcribersResponse subscribers = new SubcribersResponse(); - entity.forEach(element -> mapResponse(element, subscribers)); - return subscribers; - }); - } - - - /** - * Make a query to check if the terminal is already subscribed - * @param acquirerId Acquirer ID assigned by PagoPA - * @param channel Channel originating the request - * @param merchantId Merchant ID. Mandatory when Channel equals POS. - * @param terminalId ID of the terminal originating the transaction. It must be unique per acquirer and channel. - * @param paTaxCode Tax code of the creditor company - * @return - */ - private Uni findSubscriber(String acquirerId, - String channel, - String merchantId, - String terminalId, - String paTaxCode - ) { - Log.debugf("findSubscriber - find Subscribers by acquirerId [%s] channel [%s] merchantId [%s] terminalid [%s] paTaxCode: [%s] ", acquirerId, channel, merchantId, terminalId, paTaxCode); - - return subscriberRepository.list("acquirerId = :acquirerId and channel = :channel and merchantId =:merchantId and terminalId =:terminalId and paTaxCode =:paTaxCode", - Parameters.with("acquirerId", acquirerId) - .and("channel", channel) - .and("merchantId", merchantId) - .and("terminalId", terminalId) - .and("paTaxCode", paTaxCode) - .map()) - .onFailure().transform(err -> { - Log.errorf(err, "[%s] Error while list subscribers", ErrorCode.ERROR_COMMUNICATION_MONGO_DB); - return new InternalServerErrorException(Response - .status(Status.INTERNAL_SERVER_ERROR) - .entity(new Errors(List.of(ErrorCode.ERROR_COMMUNICATION_MONGO_DB))) - .build()); - } - ).map(entity -> - !entity.isEmpty() ? entity.get(0).getSubscriberId() : "" - ); - } - - /** - * Delete the subsctiber by paTaxCode and Subscriber Id - * @param paTaxCode Tax code of the creditor company - * @param subscriberId subscriber Id - * @return - */ - private Uni deleteByPaTaxCodeAndSubscriberId(String paTaxCode, String subscriberId) { - Log.debugf("Deleting entity with paTaxCode [%s] and subscriberId [%s]", paTaxCode, subscriberId); - - return subscriberRepository.delete("paTaxCode = :paTaxCode and subscriberId = :subscriberId", - Parameters.with("paTaxCode", paTaxCode).and("subscriberId", subscriberId).map() - ) - .onFailure().transform(err -> { - Log.debugf("Internal server error deleting entity with paTaxCode [%s] and subscriberId [%s]", paTaxCode, subscriberId); - return new InternalServerErrorException(Response - .status(Status.INTERNAL_SERVER_ERROR) - .entity(new Errors(List.of(ErrorCode.ERROR_COMMUNICATION_MONGO_DB))) - .build()); - }).map(f -> f); - } - - /** - * Maps the Entity to the SubcribersResponse - * @param entity entity retrieved form database - * @param subscribersResponse response containing the subscriber info - */ - private void mapResponse(SubscriberEntity entity, SubcribersResponse subscribersResponse) { - SubscriberResponse subscriberResponse = new SubscriberResponse(); - subscriberResponse.setAcquirerId(entity.getAcquirerId()); - subscriberResponse.setChannel(entity.getChannel()); - subscriberResponse.setLabel(entity.getLabel()); - subscriberResponse.setLastUsageTimestamp(entity.getLastUsageTimestamp()); - subscriberResponse.setMerchantId(entity.getMerchantId()); - subscriberResponse.setPaTaxCode(entity.getPaTaxCode()); - subscriberResponse.setSubscriberId(entity.getSubscriberId()); - subscriberResponse.setSubscriptionTimestamp(entity.getSubscriptionTimestamp()); - subscriberResponse.setTerminalId(entity.getTerminalId()); - subscribersResponse.getSubscribers().add(subscriberResponse); - } - - /** - * Maps the input parameters to the {@link SubscriberEntity}, used to persiste the information into the database - * @param subscriberRequest {@link SubscriberRequest} contains Tax code of the creditor company and a mnemonic terminal label - * @param commonHeader a set of mandatory headers - * @param subId subscriber Id - * @return the entity to persist - */ - private SubscriberEntity buildEntity(SubscriberRequest subscriberRequest, - CommonHeader commonHeader, - String subId) { - - final String timestamp = DateUtils.getAndFormatCurrentDate(); - SubscriberEntity entity = new SubscriberEntity(); - //set id as subscriber Id - entity.setId(subId); - entity.setAcquirerId(commonHeader.getAcquirerId()); - entity.setChannel(commonHeader.getChannel()); - entity.setLabel(subscriberRequest.getLabel()); - entity.setLastUsageTimestamp(timestamp); - entity.setMerchantId(commonHeader.getMerchantId()); - entity.setPaTaxCode(subscriberRequest.getPaTaxCode()); - entity.setSubscriberId(subId); - entity.setSubscriptionTimestamp(timestamp); - entity.setTerminalId(commonHeader.getTerminalId()); - - return entity; - } - - /** - * Utility method used to build the location path - * @param paTaxCode Tax code of the creditor company - * @param subscriber subscriber Id - * @return the location path as string - */ - private String buildLocationPath(String paTaxCode, String subscriberId) { - final StringBuilder location = new StringBuilder(); - location.append("/terminals/"); - location.append(paTaxCode); - location.append("/"); - location.append(subscriberId); - return location.toString(); - } - -} \ No newline at end of file diff --git a/src/main/java/it/pagopa/swclient/mil/preset/resource/TerminalsResource.java b/src/main/java/it/pagopa/swclient/mil/preset/resource/TerminalsResource.java new file mode 100644 index 0000000..8de5654 --- /dev/null +++ b/src/main/java/it/pagopa/swclient/mil/preset/resource/TerminalsResource.java @@ -0,0 +1,255 @@ +package it.pagopa.swclient.mil.preset.resource; + +import io.quarkus.logging.Log; +import io.quarkus.panache.common.Parameters; +import io.smallrye.mutiny.Uni; +import it.pagopa.swclient.mil.bean.CommonHeader; +import it.pagopa.swclient.mil.bean.Errors; +import it.pagopa.swclient.mil.preset.ErrorCode; +import it.pagopa.swclient.mil.preset.bean.GetSubscribersResponse; +import it.pagopa.swclient.mil.preset.bean.InstitutionPortalHeaders; +import it.pagopa.swclient.mil.preset.bean.SubscribeRequest; +import it.pagopa.swclient.mil.preset.bean.Subscriber; +import it.pagopa.swclient.mil.preset.bean.SubscriberPathParams; +import it.pagopa.swclient.mil.preset.bean.UnsubscribeHeaders; +import it.pagopa.swclient.mil.preset.dao.SubscriberEntity; +import it.pagopa.swclient.mil.preset.dao.SubscriberRepository; +import it.pagopa.swclient.mil.preset.utils.DateUtils; +import jakarta.inject.Inject; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; +import jakarta.ws.rs.BeanParam; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.InternalServerErrorException; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.Response.Status; +import org.apache.commons.lang3.RandomStringUtils; +import org.eclipse.microprofile.config.inject.ConfigProperty; + +import java.net.URI; +import java.security.SecureRandom; +import java.util.List; + + +@Path("/terminals") +public class TerminalsResource { + + @Inject + SubscriberRepository subscriberRepository; + + /** + * The base URL for the location header returned by the subscribe API (i.e. the API management base URL) + */ + @ConfigProperty(name="preset.location.base-url") + String presetLocationBaseURL; + + /** + * Returns the list of subscribed terminals for a given tax code + * @param portalHeaders a set of mandatory headers sent by the institution portal + * @param paTaxCode the tax code of the creditor company + * @return the list of subscribed terminals + */ + @GET + @Path("/{paTaxCode}") + @Produces(MediaType.APPLICATION_JSON) + public Uni getSubscribers(@Valid @BeanParam InstitutionPortalHeaders portalHeaders, + + @PathParam(value = "paTaxCode") + @NotNull(message = "[" + ErrorCode.PA_TAX_CODE_MUST_NOT_BE_NULL + "] paTaxCode must not be null") + @Pattern(regexp = "^[0-9]{11}$", message = "[" + ErrorCode.PA_TAX_CODE_MUST_MATCH_REGEXP + "] paTaxCode must match \"{regexp}\"") + String paTaxCode) { + + Log.debugf("getSubscribers - Input parameters: %s, taxCode: %s", portalHeaders, paTaxCode); + + return subscriberRepository.list("subscriber.paTaxCode", paTaxCode) + .onFailure().transform(err -> { + Log.errorf(err, "[%s] Error while retrieving data from DB", ErrorCode.ERROR_COMMUNICATION_MONGO_DB); + return new InternalServerErrorException(Response + .status(Status.INTERNAL_SERVER_ERROR) + .entity(new Errors(List.of(ErrorCode.ERROR_COMMUNICATION_MONGO_DB))) + .build()); + }) + .map(subs -> { + GetSubscribersResponse response = new GetSubscribersResponse(); + response.setSubscribers(subs.stream().map(entity -> entity.subscriber).toList()); + Log.debugf("getSubscribers - Response %s", response); + return Response + .status(Status.OK) + .entity(response) + .build(); + }); + + } + + /** + * Unsubscribes a terminal to handle preset operations + * @param headers a set of mandatory headers sent by the terminal or by the institution portal + * @param pathParams paTaxCode and subscriberId + * @return no content, if the terminal was successfully unsubscribed, or 404 if no subscriber was found with the given id + */ + @DELETE + @Produces(MediaType.APPLICATION_JSON) + @Path(value = "/{paTaxCode}/{subscriberId}") + public Uni unsubscribe(@Valid @BeanParam UnsubscribeHeaders headers, SubscriberPathParams pathParams) { + + Log.debugf("unsubscribe - Input parameters: %s, %s", headers, pathParams); + + return subscriberRepository.delete("subscriber.paTaxCode = :paTaxCode and subscriber.subscriberId = :subscriberId", + Parameters + .with("paTaxCode", pathParams.getPaTaxCode()) + .and("subscriberId", pathParams.getSubscriberId()) + .map() + ) + .onFailure().transform(err -> { + Log.debugf("[%s] Error while deleting data from DB", ErrorCode.ERROR_COMMUNICATION_MONGO_DB); + return new InternalServerErrorException(Response + .status(Status.INTERNAL_SERVER_ERROR) + .entity(new Errors(List.of(ErrorCode.ERROR_COMMUNICATION_MONGO_DB))) + .build()); + }) + .map(deleted -> { + Status status; + if (deleted > 0) { + status = Status.NO_CONTENT; + } else { + Log.warnf("No entity found for paTaxCode %s and subscriberId %s", + pathParams.getPaTaxCode(), pathParams.getSubscriberId()); + status = Status.NOT_FOUND; + } + Log.debugf("unsubscribe - Response %s", status); + return Response.status(status).build(); + }); + } + + /** + * Subscribes a terminal to handle preset operations + * + * @param commonHeader a set of mandatory headers sent by the terminal + * @param subscribeRequest the request containing the pa tax code and a mnemonic label + * @return 201 if the terminal was subscribed + */ + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Uni subscribe(@Valid @BeanParam CommonHeader commonHeader, @Valid SubscribeRequest subscribeRequest) { + + Log.debugf("subscribe - Input parameters: %s, %s", commonHeader, subscribeRequest); + + return findSubscriber(commonHeader, subscribeRequest.getPaTaxCode()) + .chain(subscriber -> { + if (subscriber == null) { + // no subscriber found, generating new subscriber id + final String subscriberId = RandomStringUtils.random(6, 0, 0, true, true, null, new SecureRandom()).toLowerCase(); + Log.debugf("Generated subscriber id %s", subscriberId); + + SubscriberEntity entity = buildSubscriberEntity(subscribeRequest, commonHeader, subscriberId); + return subscriberRepository.persist(entity) + .onFailure().transform( f -> { + Log.errorf(f, "[%s] Error while storing data in the DB", ErrorCode.ERROR_STORING_TERMINAL_IN_DB, subscriberId); + return new InternalServerErrorException(Response.status(Status.INTERNAL_SERVER_ERROR) + .entity(new Errors(List.of(ErrorCode.ERROR_STORING_TERMINAL_IN_DB))) + .build()); + }) + .map(m -> { + final URI locationURI = buildLocationPath(subscribeRequest.getPaTaxCode(), subscriberId); + Log.debugf("SubscriberId %s SAVED ", subscriberId); + return Response.status(Status.CREATED).location(locationURI).build(); + }); + } + else { + final URI locationURI = buildLocationPath(subscribeRequest.getPaTaxCode(), subscriber.getSubscriberId()); + Log.debugf("Terminal already subscribed", ErrorCode.ERROR_CONFLICT_TERMINAL_IN_DB, subscriber.getSubscriberId()); + return Uni.createFrom().item(Response.status(Status.CONFLICT).location(locationURI).build()); + } + }); + } + + /** + * Searches for a subscribed terminal by its data and the tax code of the company + * + * @param commonHeader a set of mandatory headers sent by the terminal + * @param paTaxCode tax code of the creditor company + * @return the subscriber if found, null otherwise + */ + private Uni findSubscriber(CommonHeader commonHeader, String paTaxCode) { + + return subscriberRepository.list( + """ + subscriber.acquirerId = :acquirerId and + subscriber.channel = :channel and + subscriber.merchantId =:merchantId and + subscriber.terminalId =:terminalId and + subscriber.paTaxCode =:paTaxCode + """, + Parameters.with("acquirerId", commonHeader.getAcquirerId()) + .and("channel", commonHeader.getChannel()) + .and("merchantId", commonHeader.getMerchantId()) + .and("terminalId", commonHeader.getTerminalId()) + .and("paTaxCode", paTaxCode) + .map()) + .onFailure().transform(err -> { + Log.errorf(err, "[%s] Error while retrieving data from DB", ErrorCode.ERROR_COMMUNICATION_MONGO_DB); + return new InternalServerErrorException(Response + .status(Status.INTERNAL_SERVER_ERROR) + .entity(new Errors(List.of(ErrorCode.ERROR_COMMUNICATION_MONGO_DB))) + .build()); + } + ) + .map(entityList -> entityList.isEmpty() ? null : entityList.get(0).subscriber); + } + + /** + * Maps the input parameters to the {@link SubscriberEntity}, used to persist the information into the database + * + * @param subscribeRequest {@link SubscribeRequest} contains Tax code of the creditor company and a mnemonic terminal label + * @param commonHeader a set of mandatory headers + * @param subscriberId the id of the subscriber + * @return the entity to persist + */ + private SubscriberEntity buildSubscriberEntity(SubscribeRequest subscribeRequest, + CommonHeader commonHeader, + String subscriberId) { + + Subscriber subscriber = new Subscriber(); + subscriber.setAcquirerId(commonHeader.getAcquirerId()); + subscriber.setChannel(commonHeader.getChannel()); + subscriber.setLabel(subscribeRequest.getLabel()); + subscriber.setLastUsageTimestamp(null); + subscriber.setMerchantId(commonHeader.getMerchantId()); + subscriber.setPaTaxCode(subscribeRequest.getPaTaxCode()); + subscriber.setSubscriberId(subscriberId); + subscriber.setSubscriptionTimestamp(DateUtils.getCurrentTimestamp()); + subscriber.setTerminalId(commonHeader.getTerminalId()); + + SubscriberEntity subscriberEntity = new SubscriberEntity(); + subscriberEntity.id = subscriberId; + subscriberEntity.subscriber = subscriber; + + return subscriberEntity; + } + + /** + * Utility method used to build the location path + * @param paTaxCode Tax code of the creditor company + * @param subscriberId subscriber id + * @return the location path as string + */ + private URI buildLocationPath(String paTaxCode, String subscriberId) { + final StringBuilder location = new StringBuilder(); + location.append("/terminals/"); + location.append(paTaxCode); + location.append("/"); + location.append(subscriberId); + return URI.create(presetLocationBaseURL + location.toString()); + } + + +} \ No newline at end of file diff --git a/src/main/java/it/pagopa/swclient/mil/preset/utils/DateUtils.java b/src/main/java/it/pagopa/swclient/mil/preset/utils/DateUtils.java index 3a449c3..ffb7c62 100644 --- a/src/main/java/it/pagopa/swclient/mil/preset/utils/DateUtils.java +++ b/src/main/java/it/pagopa/swclient/mil/preset/utils/DateUtils.java @@ -3,22 +3,24 @@ */ package it.pagopa.swclient.mil.preset.utils; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; public class DateUtils { + private DateUtils() {} + /** - * Utility method. Generate a formatted current date time - * @return formatted current date time. Format yyyy-MM-dd'T'HH:mm:ss.SS + * Generates the current timestamp (UTC time) in the uuuu-MM-dd'T'HH:mm:ss format + * @return the timestamp */ - public static String getAndFormatCurrentDate() { - final String pattern = "yyyy-MM-dd'T'HH:mm:ss.SS"; - - DateFormat df = new SimpleDateFormat(pattern); - Date currentDate = Calendar.getInstance().getTime(); - return df.format(currentDate); + public static String getCurrentTimestamp() { + return LocalDateTime.ofInstant(Instant.now().truncatedTo(ChronoUnit.SECONDS), ZoneOffset.UTC) + .format(DateTimeFormatter.ISO_LOCAL_DATE_TIME); } + + } diff --git a/src/main/java/it/pagopa/swclient/mil/preset/validation/constraints/MerchantIdNotNullForPos.java b/src/main/java/it/pagopa/swclient/mil/preset/validation/constraints/MerchantIdNotNullForPos.java index b1b92b8..7aad445 100644 --- a/src/main/java/it/pagopa/swclient/mil/preset/validation/constraints/MerchantIdNotNullForPos.java +++ b/src/main/java/it/pagopa/swclient/mil/preset/validation/constraints/MerchantIdNotNullForPos.java @@ -3,15 +3,15 @@ */ package it.pagopa.swclient.mil.preset.validation.constraints; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; +import jakarta.validation.Constraint; +import jakarta.validation.Payload; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; -import jakarta.validation.Constraint; -import jakarta.validation.Payload; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; @Documented @Retention(RUNTIME) diff --git a/src/main/java/it/pagopa/swclient/mil/preset/validation/constraints/MerchantIdNotNullForPosValidator.java b/src/main/java/it/pagopa/swclient/mil/preset/validation/constraints/MerchantIdNotNullForPosValidator.java index 674bb47..725e9fa 100644 --- a/src/main/java/it/pagopa/swclient/mil/preset/validation/constraints/MerchantIdNotNullForPosValidator.java +++ b/src/main/java/it/pagopa/swclient/mil/preset/validation/constraints/MerchantIdNotNullForPosValidator.java @@ -4,17 +4,16 @@ package it.pagopa.swclient.mil.preset.validation.constraints; import it.pagopa.swclient.mil.bean.Channel; -import it.pagopa.swclient.mil.preset.bean.UnsubscriberHeaders; - +import it.pagopa.swclient.mil.preset.bean.UnsubscribeHeaders; import jakarta.validation.ConstraintValidator; import jakarta.validation.ConstraintValidatorContext; -public class MerchantIdNotNullForPosValidator implements ConstraintValidator { +public class MerchantIdNotNullForPosValidator implements ConstraintValidator { /** * @see jakarta.validation.ConstraintValidator#isValid(Object, ConstraintValidatorContext) */ @Override - public boolean isValid(UnsubscriberHeaders unsubscriberHeader, ConstraintValidatorContext context) { + public boolean isValid(UnsubscribeHeaders unsubscriberHeader, ConstraintValidatorContext context) { String channel = unsubscriberHeader.getChannel(); String merchantId = unsubscriberHeader.getMerchantId(); return !(channel != null && channel.equals(Channel.POS) && merchantId == null); diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index fda14a9..0704fc0 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -29,26 +29,29 @@ quarkus.log.min-level=DEBUG # mongo-read-timeout = 10s # mongo-server-selecion-timeout = 5s # ------------------------------------------------------------------------------ -%playground.quarkus.mongodb.database=test-mongo -%playground.quarkus.mongodb.connection-string=mongodb://test-mongo:27017 %dev.quarkus.mongodb.connect-timeout=5 %dev.quarkus.mongodb.read-timeout=10 %dev.quarkus.mongodb.server-selection-timeout=5 %dev.quarkus.mongodb.connection-string = mongodb://localhost:27017 +%test.quarkus.mongodb.connect-timeout=5 +%test.quarkus.mongodb.read-timeout=10 +%test.quarkus.mongodb.server-selection-timeout=5 +%test.quarkus.mongodb.connection-string = mongodb://localhost:27017 + %prod.quarkus.mongodb.connect-timeout=${mongo-connect-timeout} %prod.quarkus.mongodb.read-timeout=${mongo-read-timeout} %prod.quarkus.mongodb.server-selection-timeout=${mongo-server-selecion-timeout} %prod.quarkus.mongodb.connection-string=${mongo-connection-string-1},${mongo-connection-string-2} -quarkus.mongodb.devservices.enabled=false #%dev.kafka.bootstrap.servers=kafka:9092 #%prod.kafka.bootstrap.servers=${kafka-bootsrtap-server} #%test.kafka.bootstrap.servers=kafka:9092 -#mp.messaging.incoming.prices.connector=smallrye-kafka -#quarkus.kafka.devservices.enabled=false +#mp.messaging.incoming.prices.connector=smallrye-kafka + +quarkus.kafka.devservices.enabled=false #%prod.kafka.bootstrap.servers=kafka:9092 #mp.messaging.outgoing.prices-out.connector=smallrye-kafka @@ -68,4 +71,10 @@ quarkus.mongodb.devservices.enabled=false #mp.messaging.incoming.presets.topic=presets #mp.messaging.incoming.presets.value.deserializer=it.pagopa.swclient.mil.preset.utils.PresetDeserializer -quarkus.http.port=8081 +# ------------------------------------------------------------------------------ +# Service configurations +# ------------------------------------------------------------------------------ + +%dev.preset.location.base-url=https://mil-d-apim.azure-api.net/mil-preset +%test.preset.location.base-url=https://mil-d-apim.azure-api.net/mil-preset +%prod.preset.location.base-url=https://mil-d-apim.azure-api.net/mil-preset \ No newline at end of file diff --git a/src/test/java/it/pagopa/swclient/mil/preset/PresetResourceTest.java b/src/test/java/it/pagopa/swclient/mil/preset/PresetResourceTest.java index 2d4db23..6de82b5 100644 --- a/src/test/java/it/pagopa/swclient/mil/preset/PresetResourceTest.java +++ b/src/test/java/it/pagopa/swclient/mil/preset/PresetResourceTest.java @@ -1,18 +1,6 @@ package it.pagopa.swclient.mil.preset; -import static io.restassured.RestAssured.given; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInstance; -import org.mockito.Mockito; - +import io.quarkus.mongodb.panache.reactive.ReactivePanacheQuery; import io.quarkus.panache.common.Sort; import io.quarkus.test.common.http.TestHTTPEndpoint; import io.quarkus.test.junit.QuarkusTest; @@ -20,265 +8,348 @@ import io.restassured.http.ContentType; import io.restassured.response.Response; import io.smallrye.mutiny.Uni; +import it.pagopa.swclient.mil.preset.bean.CreatePresetRequest; import it.pagopa.swclient.mil.preset.bean.Notice; import it.pagopa.swclient.mil.preset.bean.PaymentTransaction; -import it.pagopa.swclient.mil.preset.bean.PresetRequest; -import it.pagopa.swclient.mil.preset.bean.PresetResponse; +import it.pagopa.swclient.mil.preset.bean.PresetOperation; +import it.pagopa.swclient.mil.preset.bean.Subscriber; +import it.pagopa.swclient.mil.preset.dao.PresetEntity; import it.pagopa.swclient.mil.preset.dao.PresetRepository; -import it.pagopa.swclient.mil.preset.dao.PresetsEntity; import it.pagopa.swclient.mil.preset.dao.SubscriberEntity; import it.pagopa.swclient.mil.preset.dao.SubscriberRepository; import it.pagopa.swclient.mil.preset.resource.PresetsResource; -import it.pagopa.swclient.mil.preset.resource.SubscribeResource; +import it.pagopa.swclient.mil.preset.util.TestUtils; import it.pagopa.swclient.mil.preset.utils.DateUtils; -import jakarta.ws.rs.InternalServerErrorException; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeoutException; + +import static io.restassured.RestAssured.given; @QuarkusTest @TestHTTPEndpoint(PresetsResource.class) @TestInstance(TestInstance.Lifecycle.PER_CLASS) class PresetResourceTest { - - final static String SESSION_ID = "a6a666e6-97da-4848-b568-99fedccb642c"; - final static String API_VERSION = "1.0.0-alpha-a.b-c-somethinglong+build.1-aef.1-its-okay"; - final static String PA_TAX_CODE = "15376371009"; - final static String SUBSCRIBER_ID = "y46tr3"; - - @InjectMock - SubscriberRepository subscriberRepository; - - @InjectMock - PresetRepository presetRepository; - - Map commonHeaders; - Map presetHeaders; - - @BeforeAll - void createTestObjects() { - presetHeaders = new HashMap<>(); - presetHeaders.put("RequestId", "d0d654e6-97da-4848-b568-99fedccb642b"); - presetHeaders.put("Version", API_VERSION); - - commonHeaders = new HashMap<>(); - commonHeaders.put("RequestId", "d0d654e6-97da-4848-b568-99fedccb642b"); - commonHeaders.put("Version", API_VERSION); - commonHeaders.put("AcquirerId", "4585625"); - commonHeaders.put("Channel", "ATM"); - commonHeaders.put("TerminalId", "0aB9wXyZ"); - commonHeaders.put("SessionId", SESSION_ID); - } - - /* **** preset **** */ - @Test - void createPreset_201() { - - SubscriberEntity subscriberEntity = new SubscriberEntity(); - subscriberEntity.setAcquirerId("4585625"); - subscriberEntity.setChannel("POS"); - subscriberEntity.setLabel("Reception POS"); - subscriberEntity.setLastUsageTimestamp("2023-05-08T10:55:57"); - subscriberEntity.setMerchantId("28405fHfk73x88D"); - subscriberEntity.setPaTaxCode("15376371009"); - subscriberEntity.setSubscriberId("x46tr3"); - subscriberEntity.setSubscriptionTimestamp("2023-05-05T09:31:33"); - subscriberEntity.setTerminalId("0aB9wXyZ"); - List listOfEntities = new ArrayList<>(); - listOfEntities.add(subscriberEntity); - - Mockito - .when(subscriberRepository.list(Mockito.any(String.class), Mockito.any(Map.class))) - .thenReturn(Uni.createFrom().item(listOfEntities)); - - - Mockito - .when(subscriberRepository.update(Mockito.any(SubscriberEntity.class))) - .thenReturn(Uni.createFrom().item(subscriberEntity)); - - final String timestamp = DateUtils.getAndFormatCurrentDate(); - PresetsEntity presetEntity = new PresetsEntity(); - presetEntity.setId("77457c64-0870-407a-b2cb-0f948b04fb9a"); - presetEntity.setPresetId("77457c64-0870-407a-b2cb-0f948b04fb9a"); - presetEntity.setCreationTimestamp(timestamp); - presetEntity.setNoticeNumber("485564829563528563"); - presetEntity.setNoticeTaxCode("15376371009"); - presetEntity.setOperationType(OperationType.PAYMENT_NOTICE.name()); - presetEntity.setPaTaxCode(subscriberEntity.getPaTaxCode()); - presetEntity.setStatus(PresetStatus.TO_EXECUTE.name()); - presetEntity.setStatusTimestamp(timestamp); - presetEntity.setSubscriberId(subscriberEntity.getSubscriberId()); - - Mockito - .when(presetRepository.persist(Mockito.any(PresetsEntity.class))) - .thenReturn(Uni.createFrom().item(presetEntity)); - - PresetRequest request = new PresetRequest(); - request.setNoticeNumber("485564829563528563"); - request.setNoticeTaxCode("15376371009"); - request.setOperationType("PAYMENT_NOTICE"); - request.setPaTaxCode("15376371009"); - request.setSubscriberId("x46tr3"); - - Response response = given() - .contentType(ContentType.JSON) - .headers(presetHeaders) - .body(request) - .and() - .when() - .post() - .then() - .extract() - .response(); - + + static final Logger logger = LoggerFactory.getLogger(PresetResourceTest.class); + + final static String SESSION_ID = "a6a666e6-97da-4848-b568-99fedccb642c"; + final static String API_VERSION = "1.0.0-alpha-a.b-c-somethinglong+build.1-aef.1-its-okay"; + final static String PA_TAX_CODE = "15376371009"; + final static String SUBSCRIBER_ID = "y46tr3"; + + @InjectMock + SubscriberRepository subscriberRepository; + + @InjectMock + PresetRepository presetRepository; + + Map commonHeaders; + Map presetHeaders; + + SubscriberEntity subscriberEntity; + + PresetEntity presetEntity; + + @BeforeAll + void createTestObjects() { + + presetHeaders = new HashMap<>(); + presetHeaders.put("RequestId", "d0d654e6-97da-4848-b568-99fedccb642b"); + presetHeaders.put("Version", API_VERSION); + + commonHeaders = new HashMap<>(); + commonHeaders.put("RequestId", "d0d654e6-97da-4848-b568-99fedccb642b"); + commonHeaders.put("Version", API_VERSION); + commonHeaders.put("AcquirerId", "4585625"); + commonHeaders.put("Channel", "ATM"); + commonHeaders.put("TerminalId", "0aB9wXyZ"); + commonHeaders.put("SessionId", SESSION_ID); + + Subscriber subscriber = new Subscriber(); + subscriber.setAcquirerId("4585625"); + subscriber.setChannel("POS"); + subscriber.setLabel("Reception POS"); + subscriber.setLastUsageTimestamp("2023-05-08T10:55:57"); + subscriber.setMerchantId("28405fHfk73x88D"); + subscriber.setPaTaxCode("15376371009"); + subscriber.setSubscriberId(SUBSCRIBER_ID); + subscriber.setSubscriptionTimestamp("2023-05-05T09:31:33"); + subscriber.setTerminalId("0aB9wXyZ"); + + subscriberEntity = new SubscriberEntity(); + subscriberEntity.id = SUBSCRIBER_ID; + subscriberEntity.subscriber = subscriber; + + final String timestamp = DateUtils.getCurrentTimestamp(); + PresetOperation presetOperation = new PresetOperation(); + presetOperation.setPresetId("77457c64-0870-407a-b2cb-0f948b04fb9a"); + presetOperation.setCreationTimestamp(timestamp); + presetOperation.setNoticeNumber("485564829563528563"); + presetOperation.setNoticeTaxCode("15376371009"); + presetOperation.setOperationType(OperationType.PAYMENT_NOTICE.name()); + presetOperation.setPaTaxCode(PA_TAX_CODE); + presetOperation.setStatus(PresetStatus.TO_EXECUTE.name()); + presetOperation.setStatusTimestamp(timestamp); + presetOperation.setSubscriberId(SUBSCRIBER_ID); + + presetEntity = new PresetEntity(); + presetEntity.id = "77457c64-0870-407a-b2cb-0f948b04fb9a"; + presetEntity.presetOperation = presetOperation; + + + + } + + + /* **** preset **** */ + @Test + void createPreset_201() { + + Mockito + .when(subscriberRepository.list(Mockito.any(String.class), Mockito.anyMap())) + .thenReturn(Uni.createFrom().item(List.of(TestUtils.getClonedObject(subscriberEntity, SubscriberEntity.class)))); + + Mockito + .when(subscriberRepository.update(Mockito.any(SubscriberEntity.class))) + .then(i-> Uni.createFrom().item(i.getArgument(0, SubscriberEntity.class))); + + Mockito + .when(presetRepository.persist(Mockito.any(PresetEntity.class))) + .then(i-> Uni.createFrom().item(i.getArgument(0, PresetEntity.class))); + + CreatePresetRequest request = new CreatePresetRequest(); + request.setNoticeNumber("485564829563528563"); + request.setNoticeTaxCode("15376371009"); + request.setOperationType(OperationType.PAYMENT_NOTICE.name()); + request.setPaTaxCode("15376371009"); + request.setSubscriberId(SUBSCRIBER_ID); + + Response response = given() + .contentType(ContentType.JSON) + .headers(presetHeaders) + .body(request) + .when() + .post() + .then() + .extract() + .response(); + + Assertions.assertEquals(201, response.statusCode()); + Assertions.assertEquals(0, response.body().asString().length()); + + + // check mongo panache repository integration + ArgumentCaptor captorFindQuery = ArgumentCaptor.forClass(String.class); + ArgumentCaptor> captorFindArguments = ArgumentCaptor.forClass(Map.class); + + Mockito.verify(subscriberRepository).list(captorFindQuery.capture(), captorFindArguments.capture()); + Assertions.assertEquals(2, captorFindArguments.getValue().size()); + Assertions.assertEquals(request.getNoticeTaxCode(), captorFindArguments.getValue().get("paTaxCode")); + Assertions.assertEquals(request.getSubscriberId(), captorFindArguments.getValue().get("subscriberId")); + + ArgumentCaptor captorUpdateEntity = ArgumentCaptor.forClass(SubscriberEntity.class); + + Mockito.verify(subscriberRepository).update(captorUpdateEntity.capture()); + Assertions.assertNotNull(captorUpdateEntity.getValue()); + Subscriber updatedSubscriber = captorUpdateEntity.getValue().subscriber; + Assertions.assertEquals(subscriberEntity.subscriber.getAcquirerId(), updatedSubscriber.getAcquirerId()); + Assertions.assertEquals(subscriberEntity.subscriber.getChannel(), updatedSubscriber.getChannel()); + Assertions.assertEquals(subscriberEntity.subscriber.getMerchantId(), updatedSubscriber.getMerchantId()); + Assertions.assertEquals(subscriberEntity.subscriber.getTerminalId(), updatedSubscriber.getTerminalId()); + Assertions.assertEquals(subscriberEntity.subscriber.getPaTaxCode(), updatedSubscriber.getPaTaxCode()); + Assertions.assertEquals(subscriberEntity.subscriber.getSubscriberId(), updatedSubscriber.getSubscriberId()); + Assertions.assertEquals(subscriberEntity.subscriber.getLabel(), updatedSubscriber.getLabel()); + Assertions.assertEquals(subscriberEntity.subscriber.getSubscriptionTimestamp(), updatedSubscriber.getSubscriptionTimestamp()); + Assertions.assertNotEquals(subscriberEntity.subscriber.getLastUsageTimestamp(), updatedSubscriber.getLastUsageTimestamp()); + + ArgumentCaptor captorPersistEntity = ArgumentCaptor.forClass(PresetEntity.class); + + Mockito.verify(presetRepository).persist(captorPersistEntity.capture()); + Assertions.assertNotNull(captorPersistEntity.getValue()); + PresetOperation presetOperation = captorPersistEntity.getValue().presetOperation; + Assertions.assertEquals(request.getOperationType(), presetOperation.getOperationType()); + Assertions.assertNotNull(presetOperation.getPresetId()); + Assertions.assertEquals(request.getPaTaxCode(), presetOperation.getPaTaxCode()); + Assertions.assertEquals(request.getSubscriberId(), presetOperation.getSubscriberId()); + Assertions.assertNotNull(presetOperation.getCreationTimestamp()); + Assertions.assertEquals(PresetStatus.TO_EXECUTE.name(), presetOperation.getStatus()); + Assertions.assertNotNull(presetOperation.getStatusTimestamp()); + Assertions.assertEquals(request.getNoticeTaxCode(), presetOperation.getNoticeTaxCode()); + Assertions.assertEquals(request.getNoticeNumber(), presetOperation.getNoticeNumber()); + Assertions.assertNull(presetOperation.getStatusDetails()); + + logger.debug("Generated preset id -> {}", presetOperation.getPresetId()); + String locationSuffix = "/presets/" + PA_TAX_CODE + "/" + SUBSCRIBER_ID + "/" + presetOperation.getPresetId(); + Assertions.assertTrue(response.getHeader("Location") != null && response.getHeader("Location").endsWith(locationSuffix)); + + } + + + @Test + void createPreset_200_dbError_updateSubscriber() { + + Mockito + .when(subscriberRepository.list(Mockito.any(String.class), Mockito.anyMap())) + .thenReturn(Uni.createFrom().item(List.of(subscriberEntity))); + + Mockito + .when(subscriberRepository.update(Mockito.any(SubscriberEntity.class))) + .thenReturn(Uni.createFrom().failure(new TimeoutException())); + + Mockito + .when(presetRepository.persist(Mockito.any(PresetEntity.class))) + .then(i-> Uni.createFrom().item(i.getArgument(0, PresetEntity.class))); + + CreatePresetRequest request = new CreatePresetRequest(); + request.setNoticeNumber("485564829563528563"); + request.setNoticeTaxCode("15376371009"); + request.setOperationType(OperationType.PAYMENT_NOTICE.name()); + request.setPaTaxCode("15376371009"); + request.setSubscriberId(SUBSCRIBER_ID); + + Response response = given() + .contentType(ContentType.JSON) + .headers(presetHeaders) + .body(request) + .when() + .post() + .then() + .extract() + .response(); + Assertions.assertEquals(201, response.statusCode()); - - Assertions.assertNotNull(response.getHeader(SubscribeResource.LOCATION)); - } - - @Test - void createPreset_400_subscriberNotFound() { - - Mockito - .when(subscriberRepository.list(Mockito.any(String.class), Mockito.any(Map.class))) - .thenReturn(Uni.createFrom().item(List.of())); - - - PresetRequest request = new PresetRequest(); - request.setNoticeNumber("485564829563528563"); - request.setNoticeTaxCode("15376371009"); - request.setOperationType("PAYMENT_NOTICE"); - request.setPaTaxCode("15376371009"); - request.setSubscriberId("x46tr3"); - - Response response = given() - .contentType(ContentType.JSON) - .headers(presetHeaders) - .body(request) - .and() - .when() - .post() - .then() - .extract() - .response(); - + Assertions.assertEquals(0, response.body().asString().length()); + + ArgumentCaptor captorPersistEntity = ArgumentCaptor.forClass(PresetEntity.class); + Mockito.verify(presetRepository).persist(captorPersistEntity.capture()); + Assertions.assertNotNull(captorPersistEntity.getValue()); + PresetOperation presetOperation = captorPersistEntity.getValue().presetOperation; + logger.debug("Generated preset id -> {}", presetOperation.getPresetId()); + String locationSuffix = "/presets/" + PA_TAX_CODE + "/" + SUBSCRIBER_ID + "/" + presetOperation.getPresetId(); + Assertions.assertTrue(response.getHeader("Location") != null && response.getHeader("Location").endsWith(locationSuffix)); + + } + + // TODO add header validation + + // TODO add request validation + + @Test + void createPreset_400_subscriberNotFound() { + + Mockito + .when(subscriberRepository.list(Mockito.any(String.class), Mockito.anyMap())) + .thenReturn(Uni.createFrom().item(List.of())); + + CreatePresetRequest request = new CreatePresetRequest(); + request.setNoticeNumber("485564829563528563"); + request.setNoticeTaxCode("15376371009"); + request.setOperationType("PAYMENT_NOTICE"); + request.setPaTaxCode("15376371009"); + request.setSubscriberId("x46tr3"); + + Response response = given() + .contentType(ContentType.JSON) + .headers(presetHeaders) + .body(request) + .when() + .post() + .then() + .extract() + .response(); + Assertions.assertEquals(400, response.statusCode()); - - Assertions.assertNull(response.getHeader(SubscribeResource.LOCATION)); + Assertions.assertNull(response.getHeader("Location")); Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_SUBSCRIBER_NOT_FOUND)); - } - - @Test - void createPreset_500_datadaseErrorFindSubscriber() { - - SubscriberEntity subscriberEntity = new SubscriberEntity(); - subscriberEntity.setAcquirerId("4585625"); - subscriberEntity.setChannel("POS"); - subscriberEntity.setLabel("Reception POS"); - subscriberEntity.setLastUsageTimestamp("2023-05-08T10:55:57"); - subscriberEntity.setMerchantId("28405fHfk73x88D"); - subscriberEntity.setPaTaxCode("15376371009"); - subscriberEntity.setSubscriberId("x46tr3"); - subscriberEntity.setSubscriptionTimestamp("2023-05-05T09:31:33"); - subscriberEntity.setTerminalId("0aB9wXyZ"); - List listOfEntities = new ArrayList<>(); - listOfEntities.add(subscriberEntity); - - Mockito - .when(subscriberRepository.list(Mockito.any(String.class), Mockito.any(Map.class))) - .thenReturn(Uni.createFrom().failure(new InternalServerErrorException())); - - PresetRequest request = new PresetRequest(); - request.setNoticeNumber("485564829563528563"); - request.setNoticeTaxCode("15376371009"); - request.setOperationType("PAYMENT_NOTICE"); - request.setPaTaxCode("15376371009"); - request.setSubscriberId("x46tr3"); - - Response response = given() - .contentType(ContentType.JSON) - .headers(presetHeaders) - .body(request) - .and() - .when() - .post() - .then() - .extract() - .response(); - + } + + @Test + void createPreset_500_dbError_listSubscribers() { + + Mockito + .when(subscriberRepository.list(Mockito.any(String.class), Mockito.anyMap())) + .thenReturn(Uni.createFrom().failure(new TimeoutException())); + + CreatePresetRequest request = new CreatePresetRequest(); + request.setNoticeNumber("485564829563528563"); + request.setNoticeTaxCode("15376371009"); + request.setOperationType("PAYMENT_NOTICE"); + request.setPaTaxCode("15376371009"); + request.setSubscriberId("x46tr3"); + + Response response = given() + .contentType(ContentType.JSON) + .headers(presetHeaders) + .body(request) + .when() + .post() + .then() + .extract() + .response(); + Assertions.assertEquals(500, response.statusCode()); Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_COMMUNICATION_MONGO_DB)); - Assertions.assertNull(response.getHeader(SubscribeResource.LOCATION)); - } - - - - @Test - void createPreset_500_datadaseErrorInsertingPreset() { - - SubscriberEntity subscriberEntity = new SubscriberEntity(); - subscriberEntity.setAcquirerId("4585625"); - subscriberEntity.setChannel("POS"); - subscriberEntity.setLabel("Reception POS"); - subscriberEntity.setLastUsageTimestamp("2023-05-08T10:55:57"); - subscriberEntity.setMerchantId("28405fHfk73x88D"); - subscriberEntity.setPaTaxCode("15376371009"); - subscriberEntity.setSubscriberId("x46tr3"); - subscriberEntity.setSubscriptionTimestamp("2023-05-05T09:31:33"); - subscriberEntity.setTerminalId("0aB9wXyZ"); - List listOfEntities = new ArrayList<>(); - listOfEntities.add(subscriberEntity); - - Mockito - .when(subscriberRepository.list(Mockito.any(String.class), Mockito.any(Map.class))) - .thenReturn(Uni.createFrom().item(listOfEntities)); - - - Mockito - .when(subscriberRepository.update(Mockito.any(SubscriberEntity.class))) - .thenReturn(Uni.createFrom().item(subscriberEntity)); - - Mockito - .when(presetRepository.persist(Mockito.any(PresetsEntity.class))) - .thenReturn(Uni.createFrom().failure(new InternalServerErrorException())); - - PresetRequest request = new PresetRequest(); - request.setNoticeNumber("485564829563528563"); - request.setNoticeTaxCode("15376371009"); - request.setOperationType("PAYMENT_NOTICE"); - request.setPaTaxCode("15376371009"); - request.setSubscriberId("x46tr3"); - - Response response = given() - .contentType(ContentType.JSON) - .headers(presetHeaders) - .body(request) - .and() - .when() - .post() - .then() - .extract() - .response(); - + Assertions.assertNull(response.getHeader("Location")); + } + + + @Test + void createPreset_500_dbError_persistPreset() { + + Mockito + .when(subscriberRepository.list(Mockito.any(String.class), Mockito.anyMap())) + .thenReturn(Uni.createFrom().item(List.of(subscriberEntity))); + + Mockito + .when(subscriberRepository.update(Mockito.any(SubscriberEntity.class))) + .thenReturn(Uni.createFrom().item(subscriberEntity)); + + Mockito + .when(presetRepository.persist(Mockito.any(PresetEntity.class))) + .thenReturn(Uni.createFrom().failure(new TimeoutException())); + + CreatePresetRequest request = new CreatePresetRequest(); + request.setNoticeNumber("485564829563528563"); + request.setNoticeTaxCode("15376371009"); + request.setOperationType("PAYMENT_NOTICE"); + request.setPaTaxCode("15376371009"); + request.setSubscriberId("x46tr3"); + + Response response = given() + .contentType(ContentType.JSON) + .headers(presetHeaders) + .body(request) + .when() + .post() + .then() + .extract() + .response(); + Assertions.assertEquals(500, response.statusCode()); Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_STORING_TERMINAL_IN_DB)); - Assertions.assertNull(response.getHeader(SubscribeResource.LOCATION)); - } - - @Test - void getPresets_200() { - - final String timestamp = DateUtils.getAndFormatCurrentDate(); - PresetsEntity presetEntity = new PresetsEntity(); - presetEntity.setId("77457c64-0870-407a-b2cb-0f948b04fb9a"); - presetEntity.setPresetId("77457c64-0870-407a-b2cb-0f948b04fb9a"); - presetEntity.setCreationTimestamp(timestamp); - presetEntity.setNoticeNumber("485564829563528563"); - presetEntity.setNoticeTaxCode("15376371009"); - presetEntity.setOperationType(OperationType.PAYMENT_NOTICE.name()); - presetEntity.setPaTaxCode("15376371009"); - presetEntity.setStatus(PresetStatus.TO_EXECUTE.name()); - presetEntity.setStatusTimestamp(timestamp); - presetEntity.setSubscriberId("x46tr3"); - + Assertions.assertNull(response.getHeader("Location")); + + } + + + @Test + void getPresets_200() { + + final String timestamp = DateUtils.getCurrentTimestamp(); + Notice notice = new Notice(); notice.setPaymentToken("648fhg36s95jfg7DS"); notice.setPaTaxCode(PA_TAX_CODE); @@ -287,7 +358,7 @@ void getPresets_200() { notice.setDescription("Test payment notice"); notice.setCompany("Test company"); notice.setOffice("Test office"); - + PaymentTransaction statusDetails = new PaymentTransaction(); statusDetails.setTransactionId("517a4216840E461fB011036A0fd134E1"); statusDetails.setAcquirerId("4585625"); @@ -302,34 +373,46 @@ void getPresets_200() { statusDetails.setFee(100L); statusDetails.setStatus("PRE_CLOSE"); - - presetEntity.setStatusDetails(statusDetails); - - List listOfPresetsEntity = new ArrayList<>(); - listOfPresetsEntity.add(presetEntity); - - Mockito - .when(presetRepository.list(Mockito.any(String.class), Mockito.any(Map.class))) - .thenReturn(Uni.createFrom().item(listOfPresetsEntity)); - - Response response = given() - .contentType(ContentType.JSON) - .headers(presetHeaders) - .and() - .when() - .get("/15376371009/x46tr3") - .then() - .extract() - .response(); - + + PresetOperation presetOperation = new PresetOperation(); + presetOperation.setPresetId("77457c64-0870-407a-b2cb-0f948b04fb9a"); + presetOperation.setCreationTimestamp(timestamp); + presetOperation.setNoticeNumber("485564829563528563"); + presetOperation.setNoticeTaxCode("15376371009"); + presetOperation.setOperationType(OperationType.PAYMENT_NOTICE.name()); + presetOperation.setPaTaxCode("15376371009"); + presetOperation.setStatus(PresetStatus.EXECUTED.name()); + presetOperation.setStatusTimestamp(timestamp); + presetOperation.setSubscriberId("x46tr3"); + presetOperation.setStatusDetails(statusDetails); + + PresetEntity presetEntity = new PresetEntity(); + presetEntity.id = "77457c64-0870-407a-b2cb-0f948b04fb9a"; + presetEntity.presetOperation = presetOperation; + + Mockito + .when(presetRepository.list(Mockito.any(String.class), Mockito.anyMap())) + .thenReturn(Uni.createFrom().item(List.of(presetEntity))); + + Response response = given() + .contentType(ContentType.JSON) + .headers(presetHeaders) + .pathParam("paTaxCode", PA_TAX_CODE) + .pathParam("subscriberId", SUBSCRIBER_ID) + .when() + .get("/{paTaxCode}/{subscriberId}") + .then() + .extract() + .response(); + Assertions.assertEquals(200, response.statusCode()); - + Assertions.assertNotNull(response.jsonPath().getJsonObject("presets")); - List arr = response.jsonPath().getList("presets", PresetResponse.class); - + List arr = response.jsonPath().getList("presets", PresetOperation.class); + Assertions.assertNotNull(arr.get(0).getCreationTimestamp()); Assertions.assertNotNull(arr.get(0).getNoticeNumber()); - + Assertions.assertNotNull(arr.get(0).getNoticeTaxCode()); Assertions.assertNotNull(arr.get(0).getOperationType()); Assertions.assertNotNull(arr.get(0).getPaTaxCode()); @@ -344,7 +427,7 @@ void getPresets_200() { Assertions.assertNotNull(statDetails.getAcquirerId()); Assertions.assertNotNull(statDetails.getStatus()); Assertions.assertNotNull(statDetails.getNotices()); - List noticesResponse = statDetails.getNotices(); + List noticesResponse = statDetails.getNotices(); Assertions.assertNotNull(noticesResponse.get(0).getAmount()); Assertions.assertNotNull(noticesResponse.get(0).getCompany()); Assertions.assertNotNull(noticesResponse.get(0).getDescription()); @@ -352,136 +435,107 @@ void getPresets_200() { Assertions.assertNotNull(noticesResponse.get(0).getOffice()); Assertions.assertNotNull(noticesResponse.get(0).getPaTaxCode()); Assertions.assertNotNull(noticesResponse.get(0).getPaymentToken()); - } - - @Test - void getPresets_200_emptyPreset() { - - final String timestamp = DateUtils.getAndFormatCurrentDate(); - PresetsEntity presetEntity = new PresetsEntity(); - presetEntity.setId("77457c64-0870-407a-b2cb-0f948b04fb9a"); - presetEntity.setPresetId("77457c64-0870-407a-b2cb-0f948b04fb9a"); - presetEntity.setCreationTimestamp(timestamp); - presetEntity.setNoticeNumber("485564829563528563"); - presetEntity.setNoticeTaxCode("15376371009"); - presetEntity.setOperationType(OperationType.PAYMENT_NOTICE.name()); - presetEntity.setPaTaxCode("15376371009"); - presetEntity.setStatus(PresetStatus.TO_EXECUTE.name()); - presetEntity.setStatusTimestamp(timestamp); - presetEntity.setSubscriberId("x46tr3"); - - Notice notice = new Notice(); - notice.setPaymentToken("648fhg36s95jfg7DS"); - notice.setPaTaxCode(PA_TAX_CODE); - notice.setNoticeNumber("485564829563528563"); - notice.setAmount(12345L); - notice.setDescription("Test payment notice"); - notice.setCompany("Test company"); - notice.setOffice("Test office"); - - PaymentTransaction statusDetails = new PaymentTransaction(); - statusDetails.setTransactionId("517a4216840E461fB011036A0fd134E1"); - statusDetails.setAcquirerId("4585625"); - statusDetails.setChannel("POS"); - statusDetails.setMerchantId("28405fHfk73x88D"); - statusDetails.setTerminalId("0aB9wXyZ"); - statusDetails.setInsertTimestamp(timestamp); - List notices = new ArrayList<>(); - notices.add(notice); - statusDetails.setNotices(notices); - statusDetails.setTotalAmount(notices.stream().map(Notice::getAmount).reduce(Long::sum).orElse(0L)); - statusDetails.setFee(100L); - statusDetails.setStatus("PRE_CLOSE"); - - presetEntity.setStatusDetails(statusDetails); - - List listOfPresetsEntity = new ArrayList<>(); -// listOfPresetsEntity.add(presetEntity); - - Mockito - .when(presetRepository.list(Mockito.any(String.class), Mockito.any(Map.class))) - .thenReturn(Uni.createFrom().item(listOfPresetsEntity)); - - Response response = given() - .contentType(ContentType.JSON) - .headers(presetHeaders) - .and() - .when() - .get("/15376371009/x46tr3") - .then() - .extract() - .response(); - + // check mongo panache repository integration + ArgumentCaptor captorFindQuery = ArgumentCaptor.forClass(String.class); + ArgumentCaptor> captorFindArguments = ArgumentCaptor.forClass(Map.class); + + Mockito.verify(presetRepository).list(captorFindQuery.capture(), captorFindArguments.capture()); + Assertions.assertEquals(2, captorFindArguments.getValue().size()); + Assertions.assertEquals(PA_TAX_CODE, captorFindArguments.getValue().get("paTaxCode")); + Assertions.assertEquals(SUBSCRIBER_ID, captorFindArguments.getValue().get("subscriberId")); + } + + @Test + void getPresets_200_emptyPresets() { + + Mockito + .when(presetRepository.list(Mockito.any(String.class), Mockito.anyMap())) + .thenReturn(Uni.createFrom().item(List.of())); + + Response response = given() + .contentType(ContentType.JSON) + .headers(presetHeaders) + .pathParam("paTaxCode", PA_TAX_CODE) + .pathParam("subscriberId", SUBSCRIBER_ID) + .when() + .get("/{paTaxCode}/{subscriberId}") + .then() + .extract() + .response(); + Assertions.assertEquals(200, response.statusCode()); - + Assertions.assertNotNull(response.jsonPath().getJsonObject("presets")); - List arr = response.jsonPath().getList("presets", PresetResponse.class); - - Assertions.assertEquals(0,arr.size()); - } - - @Test - void getLastPreset_200() { - - final String timestamp = DateUtils.getAndFormatCurrentDate(); - PresetsEntity presetEntity = new PresetsEntity(); - presetEntity.setId("77457c64-0870-407a-b2cb-0f948b04fb9a"); - presetEntity.setPresetId("77457c64-0870-407a-b2cb-0f948b04fb9a"); - presetEntity.setCreationTimestamp(timestamp); - presetEntity.setNoticeNumber("485564829563528563"); - presetEntity.setNoticeTaxCode("15376371009"); - presetEntity.setOperationType(OperationType.PAYMENT_NOTICE.name()); - presetEntity.setPaTaxCode("15376371009"); - presetEntity.setStatus(PresetStatus.TO_EXECUTE.name()); - presetEntity.setStatusTimestamp(timestamp); - presetEntity.setSubscriberId("x46tr3"); - - Notice notice = new Notice(); - notice.setPaymentToken("648fhg36s95jfg7DS"); - notice.setPaTaxCode(PA_TAX_CODE); - notice.setNoticeNumber("485564829563528563"); - notice.setAmount(12345L); - notice.setDescription("Test payment notice"); - notice.setCompany("Test company"); - notice.setOffice("Test office"); - - PaymentTransaction statusDetails = new PaymentTransaction(); - statusDetails.setTransactionId("517a4216840E461fB011036A0fd134E1"); - statusDetails.setAcquirerId("4585625"); - statusDetails.setChannel("POS"); - statusDetails.setMerchantId("28405fHfk73x88D"); - statusDetails.setTerminalId("0aB9wXyZ"); - statusDetails.setInsertTimestamp(timestamp); - List notices = new ArrayList<>(); - notices.add(notice); - statusDetails.setNotices(notices); - statusDetails.setTotalAmount(notices.stream().map(Notice::getAmount).reduce(Long::sum).orElse(0L)); + List arr = response.jsonPath().getList("presets", PresetOperation.class); + Assertions.assertEquals(0, arr.size()); + + } + + // TODO add header validation + + @Test + void getPresets_500_dbError_listPresets() { + + Mockito + .when(presetRepository.list(Mockito.any(String.class), Mockito.anyMap())) + .thenReturn(Uni.createFrom().failure(new TimeoutException())); + + Response response = given() + .contentType(ContentType.JSON) + .headers(presetHeaders) + .pathParam("paTaxCode", PA_TAX_CODE) + .pathParam("subscriberId", SUBSCRIBER_ID) + .when() + .get("/{paTaxCode}/{subscriberId}") + .then() + .extract() + .response(); + + Assertions.assertEquals(500, response.statusCode()); + Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_COMMUNICATION_MONGO_DB)); + Assertions.assertNull(response.getHeader("Location")); + + } + + @Test + void getLastPresetsOperation_200() { + + final String timestamp = DateUtils.getCurrentTimestamp(); + + PresetOperation presetOperation = new PresetOperation(); + presetOperation.setPresetId("77457c64-0870-407a-b2cb-0f948b04fb9a"); + presetOperation.setCreationTimestamp(timestamp); + presetOperation.setNoticeNumber("485564829563528563"); + presetOperation.setNoticeTaxCode("15376371009"); + presetOperation.setOperationType(OperationType.PAYMENT_NOTICE.name()); + presetOperation.setPaTaxCode("15376371009"); + presetOperation.setStatus(PresetStatus.EXECUTED.name()); + presetOperation.setStatusTimestamp(timestamp); + presetOperation.setSubscriberId("x46tr3"); + presetOperation.setStatusDetails(null); + + PresetEntity presetEntity = new PresetEntity(); + presetEntity.id = "77457c64-0870-407a-b2cb-0f948b04fb9a"; + presetEntity.presetOperation = presetOperation; + + ReactivePanacheQuery reactivePanacheQuery = Mockito.mock(ReactivePanacheQuery.class); + Mockito.when(presetRepository.find(Mockito.anyString(), Mockito.any(Sort.class), Mockito.anyMap())).thenReturn(reactivePanacheQuery); + Mockito.when(reactivePanacheQuery.firstResult()).thenReturn(Uni.createFrom().item(presetEntity)); + + Response response = given() + .contentType(ContentType.JSON) + .headers(commonHeaders) + .pathParam("paTaxCode", PA_TAX_CODE) + .pathParam("subscriberId", SUBSCRIBER_ID) + .when() + .get("/{paTaxCode}/{subscriberId}/last_to_execute") + .then() + .extract() + .response(); - statusDetails.setFee(100L); - statusDetails.setStatus("PRE_CLOSE"); - - presetEntity.setStatusDetails(statusDetails); - - List listOfPresetsEntity = new ArrayList<>(); - listOfPresetsEntity.add(presetEntity); - - Mockito - .when(presetRepository.list(Mockito.any(String.class), Mockito.any(Sort.class),Mockito.any(Map.class))) - .thenReturn(Uni.createFrom().item(listOfPresetsEntity)); - - Response response = given() - .contentType(ContentType.JSON) - .headers(commonHeaders) - .and() - .when() - .get("/15376371009/x46tr3/last_to_execute") - .then() - .extract() - .response(); - Assertions.assertEquals(200, response.statusCode()); - + Assertions.assertNotNull(response.jsonPath().getString("creationTimestamp")); Assertions.assertNotNull(response.jsonPath().getString("noticeNumber")); Assertions.assertNotNull(response.jsonPath().getString("noticeTaxCode")); @@ -491,89 +545,57 @@ void getLastPreset_200() { Assertions.assertNotNull(response.jsonPath().getString("status")); Assertions.assertNotNull(response.jsonPath().getString("statusTimestamp")); Assertions.assertNotNull(response.jsonPath().getString("subscriberId")); - PaymentTransaction statDetails = response.jsonPath().getObject("statusDetails", PaymentTransaction.class); - Assertions.assertNotNull(statDetails.getAcquirerId()); - Assertions.assertNotNull(statDetails.getChannel()); - Assertions.assertNotNull(statDetails.getInsertTimestamp()); - Assertions.assertNotNull(statDetails.getAcquirerId()); - Assertions.assertNotNull(statDetails.getStatus()); - Assertions.assertNotNull(statDetails.getNotices()); - List noticesResponse = statDetails.getNotices(); - Assertions.assertNotNull(noticesResponse.get(0).getAmount()); - Assertions.assertNotNull(noticesResponse.get(0).getCompany()); - Assertions.assertNotNull(noticesResponse.get(0).getDescription()); - Assertions.assertNotNull(noticesResponse.get(0).getNoticeNumber()); - Assertions.assertNotNull(noticesResponse.get(0).getOffice()); - Assertions.assertNotNull(noticesResponse.get(0).getPaTaxCode()); - Assertions.assertNotNull(noticesResponse.get(0).getPaymentToken()); - } - - @Test - void getLastPreset_404_presetNotFound() { - - List listOfPresetsEntity = new ArrayList<>(); - - Mockito - .when(presetRepository.list(Mockito.any(String.class), Mockito.any(Sort.class),Mockito.any(Map.class))) - .thenReturn(Uni.createFrom().item(listOfPresetsEntity)); - - Response response = given() - .contentType(ContentType.JSON) - .headers(commonHeaders) - .and() - .when() - .get("/15376371009/x46tr3/last_to_execute") - .then() - .extract() - .response(); - + Assertions.assertNull(response.jsonPath().getString("statusDetails")); + + // TODO add check find parameters + + } + + // TODO add header validation + + @Test + void getLastPresetsOperation_404_presetNotFound() { + + ReactivePanacheQuery reactivePanacheQuery = Mockito.mock(ReactivePanacheQuery.class); + Mockito.when(presetRepository.find(Mockito.anyString(), Mockito.any(Sort.class), Mockito.anyMap())).thenReturn(reactivePanacheQuery); + Mockito.when(reactivePanacheQuery.firstResult()).thenReturn(Uni.createFrom().nullItem()); + + Response response = given() + .contentType(ContentType.JSON) + .headers(commonHeaders) + .pathParam("paTaxCode", PA_TAX_CODE) + .pathParam("subscriberId", SUBSCRIBER_ID) + .when() + .get("/{paTaxCode}/{subscriberId}/last_to_execute") + .then() + .extract() + .response(); + Assertions.assertEquals(404, response.statusCode()); - - Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_PRESET_OPERATION_NOT_FOUND)); - - Assertions.assertNull(response.jsonPath().getString("creationTimestamp")); - Assertions.assertNull(response.jsonPath().getString("noticeNumber")); - Assertions.assertNull(response.jsonPath().getString("noticeTaxCode")); - Assertions.assertNull(response.jsonPath().getString("operationType")); - Assertions.assertNull(response.jsonPath().getString("paTaxCode")); - Assertions.assertNull(response.jsonPath().getString("presetId")); - Assertions.assertNull(response.jsonPath().getString("status")); - Assertions.assertNull(response.jsonPath().getString("statusTimestamp")); - Assertions.assertNull(response.jsonPath().getString("subscriberId")); - Assertions.assertNull(response.jsonPath().getObject("statusDetails", PaymentTransaction.class)); - } - - @Test - void getLastPreset_500() { - - Mockito - .when(presetRepository.list(Mockito.any(String.class), Mockito.any(Sort.class),Mockito.any(Map.class))) - .thenReturn(Uni.createFrom().failure(new InternalServerErrorException())); - - Response response = given() - .contentType(ContentType.JSON) - .headers(commonHeaders) - .and() - .when() - .get("/15376371009/x46tr3/last_to_execute") - .then() - .extract() - .response(); - + Assertions.assertEquals(0, response.body().asString().length()); + + } + + @Test + void getLastPresetsOperation_500_dbError_findPreset() { + + ReactivePanacheQuery reactivePanacheQuery = Mockito.mock(ReactivePanacheQuery.class); + Mockito.when(presetRepository.find(Mockito.anyString(), Mockito.any(Sort.class), Mockito.anyMap())).thenReturn(reactivePanacheQuery); + Mockito.when(reactivePanacheQuery.firstResult()).thenReturn(Uni.createFrom().failure(new TimeoutException())); + + Response response = given() + .contentType(ContentType.JSON) + .headers(commonHeaders) + .pathParam("paTaxCode", PA_TAX_CODE) + .pathParam("subscriberId", SUBSCRIBER_ID) + .when() + .get("/{paTaxCode}/{subscriberId}/last_to_execute") + .then() + .extract() + .response(); + Assertions.assertEquals(500, response.statusCode()); - Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_COMMUNICATION_MONGO_DB)); - - Assertions.assertNull(response.jsonPath().getString("creationTimestamp")); - Assertions.assertNull(response.jsonPath().getString("noticeNumber")); - Assertions.assertNull(response.jsonPath().getString("noticeTaxCode")); - Assertions.assertNull(response.jsonPath().getString("operationType")); - Assertions.assertNull(response.jsonPath().getString("paTaxCode")); - Assertions.assertNull(response.jsonPath().getString("presetId")); - Assertions.assertNull(response.jsonPath().getString("status")); - Assertions.assertNull(response.jsonPath().getString("statusTimestamp")); - Assertions.assertNull(response.jsonPath().getString("subscriberId")); - Assertions.assertNull(response.jsonPath().getObject("statusDetails", PaymentTransaction.class)); - - } + + } } diff --git a/src/test/java/it/pagopa/swclient/mil/preset/PresetTopicResourceTest.java b/src/test/java/it/pagopa/swclient/mil/preset/PresetTopicResourceTest.java index 4f83744..96406b2 100644 --- a/src/test/java/it/pagopa/swclient/mil/preset/PresetTopicResourceTest.java +++ b/src/test/java/it/pagopa/swclient/mil/preset/PresetTopicResourceTest.java @@ -1,159 +1,98 @@ package it.pagopa.swclient.mil.preset; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import org.apache.kafka.clients.producer.ProducerRecord; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInstance; -import org.mockito.Mockito; - import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.junit.QuarkusTest; import io.quarkus.test.junit.mockito.InjectMock; -import io.quarkus.test.kafka.InjectKafkaCompanion; -import io.quarkus.test.kafka.KafkaCompanionResource; import io.smallrye.mutiny.Uni; -import io.smallrye.reactive.messaging.kafka.companion.KafkaCompanion; -import io.smallrye.reactive.messaging.kafka.companion.ProducerTask; -import it.pagopa.swclient.mil.preset.bean.Notice; +import io.smallrye.reactive.messaging.memory.InMemoryConnector; +import io.smallrye.reactive.messaging.memory.InMemorySource; import it.pagopa.swclient.mil.preset.bean.PaymentTransaction; -import it.pagopa.swclient.mil.preset.bean.Preset; +import it.pagopa.swclient.mil.preset.bean.PaymentTransactionStatus; +import it.pagopa.swclient.mil.preset.bean.PresetOperation; +import it.pagopa.swclient.mil.preset.dao.PresetEntity; import it.pagopa.swclient.mil.preset.dao.PresetRepository; -import it.pagopa.swclient.mil.preset.dao.PresetsEntity; -import it.pagopa.swclient.mil.preset.resource.PresetTopicResource; -import it.pagopa.swclient.mil.preset.utils.DateUtils; -import it.pagopa.swclient.mil.preset.utils.PresetSerializer; +import it.pagopa.swclient.mil.preset.resource.KafkaTestResourceLifecycleManager; +import it.pagopa.swclient.mil.preset.util.PresetTestData; +import it.pagopa.swclient.mil.preset.util.TestUtils; +import jakarta.enterprise.inject.Any; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.Map; +import java.util.UUID; @QuarkusTest -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -@QuarkusTestResource(KafkaCompanionResource.class) -class PresetTopicResourceTest{ -// - @InjectKafkaCompanion - KafkaCompanion companion; - -// @Inject -// @Channel("presets") -// Emitter emitter; - +@QuarkusTestResource(KafkaTestResourceLifecycleManager.class) +class PresetTopicResourceTest { + + static final Logger logger = LoggerFactory.getLogger(PresetTopicResourceTest.class); + + @Inject @Any + InMemoryConnector connector; + @InjectMock PresetRepository presetRepository; - - @Test - void preset_200() { - - final String timestamp = DateUtils.getAndFormatCurrentDate(); - PresetsEntity presetEntity = new PresetsEntity(); - presetEntity.setId("77457c64-0870-407a-b2cb-0f948b04fb9a"); - presetEntity.setPresetId("77457c64-0870-407a-b2cb-0f948b04fb9a"); - presetEntity.setCreationTimestamp(timestamp); - presetEntity.setNoticeNumber("485564829563528563"); - presetEntity.setNoticeTaxCode("15376371009"); - presetEntity.setOperationType(OperationType.PAYMENT_NOTICE.name()); - presetEntity.setPaTaxCode("15376371009"); - presetEntity.setStatus(PresetStatus.TO_EXECUTE.name()); - presetEntity.setStatusTimestamp(timestamp); - presetEntity.setSubscriberId("csl0kq"); - + + @Test + void consume_close_ok() { + + InMemorySource paymentTransactionsIn = connector.source("presets"); + + String presetId = UUID.randomUUID().toString(); + + PaymentTransaction paymentTransaction = PresetTestData.getPaymentTransaction( + PaymentTransactionStatus.PENDING, + PresetTestData.getMilHeaders(true, true), + PresetTestData.getPreset(presetId, "x46tr3"), + 1); + + PresetEntity presetEntity = PresetTestData.getPresetEntity(presetId, "x46tr3"); + + Mockito + .when(presetRepository.list(Mockito.any(String.class), Mockito.anyMap())) + .thenReturn(Uni.createFrom().item(List.of(TestUtils.getClonedObject(presetEntity, PresetEntity.class)))); + Mockito - .when(presetRepository.list(Mockito.any(String.class), Mockito.any(Map.class))) - .thenReturn(Uni.createFrom().item(presetEntity)); - - -// CompletionStage ack = emitter.send(getPaymentTransaction()); - PresetSerializer s = new PresetSerializer(); - ProducerTask producerTask = companion.produce(byte[].class).usingGenerator(i -> new ProducerRecord<>("presets",s.serialize("presets", getPaymentTransaction())),2); - - - -// ProducerTask producerTask = companion.produce(byte[].class).usingGenerator(i -> new ProducerRecord<>("presets",SerializationUtils.serialize(getPaymentTransaction())),1); - long count = producerTask.awaitCompletion().count(); - - System.out.println(">[" + count + "]<"); - -// System.out.println(">>>>b"); -// ConsumerTask consumerTask = companion.consume(byte[].class).fromTopics("preset-result", 1); -// System.out.println(">>>>c"); -// ConsumerRecord lastRecord = consumerTask.awaitCompletion().getLastRecord(); -// -// System.out.println(">>>>d " + lastRecord.topic()); - - - - } - -/* - @Test - void preset_200() { - - CompletionStage ack = testEmitter.send(getPaymentTransaction()); - System.out.println(">>>>a"); - -// ProducerTask producerTask = companion.produce(byte[].class).usingGenerator(i -> new ProducerRecord<>("presets",SerializationUtils.serialize(getPaymentTransaction())),1); -// long count = producerTask.awaitCompletion().count(); -// System.out.println(">[" + count + "]<"); - -// System.out.println(">>>>b"); -// ConsumerTask consumerTask = companion.consume(byte[].class).fromTopics("presets", 1); -// ConsumerRecord lastRecord = consumerTask.awaitCompletion().getLastRecord(); -// -// System.out.println(">>>>c " + new String(lastRecord.value())); - - - -// System.out.println(">>>>"); -// ConsumerTask orders = companion.consumeStrings().fromTopics("presets", 10); -// orders.awaitCompletion(); -// System.out.println(">>>><<<<"); -// assertEquals(10, orders.count()); - -// ProducerRecord p = new ProducerRecord("presets", getPaymentTransaction()); -// companion.produce(p.getClass()); -// -// companion.topics().create("presets", 1); -// -// companion.registerSerde(PaymentTransaction.class, new PaymentTransaction())); -// companion.produce(getPaymentTransaction().getClass()); - } - */ - private PaymentTransaction getPaymentTransaction() { - PaymentTransaction transaction = new PaymentTransaction(); - transaction.setTransactionId("517a4216840E461fB011036A0fd134E1"); - transaction.setAcquirerId("4585625"); - transaction.setChannel("POS"); - transaction.setMerchantId("28405fHfk73x88D"); - transaction.setTerminalId("0aB9wXyZ"); - transaction.setInsertTimestamp("2023-04-11T16:20:34"); - - Notice notice = new Notice(); - notice.setPaymentToken("648fhg36s95jfg7DS"); - notice.setPaTaxCode("15376371009"); - notice.setNoticeNumber("485564829563528563"); - notice.setAmount(Long.valueOf("12345")); - notice.setDescription("Health ticket for chest x-ray"); - notice.setCompany("ASL Roma 2"); - notice.setOffice("Office RoMA"); - List notices = new ArrayList<>(); - notices.add(notice); - - Preset preset = new Preset(); - preset.setPaTaxCode("15376371009"); - preset.setSubscriberId("csl0kq"); - preset.setPresetId("77457c64-0870-407a-b2cb-0f948b04fb9a"); - transaction.setPreset(preset); - - transaction.setNotices(notices); - - transaction.setTotalAmount(1000L); - transaction.setFee(Long.valueOf("50")); - transaction.setStatus("SSS"); - transaction.setPaymentMethod("CASH"); - transaction.setPaymentTimestamp("2023-05-21T09:29:34.526"); - transaction.setCloseTimestamp("2023-05-21T10:29:34.526"); - return transaction; - } - + .when(presetRepository.update(Mockito.any(PresetEntity.class))) + .then(i -> Uni.createFrom().item(i.getArgument(0, PresetEntity.class))); + + paymentTransactionsIn.send(paymentTransaction); + + // check mongo panache repository integration + ArgumentCaptor captorFindQuery = ArgumentCaptor.forClass(String.class); + ArgumentCaptor> captorFindArguments = ArgumentCaptor.forClass(Map.class); + + Mockito.verify(presetRepository, Mockito.timeout(10000)).list(captorFindQuery.capture(), captorFindArguments.capture()); + Assertions.assertEquals(3, captorFindArguments.getValue().size()); + Assertions.assertEquals(PresetTestData.PA_TAX_CODE, captorFindArguments.getValue().get("paTaxCode")); + Assertions.assertEquals("x46tr3", captorFindArguments.getValue().get("subscriberId")); + Assertions.assertEquals(presetId, captorFindArguments.getValue().get("presetId")); + + ArgumentCaptor captorUpdateQuery = ArgumentCaptor.forClass(PresetEntity.class); + Mockito.verify(presetRepository, Mockito.timeout(10000)).update(captorUpdateQuery.capture()); + + Assertions.assertNotNull(captorUpdateQuery.getValue()); + PresetOperation updatedPreset = captorUpdateQuery.getValue().presetOperation; + logger.info("{}", updatedPreset); + + Assertions.assertEquals(presetEntity.presetOperation.getOperationType(), updatedPreset.getOperationType()); + Assertions.assertEquals(presetEntity.presetOperation.getPresetId(),updatedPreset.getPresetId()); + Assertions.assertEquals(presetEntity.presetOperation.getPaTaxCode(), updatedPreset.getPaTaxCode()); + Assertions.assertEquals(presetEntity.presetOperation.getSubscriberId(), updatedPreset.getSubscriberId()); + Assertions.assertEquals(presetEntity.presetOperation.getCreationTimestamp(),updatedPreset.getCreationTimestamp()); + Assertions.assertEquals(PresetStatus.EXECUTED.name(), updatedPreset.getStatus()); + Assertions.assertNotEquals(presetEntity.presetOperation.getStatusTimestamp(), updatedPreset.getStatusTimestamp()); + Assertions.assertEquals(presetEntity.presetOperation.getNoticeTaxCode(), updatedPreset.getNoticeTaxCode()); + Assertions.assertEquals(presetEntity.presetOperation.getNoticeNumber(), updatedPreset.getNoticeNumber()); + Assertions.assertNotNull(updatedPreset.getStatusDetails()); + + } + } diff --git a/src/test/java/it/pagopa/swclient/mil/preset/SubscribeResourceTest.java b/src/test/java/it/pagopa/swclient/mil/preset/SubscribeResourceTest.java deleted file mode 100644 index 1834887..0000000 --- a/src/test/java/it/pagopa/swclient/mil/preset/SubscribeResourceTest.java +++ /dev/null @@ -1,325 +0,0 @@ -package it.pagopa.swclient.mil.preset; - -import static io.restassured.RestAssured.given; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInstance; -import org.mockito.Mockito; - -import io.quarkus.test.common.http.TestHTTPEndpoint; -import io.quarkus.test.junit.QuarkusTest; -import io.quarkus.test.junit.mockito.InjectMock; -import io.restassured.http.ContentType; -import io.restassured.response.Response; -import io.smallrye.mutiny.Uni; -import it.pagopa.swclient.mil.preset.bean.SubscriberRequest; -import it.pagopa.swclient.mil.preset.bean.SubscriberResponse; -import it.pagopa.swclient.mil.preset.dao.SubscriberEntity; -import it.pagopa.swclient.mil.preset.dao.SubscriberRepository; -import it.pagopa.swclient.mil.preset.resource.SubscribeResource; -import jakarta.ws.rs.InternalServerErrorException; - - -@QuarkusTest -@TestHTTPEndpoint(SubscribeResource.class) -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -class SubscribeResourceTest { - - final static String SESSION_ID = "a6a666e6-97da-4848-b568-99fedccb642c"; - final static String API_VERSION = "1.0.0-alpha-a.b-c-somethinglong+build.1-aef.1-its-okay"; - final static String PA_TAX_CODE = "15376371009"; - final static String SUBSCRIBER_ID = "y46tr3"; - - @InjectMock - SubscriberRepository subscriberRepository; - - Map commonHeaders; - Map presetHeaders; - - @BeforeAll - void createTestObjects() { - presetHeaders = new HashMap<>(); - presetHeaders.put("RequestId", "d0d654e6-97da-4848-b568-99fedccb642b"); - presetHeaders.put("Version", API_VERSION); - - commonHeaders = new HashMap<>(); - commonHeaders.put("RequestId", "d0d654e6-97da-4848-b568-99fedccb642b"); - commonHeaders.put("Version", API_VERSION); - commonHeaders.put("AcquirerId", "4585625"); - commonHeaders.put("Channel", "ATM"); - commonHeaders.put("TerminalId", "0aB9wXyZ"); - commonHeaders.put("SessionId", SESSION_ID); - } - - /* **** get Subscribers **** */ - @Test - void getSubscribers_200() { - - SubscriberEntity subscriberEntity = new SubscriberEntity(); - subscriberEntity.setAcquirerId("4585625"); - subscriberEntity.setChannel("POS"); - subscriberEntity.setLabel("Reception POS"); - subscriberEntity.setLastUsageTimestamp("2023-05-08T10:55:57"); - subscriberEntity.setMerchantId("28405fHfk73x88D"); - subscriberEntity.setPaTaxCode("15376371009"); - subscriberEntity.setSubscriberId("x46tr3"); - subscriberEntity.setSubscriptionTimestamp("2023-05-05T09:31:33"); - subscriberEntity.setTerminalId("0aB9wXyZ"); - List listOfEntities = new ArrayList<>(); - listOfEntities.add(subscriberEntity); - - Mockito - .when(subscriberRepository.list("paTaxCode",PA_TAX_CODE)) - .thenReturn(Uni.createFrom().item(listOfEntities)); - - Response response = given() - .contentType(ContentType.JSON) - .headers(presetHeaders) - .and() - .when() - .get("/" + PA_TAX_CODE) - .then() - .extract() - .response(); - - Assertions.assertEquals(200, response.statusCode()); - - Assertions.assertNotNull(response.jsonPath().getJsonObject("subscribers")); - List res = response.jsonPath().getList("subscribers", SubscriberResponse.class); - - Assertions.assertNotNull(res.get(0).getChannel()); - Assertions.assertNotNull(res.get(0).getMerchantId()); - Assertions.assertNotNull(res.get(0).getTerminalId()); - Assertions.assertNotNull(res.get(0).getPaTaxCode()); - Assertions.assertNotNull(res.get(0).getSubscriberId()); - Assertions.assertNotNull(res.get(0).getLabel()); - Assertions.assertNotNull(res.get(0).getSubscriptionTimestamp()); - Assertions.assertNotNull(res.get(0).getLastUsageTimestamp()); - } - - @Test - void getSubscribers_200_emptyListOfSubribers() { - - List listOfEntities = new ArrayList<>(); - - Mockito - .when(subscriberRepository.list("paTaxCode","")) - .thenReturn(Uni.createFrom().item(listOfEntities)); - - Response response = given() - .contentType(ContentType.JSON) - .headers(presetHeaders) - .and() - .when() - .get("/" + PA_TAX_CODE) - .then() - .extract() - .response(); - - Assertions.assertEquals(200, response.statusCode()); - - Assertions.assertNotNull(response.jsonPath().getJsonObject("subscribers")); - List res = response.jsonPath().getList("subscribers", SubscriberResponse.class); - - Assertions.assertEquals(0,res.size()); - - } - - @Test - void getSubscribers_500_exceptionMongoDb() { - - Mockito - .when(subscriberRepository.list("paTaxCode",PA_TAX_CODE)) - .thenReturn(Uni.createFrom().failure(new InternalServerErrorException())); - - Response response = given() - .contentType(ContentType.JSON) - .headers(presetHeaders) - .and() - .when() - .get("/" + PA_TAX_CODE) - .then() - .extract() - .response(); - - Assertions.assertEquals(500, response.statusCode()); - Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_COMMUNICATION_MONGO_DB)); - Assertions.assertNull(response.jsonPath().getJsonObject("subcribers")); - } - - /* **** unsubscribe **** */ - @Test - void unsubscriber_200() { - - Mockito - .when(subscriberRepository.delete(Mockito.any(String.class),Mockito.any(Map.class))) - .thenReturn(Uni.createFrom().item(1L)); - - Response response = given() - .contentType(ContentType.JSON) - .headers(commonHeaders) - .and() - .when() - .delete("/" + PA_TAX_CODE + "/" + SUBSCRIBER_ID) - .then() - .extract() - .response(); - - Assertions.assertEquals(204, response.statusCode()); - Assertions.assertEquals(0,response.body().asString().length()); - } - - @Test - void unsubscriber_404() { - - Mockito - .when(subscriberRepository.delete(Mockito.any(String.class),Mockito.any(Map.class))) - .thenReturn(Uni.createFrom().item(0L)); - - Response response = given() - .contentType(ContentType.JSON) - .headers(commonHeaders) - .and() - .when() - .delete("/" + PA_TAX_CODE + "/" + SUBSCRIBER_ID) - .then() - .extract() - .response(); - - Assertions.assertEquals(404, response.statusCode()); - Assertions.assertEquals(0,response.body().asString().length()); - } - - @Test - void unsubscriber_500() { - - Mockito - .when(subscriberRepository.delete(Mockito.any(String.class),Mockito.any(Map.class))) - .thenReturn(Uni.createFrom().failure(new InternalServerErrorException())); - - Response response = given() - .contentType(ContentType.JSON) - .headers(commonHeaders) - .and() - .when() - .delete("/" + PA_TAX_CODE + "/" + SUBSCRIBER_ID) - .then() - .extract() - .response(); - - Assertions.assertEquals(500, response.statusCode()); - Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_COMMUNICATION_MONGO_DB)); - } - - /* **** subscribe **** */ - @Test - void subscribe_200() { - SubscriberEntity entity = new SubscriberEntity(); - entity.setAcquirerId("4585625"); - entity.setChannel("POS"); - entity.setLabel("Reception POS"); - entity.setLastUsageTimestamp("2023-05-15T12:08:58.392"); - entity.setSubscriptionTimestamp("2023-05-15T12:08:58.392"); - entity.setMerchantId("28405fHfk73x88D"); - entity.setPaTaxCode("15376371009"); - entity.setTerminalId("0aB9wXyZ"); - - SubscriberRequest request = new SubscriberRequest(); - request.setPaTaxCode("15376371009"); - request.setLabel("Reception POS"); - - Mockito - .when(subscriberRepository.persist(Mockito.any(SubscriberEntity.class))) - .thenReturn(Uni.createFrom().item(entity)); - - Response response = given() - .contentType(ContentType.JSON) - .headers(commonHeaders) - .body(request) - .and() - .when() - .post() - .then() - .extract() - .response(); - - Assertions.assertEquals(201, response.statusCode()); - Assertions.assertEquals(0,response.body().asString().length()); - Assertions.assertNotNull(response.getHeader(SubscribeResource.LOCATION)); - } - - @Test - void subscribe_409() { - SubscriberEntity entity = new SubscriberEntity(); - entity.setAcquirerId("4585625"); - entity.setChannel("POS"); - entity.setLabel("Reception POS"); - entity.setLastUsageTimestamp("2023-05-15T12:08:58.392"); - entity.setSubscriptionTimestamp("2023-05-15T12:08:58.392"); - entity.setMerchantId("28405fHfk73x88D"); - entity.setPaTaxCode("15376371009"); - entity.setTerminalId("0aB9wXyZ"); - entity.setSubscriberId("2Or8Jw"); - - SubscriberRequest request = new SubscriberRequest(); - request.setPaTaxCode("15376371009"); - request.setLabel("Reception POS"); - - Mockito - .when(subscriberRepository.list(Mockito.any(String.class), Mockito.any(Map.class))) - .thenReturn(Uni.createFrom().item(List.of(entity))); - - Response response = given() - .contentType(ContentType.JSON) - .headers(commonHeaders) - .body(request) - .and() - .when() - .post() - .then() - .extract() - .response(); - - Assertions.assertEquals(409, response.statusCode()); - Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_CONFLICT_TERMINAL_IN_DB)); - Assertions.assertNotNull(response.getHeader(SubscribeResource.LOCATION)); - } - - - @Test - void subscribe_500() { - - SubscriberRequest request = new SubscriberRequest(); - request.setPaTaxCode("15376371009"); - request.setLabel("Reception POS"); - - Mockito - .when(subscriberRepository.list(Mockito.any(String.class), Mockito.any(Map.class))) - .thenReturn(Uni.createFrom().item(new ArrayList())); - - Mockito - .when(subscriberRepository.persist(Mockito.any(SubscriberEntity.class))) - .thenReturn(Uni.createFrom().failure(new InternalServerErrorException())); - - Response response = given() - .contentType(ContentType.JSON) - .headers(commonHeaders) - .body(request) - .and() - .when() - .post() - .then() - .extract() - .response(); - - Assertions.assertEquals(500, response.statusCode()); - Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_STORING_TERMINAL_IN_DB)); - } -} diff --git a/src/test/java/it/pagopa/swclient/mil/preset/TerminalsResourceTest.java b/src/test/java/it/pagopa/swclient/mil/preset/TerminalsResourceTest.java new file mode 100644 index 0000000..d6059ab --- /dev/null +++ b/src/test/java/it/pagopa/swclient/mil/preset/TerminalsResourceTest.java @@ -0,0 +1,415 @@ +package it.pagopa.swclient.mil.preset; + +import io.quarkus.test.common.http.TestHTTPEndpoint; +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.mockito.InjectMock; +import io.restassured.http.ContentType; +import io.restassured.response.Response; +import io.smallrye.mutiny.Uni; +import it.pagopa.swclient.mil.preset.bean.SubscribeRequest; +import it.pagopa.swclient.mil.preset.bean.Subscriber; +import it.pagopa.swclient.mil.preset.dao.SubscriberEntity; +import it.pagopa.swclient.mil.preset.dao.SubscriberRepository; +import it.pagopa.swclient.mil.preset.resource.TerminalsResource; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeoutException; + +import static io.restassured.RestAssured.given; + + +@QuarkusTest +@TestHTTPEndpoint(TerminalsResource.class) +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class TerminalsResourceTest { + + final static String SESSION_ID = "a6a666e6-97da-4848-b568-99fedccb642c"; + final static String API_VERSION = "1.0.0-alpha-a.b-c-somethinglong+build.1-aef.1-its-okay"; + final static String PA_TAX_CODE = "15376371009"; + final static String SUBSCRIBER_ID = "y46tr3"; + + @InjectMock + SubscriberRepository subscriberRepository; + + Map commonHeaders; + Map presetHeaders; + + SubscriberEntity subscriberEntity; + + @BeforeAll + void createTestObjects() { + presetHeaders = new HashMap<>(); + presetHeaders.put("RequestId", "d0d654e6-97da-4848-b568-99fedccb642b"); + presetHeaders.put("Version", API_VERSION); + + commonHeaders = new HashMap<>(); + commonHeaders.put("RequestId", "d0d654e6-97da-4848-b568-99fedccb642b"); + commonHeaders.put("Version", API_VERSION); + commonHeaders.put("AcquirerId", "4585625"); + commonHeaders.put("Channel", "ATM"); + commonHeaders.put("TerminalId", "0aB9wXyZ"); + commonHeaders.put("SessionId", SESSION_ID); + + Subscriber subscriber = new Subscriber(); + subscriber.setAcquirerId("4585625"); + subscriber.setChannel("POS"); + subscriber.setLabel("Reception POS"); + subscriber.setLastUsageTimestamp("2023-05-08T10:55:57"); + subscriber.setMerchantId("28405fHfk73x88D"); + subscriber.setPaTaxCode("15376371009"); + subscriber.setSubscriberId(SUBSCRIBER_ID); + subscriber.setSubscriptionTimestamp("2023-05-05T09:31:33"); + subscriber.setTerminalId("0aB9wXyZ"); + + subscriberEntity = new SubscriberEntity(); + subscriberEntity.id = SUBSCRIBER_ID; + subscriberEntity.subscriber = subscriber; + } + + /* **** get Subscribers **** */ + @Test + void getSubscribers_200() { + + Mockito + .when(subscriberRepository.list(Mockito.anyString(), Mockito.any(Object[].class))) + .thenReturn(Uni.createFrom().item(List.of(subscriberEntity))); + + Response response = given() + .contentType(ContentType.JSON) + .headers(presetHeaders) + .and() + .pathParam("paTaxCode", PA_TAX_CODE) + .when() + .get("/{paTaxCode}") + .then() + .extract() + .response(); + + Assertions.assertEquals(200, response.statusCode()); + + Assertions.assertNotNull(response.jsonPath().getJsonObject("subscribers")); + Assertions.assertNull(response.jsonPath().getJsonObject("errors")); + + List subscriberList = response.jsonPath().getList("subscribers", Subscriber.class); + Assertions.assertEquals(subscriberEntity.subscriber.getAcquirerId(), subscriberList.get(0).getAcquirerId()); + Assertions.assertEquals(subscriberEntity.subscriber.getChannel(), subscriberList.get(0).getChannel()); + Assertions.assertNotNull(subscriberEntity.subscriber.getMerchantId(), subscriberList.get(0).getMerchantId()); + Assertions.assertNotNull(subscriberEntity.subscriber.getTerminalId(), subscriberList.get(0).getTerminalId()); + Assertions.assertNotNull(subscriberEntity.subscriber.getPaTaxCode(), subscriberList.get(0).getPaTaxCode()); + Assertions.assertNotNull(subscriberEntity.subscriber.getSubscriberId(), subscriberList.get(0).getSubscriberId()); + Assertions.assertNotNull(subscriberEntity.subscriber.getLabel(), subscriberList.get(0).getLabel()); + Assertions.assertNotNull(subscriberEntity.subscriber.getSubscriptionTimestamp(), subscriberList.get(0).getSubscriptionTimestamp()); + Assertions.assertNotNull(subscriberEntity.subscriber.getLastUsageTimestamp(), subscriberList.get(0).getLastUsageTimestamp()); + + // check mongo panache repository integration + ArgumentCaptor captorQuery = ArgumentCaptor.forClass(String.class); + ArgumentCaptor captorArguments = ArgumentCaptor.forClass(Object[].class); + + Mockito.verify(subscriberRepository).list(captorQuery.capture(), captorArguments.capture()); + Assertions.assertEquals(1, captorArguments.getValue().length); + Assertions.assertEquals(PA_TAX_CODE, captorArguments.getValue()[0].toString()); + + } + + @Test + void getSubscribers_200_noSubscribers() { + + Mockito + .when(subscriberRepository.list(Mockito.anyString(), Mockito.any(Object[].class))) + .thenReturn(Uni.createFrom().item(List.of())); + + Response response = given() + .contentType(ContentType.JSON) + .headers(presetHeaders) + .and() + .pathParam("paTaxCode", PA_TAX_CODE) + .when() + .get("/{paTaxCode}") + .then() + .extract() + .response(); + + Assertions.assertEquals(200, response.statusCode()); + Assertions.assertNull(response.jsonPath().getJsonObject("errors")); + + Assertions.assertNotNull(response.jsonPath().getJsonObject("subscribers")); + List subscriberList = response.jsonPath().getList("subscribers", Subscriber.class); + + Assertions.assertEquals(0, subscriberList.size()); + + } + + // TODO add validation tests for paTaxCode + + // TODO add validation tests for headers + + + @Test + void getSubscribers_500_dbError_listSubscribers() { + + Mockito + .when(subscriberRepository.list(Mockito.anyString(), Mockito.any(Object[].class))) + .thenReturn(Uni.createFrom().failure(new TimeoutException())); + + Response response = given() + .contentType(ContentType.JSON) + .headers(presetHeaders) + .and() + .pathParam("paTaxCode", PA_TAX_CODE) + .when() + .get("/{paTaxCode}") + .then() + .extract() + .response(); + + Assertions.assertEquals(500, response.statusCode()); + Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_COMMUNICATION_MONGO_DB)); + Assertions.assertNull(response.jsonPath().getJsonObject("subscribers")); + + } + + /* **** unsubscribe **** */ + @Test + void unsubscribe_200() { + + Mockito + .when(subscriberRepository.delete(Mockito.any(String.class), Mockito.anyMap())) + .thenReturn(Uni.createFrom().item(1L)); + + Response response = given() + .contentType(ContentType.JSON) + .headers(commonHeaders) + .and() + .pathParam("paTaxCode", PA_TAX_CODE) + .pathParam("subscriberId", SUBSCRIBER_ID) + .when() + .delete("/{paTaxCode}/{subscriberId}") + .then() + .extract() + .response(); + + Assertions.assertEquals(204, response.statusCode()); + Assertions.assertEquals(0, response.body().asString().length()); + + // check mongo panache repository integration + ArgumentCaptor captorQuery = ArgumentCaptor.forClass(String.class); + ArgumentCaptor> captorArguments = ArgumentCaptor.forClass(Map.class); + + Mockito.verify(subscriberRepository).delete(captorQuery.capture(), captorArguments.capture()); + Assertions.assertEquals(2, captorArguments.getValue().size()); + Assertions.assertEquals(PA_TAX_CODE, captorArguments.getValue().get("paTaxCode")); + Assertions.assertEquals(SUBSCRIBER_ID, captorArguments.getValue().get("subscriberId")); + + } + + // TODO add validation tests for paTaxCode, subscriberId + + // TODO add validation tests for headers + + @Test + void unsubscribe_404_unknownSubscriberId() { + + Mockito + .when(subscriberRepository.delete(Mockito.any(String.class), Mockito.anyMap())) + .thenReturn(Uni.createFrom().item(0L)); + + Response response = given() + .contentType(ContentType.JSON) + .headers(commonHeaders) + .and() + .pathParam("paTaxCode", PA_TAX_CODE) + .pathParam("subscriberId", SUBSCRIBER_ID) + .when() + .delete("/{paTaxCode}/{subscriberId}") + .then() + .extract() + .response(); + + Assertions.assertEquals(404, response.statusCode()); + Assertions.assertEquals(0, response.body().asString().length()); + } + + @Test + void unsubscribe_500_dbError_deleteSubscriber() { + + Mockito + .when(subscriberRepository.delete(Mockito.any(String.class), Mockito.anyMap())) + .thenReturn(Uni.createFrom().failure(new TimeoutException())); + + Response response = given() + .contentType(ContentType.JSON) + .headers(commonHeaders) + .and() + .pathParam("paTaxCode", PA_TAX_CODE) + .pathParam("subscriberId", SUBSCRIBER_ID) + .when() + .delete("/{paTaxCode}/{subscriberId}") + .then() + .extract() + .response(); + + Assertions.assertEquals(500, response.statusCode()); + Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_COMMUNICATION_MONGO_DB)); + } + + /* **** subscribe **** */ + @Test + void subscribe_200() { + + SubscribeRequest request = new SubscribeRequest(); + request.setPaTaxCode("15376371009"); + request.setLabel("Reception POS"); + + Mockito + .when(subscriberRepository.list(Mockito.any(String.class), Mockito.anyMap())) + .thenReturn(Uni.createFrom().item(List.of())); + + Mockito + .when(subscriberRepository.persist(Mockito.any(SubscriberEntity.class))) + .then(i -> Uni.createFrom().item(i.getArgument(0, SubscriberEntity.class))); + + Response response = given() + .contentType(ContentType.JSON) + .headers(commonHeaders) + .body(request) + .and() + .when() + .post() + .then() + .extract() + .response(); + + Assertions.assertEquals(201, response.statusCode()); + Assertions.assertEquals(0, response.body().asString().length()); + + + // check mongo panache repository integration + ArgumentCaptor captorFindQuery = ArgumentCaptor.forClass(String.class); + ArgumentCaptor> captorFindArguments = ArgumentCaptor.forClass(Map.class); + + Mockito.verify(subscriberRepository).list(captorFindQuery.capture(), captorFindArguments.capture()); + Assertions.assertEquals(5, captorFindArguments.getValue().size()); + Assertions.assertEquals(commonHeaders.get("AcquirerId"), captorFindArguments.getValue().get("acquirerId")); + Assertions.assertEquals(commonHeaders.get("Channel"), captorFindArguments.getValue().get("channel")); + Assertions.assertEquals(commonHeaders.get("MerchantId"), captorFindArguments.getValue().get("merchantId")); + Assertions.assertEquals(commonHeaders.get("TerminalId"), captorFindArguments.getValue().get("terminalId")); + Assertions.assertEquals(request.getPaTaxCode(), captorFindArguments.getValue().get("paTaxCode")); + + ArgumentCaptor captorPersistEntity = ArgumentCaptor.forClass(SubscriberEntity.class); + + Mockito.verify(subscriberRepository).persist(captorPersistEntity.capture()); + Assertions.assertNotNull(captorPersistEntity.getValue()); + Subscriber persistedSubscriber = captorPersistEntity.getValue().subscriber; + Assertions.assertEquals(commonHeaders.get("AcquirerId"), persistedSubscriber.getAcquirerId()); + Assertions.assertEquals(commonHeaders.get("Channel"), persistedSubscriber.getChannel()); + Assertions.assertEquals(commonHeaders.get("MerchantId"), persistedSubscriber.getMerchantId()); + Assertions.assertEquals(commonHeaders.get("TerminalId"), persistedSubscriber.getTerminalId()); + Assertions.assertEquals(request.getPaTaxCode(), persistedSubscriber.getPaTaxCode()); + Assertions.assertNotNull(persistedSubscriber.getSubscriberId()); + Assertions.assertEquals(request.getLabel(), persistedSubscriber.getLabel()); + Assertions.assertNotNull(persistedSubscriber.getSubscriptionTimestamp()); + Assertions.assertNull(persistedSubscriber.getLastUsageTimestamp()); + + Assertions.assertTrue(response.getHeader("Location") != null && + response.getHeader("Location").endsWith("/terminals/" + PA_TAX_CODE + "/" + persistedSubscriber.getSubscriberId())); + + } + + // TODO add validation tests for headers + + @Test + void subscribe_409_subscriberAlreadyExists() { + + SubscribeRequest request = new SubscribeRequest(); + request.setPaTaxCode("15376371009"); + request.setLabel("Reception POS"); + + Mockito + .when(subscriberRepository.list(Mockito.any(String.class), Mockito.anyMap())) + .thenReturn(Uni.createFrom().item(List.of(subscriberEntity))); + + Response response = given() + .contentType(ContentType.JSON) + .headers(commonHeaders) + .body(request) + .and() + .when() + .post() + .then() + .extract() + .response(); + + Assertions.assertEquals(409, response.statusCode()); + Assertions.assertEquals(0, response.body().asString().length()); + Assertions.assertTrue(response.getHeader("Location") != null && + response.getHeader("Location").endsWith("/terminals/" + PA_TAX_CODE + "/" + SUBSCRIBER_ID)); + + } + + @Test + void subscribe_500_dbError_listSubscribers() { + + SubscribeRequest request = new SubscribeRequest(); + request.setPaTaxCode("15376371009"); + request.setLabel("Reception POS"); + + Mockito + .when(subscriberRepository.list(Mockito.any(String.class), Mockito.anyMap())) + .thenReturn(Uni.createFrom().failure(new TimeoutException())); + + Response response = given() + .contentType(ContentType.JSON) + .headers(commonHeaders) + .body(request) + .and() + .when() + .post() + .then() + .extract() + .response(); + + Assertions.assertEquals(500, response.statusCode()); + Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_COMMUNICATION_MONGO_DB)); + + } + + @Test + void subscribe_500_dbError_persistSubscriber() { + + SubscribeRequest request = new SubscribeRequest(); + request.setPaTaxCode("15376371009"); + request.setLabel("Reception POS"); + + Mockito + .when(subscriberRepository.list(Mockito.any(String.class), Mockito.anyMap())) + .thenReturn(Uni.createFrom().item(new ArrayList<>())); + + Mockito + .when(subscriberRepository.persist(Mockito.any(SubscriberEntity.class))) + .thenReturn(Uni.createFrom().failure(new TimeoutException())); + + Response response = given() + .contentType(ContentType.JSON) + .headers(commonHeaders) + .body(request) + .and() + .when() + .post() + .then() + .extract() + .response(); + + Assertions.assertEquals(500, response.statusCode()); + Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_STORING_TERMINAL_IN_DB)); + + } +} diff --git a/src/test/java/it/pagopa/swclient/mil/preset/it/PresetResourceTestIT.java b/src/test/java/it/pagopa/swclient/mil/preset/it/PresetResourceTestIT.java index dcd038d..7858d09 100644 --- a/src/test/java/it/pagopa/swclient/mil/preset/it/PresetResourceTestIT.java +++ b/src/test/java/it/pagopa/swclient/mil/preset/it/PresetResourceTestIT.java @@ -1,29 +1,15 @@ package it.pagopa.swclient.mil.preset.it; -import static io.restassured.RestAssured.given; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInstance; - import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.common.http.TestHTTPEndpoint; import io.quarkus.test.junit.QuarkusIntegrationTest; -import io.restassured.http.ContentType; -import io.restassured.response.Response; -import it.pagopa.swclient.mil.preset.ErrorCode; -import it.pagopa.swclient.mil.preset.bean.Notice; -import it.pagopa.swclient.mil.preset.bean.PaymentTransaction; -import it.pagopa.swclient.mil.preset.bean.PresetRequest; -import it.pagopa.swclient.mil.preset.bean.PresetResponse; import it.pagopa.swclient.mil.preset.resource.MongoTestResource; import it.pagopa.swclient.mil.preset.resource.PresetsResource; -import it.pagopa.swclient.mil.preset.resource.SubscribeResource; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; + +import java.util.HashMap; +import java.util.Map; @QuarkusIntegrationTest @QuarkusTestResource(value=MongoTestResource.class,restrictToAnnotatedClass = true) diff --git a/src/test/java/it/pagopa/swclient/mil/preset/it/PresetTopicResourceTestIT.java b/src/test/java/it/pagopa/swclient/mil/preset/it/PresetTopicResourceTestIT.java index 862e84c..bfaa801 100644 --- a/src/test/java/it/pagopa/swclient/mil/preset/it/PresetTopicResourceTestIT.java +++ b/src/test/java/it/pagopa/swclient/mil/preset/it/PresetTopicResourceTestIT.java @@ -1,40 +1,31 @@ package it.pagopa.swclient.mil.preset.it; -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.lang3.SerializationUtils; -import org.apache.kafka.clients.producer.ProducerRecord; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInstance; - -import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.junit.QuarkusIntegrationTest; -import io.quarkus.test.kafka.InjectKafkaCompanion; -import io.quarkus.test.kafka.KafkaCompanionResource; -import io.smallrye.reactive.messaging.kafka.companion.KafkaCompanion; -import io.smallrye.reactive.messaging.kafka.companion.ProducerTask; import it.pagopa.swclient.mil.preset.bean.Notice; import it.pagopa.swclient.mil.preset.bean.PaymentTransaction; import it.pagopa.swclient.mil.preset.bean.Preset; +import org.junit.jupiter.api.TestInstance; + +import java.util.ArrayList; +import java.util.List; @QuarkusIntegrationTest //@QuarkusTestResource(value=MongoTestResource.class,restrictToAnnotatedClass = true) //@TestHTTPEndpoint(PresetsResource.class) @TestInstance(TestInstance.Lifecycle.PER_CLASS) -@QuarkusTestResource(KafkaCompanionResource.class) +//@QuarkusTestResource(KafkaCompanionResource.class) class PresetTopicResourceTestIT { - @InjectKafkaCompanion - KafkaCompanion companion; +// @InjectKafkaCompanion + // KafkaCompanion companion; - @Test - void preset_200() { - - ProducerTask producerTask = companion.produce(byte[].class).usingGenerator(i -> new ProducerRecord<>("presets",SerializationUtils.serialize(getPaymentTransaction())),1); - long count = producerTask.awaitCompletion().count(); - System.out.println(">[" + count + "]<"); - System.out.println(">>>>a"); - } +// @Test +// void preset_200() { +// +// ProducerTask producerTask = companion.produce(byte[].class).usingGenerator(i -> new ProducerRecord<>("presets",SerializationUtils.serialize(getPaymentTransaction())),1); +// long count = producerTask.awaitCompletion().count(); +// System.out.println(">[" + count + "]<"); +// System.out.println(">>>>a"); +// } private PaymentTransaction getPaymentTransaction() { PaymentTransaction transaction = new PaymentTransaction(); diff --git a/src/test/java/it/pagopa/swclient/mil/preset/it/SubscribeResourceTestIT.java b/src/test/java/it/pagopa/swclient/mil/preset/it/SubscribeResourceTestIT.java index f604231..b35d450 100644 --- a/src/test/java/it/pagopa/swclient/mil/preset/it/SubscribeResourceTestIT.java +++ b/src/test/java/it/pagopa/swclient/mil/preset/it/SubscribeResourceTestIT.java @@ -1,32 +1,21 @@ package it.pagopa.swclient.mil.preset.it; -import static io.restassured.RestAssured.given; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInstance; - import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.common.http.TestHTTPEndpoint; import io.quarkus.test.junit.QuarkusIntegrationTest; -import io.restassured.http.ContentType; -import io.restassured.response.Response; -import it.pagopa.swclient.mil.preset.ErrorCode; -import it.pagopa.swclient.mil.preset.bean.SubscriberRequest; -import it.pagopa.swclient.mil.preset.bean.SubscriberResponse; import it.pagopa.swclient.mil.preset.resource.MongoTestResource; -import it.pagopa.swclient.mil.preset.resource.SubscribeResource; +import it.pagopa.swclient.mil.preset.resource.TerminalsResource; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; + +import java.util.HashMap; +import java.util.Map; @QuarkusIntegrationTest @QuarkusTestResource(value=MongoTestResource.class,restrictToAnnotatedClass = true) -@TestHTTPEndpoint(SubscribeResource.class) +@TestHTTPEndpoint(TerminalsResource.class) @TestInstance(TestInstance.Lifecycle.PER_CLASS) class SubscribeResourceTestIT { final static String SESSION_ID = "a6a666e6-97da-4848-b568-99fedccb642c"; diff --git a/src/test/java/it/pagopa/swclient/mil/preset/resource/KafkaResource.java b/src/test/java/it/pagopa/swclient/mil/preset/resource/KafkaResource.java deleted file mode 100644 index dcb25a1..0000000 --- a/src/test/java/it/pagopa/swclient/mil/preset/resource/KafkaResource.java +++ /dev/null @@ -1,26 +0,0 @@ -/** - * - */ -package it.pagopa.swclient.mil.preset.resource; - -import java.util.HashMap; -import java.util.Map; - -import io.quarkus.test.common.QuarkusTestResourceLifecycleManager; -import io.smallrye.reactive.messaging.memory.InMemoryConnector; - -public class KafkaResource implements QuarkusTestResourceLifecycleManager { - - @Override - public Map start() { - Map env = new HashMap<>(); - Map props1 = InMemoryConnector.switchIncomingChannelsToInMemory("orders"); - env.putAll(props1); - return env; - } - - @Override - public void stop() { - InMemoryConnector.clear(); - } -} diff --git a/src/test/java/it/pagopa/swclient/mil/preset/resource/KafkaTestResourceLifecycleManager.java b/src/test/java/it/pagopa/swclient/mil/preset/resource/KafkaTestResourceLifecycleManager.java new file mode 100644 index 0000000..121cee8 --- /dev/null +++ b/src/test/java/it/pagopa/swclient/mil/preset/resource/KafkaTestResourceLifecycleManager.java @@ -0,0 +1,27 @@ +package it.pagopa.swclient.mil.preset.resource; + +import io.quarkus.test.common.QuarkusTestResourceLifecycleManager; +import io.smallrye.reactive.messaging.memory.InMemoryConnector; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.Map; + +public class KafkaTestResourceLifecycleManager implements QuarkusTestResourceLifecycleManager { + + static final Logger logger = LoggerFactory.getLogger(KafkaTestResourceLifecycleManager.class); + + @Override + public Map start() { + logger.info("Starting in memory Kafka connector"); + Map props1 = InMemoryConnector.switchIncomingChannelsToInMemory("presets"); + return new HashMap<>(props1); + } + + @Override + public void stop() { + logger.info("Stopping in memory Kafka connector"); + InMemoryConnector.clear(); + } +} diff --git a/src/test/java/it/pagopa/swclient/mil/preset/resource/MongoTestResource.java b/src/test/java/it/pagopa/swclient/mil/preset/resource/MongoTestResource.java index e72f987..71b4656 100644 --- a/src/test/java/it/pagopa/swclient/mil/preset/resource/MongoTestResource.java +++ b/src/test/java/it/pagopa/swclient/mil/preset/resource/MongoTestResource.java @@ -1,25 +1,23 @@ package it.pagopa.swclient.mil.preset.resource; -import java.util.Iterator; -import java.util.Map; - +import com.google.common.collect.ImmutableMap; +import io.quarkus.test.common.DevServicesContext; +import io.quarkus.test.common.QuarkusTestResourceLifecycleManager; import org.junit.runner.Description; import org.junit.runners.model.Statement; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testcontainers.containers.Container.ExecResult; import org.testcontainers.containers.GenericContainer; -//import org.testcontainers.containers.MongoDBContainer; import org.testcontainers.containers.Network; import org.testcontainers.containers.output.Slf4jLogConsumer; import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.utility.DockerImageName; -import com.google.common.collect.ImmutableMap; +import java.util.Iterator; +import java.util.Map; -import io.quarkus.test.common.DevServicesContext; -import io.quarkus.test.common.QuarkusTestResourceLifecycleManager; -public class MongoTestResource implements QuarkusTestResourceLifecycleManager,DevServicesContext.ContextAware { +public class MongoTestResource implements QuarkusTestResourceLifecycleManager, DevServicesContext.ContextAware { private static final Logger logger = LoggerFactory.getLogger(MongoTestResource.class); private static final String MONGO_NETWORK_ALIAS = "mongo-it"; diff --git a/src/test/java/it/pagopa/swclient/mil/preset/util/PresetTestData.java b/src/test/java/it/pagopa/swclient/mil/preset/util/PresetTestData.java new file mode 100644 index 0000000..b404c0e --- /dev/null +++ b/src/test/java/it/pagopa/swclient/mil/preset/util/PresetTestData.java @@ -0,0 +1,147 @@ +package it.pagopa.swclient.mil.preset.util; + +import it.pagopa.swclient.mil.preset.OperationType; +import it.pagopa.swclient.mil.preset.PresetStatus; +import it.pagopa.swclient.mil.preset.bean.Notice; +import it.pagopa.swclient.mil.preset.bean.PaymentTransaction; +import it.pagopa.swclient.mil.preset.bean.PaymentTransactionStatus; +import it.pagopa.swclient.mil.preset.bean.Preset; +import it.pagopa.swclient.mil.preset.bean.PresetOperation; +import it.pagopa.swclient.mil.preset.dao.PresetEntity; +import org.testcontainers.shaded.org.apache.commons.lang3.RandomStringUtils; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public final class PresetTestData { + + public static Map getMilHeaders(boolean isPos, boolean isKnownAcquirer) { + Map headerMap = new HashMap<>(); + headerMap.put("RequestId", UUID.randomUUID().toString()); + headerMap.put("Version", "1.0.0"); + headerMap.put("AcquirerId", isKnownAcquirer ? PresetTestData.ACQUIRER_ID_KNOWN : PresetTestData.ACQUIRER_ID_NOT_KNOWN); + headerMap.put("Channel", isPos ? "POS" : "ATM"); + headerMap.put("TerminalId", "0aB9wXyZ"); + if (isPos) headerMap.put("MerchantId", "28405fHfk73x88D"); + headerMap.put("SessionId", UUID.randomUUID().toString()); + return headerMap; + } + + public static Notice getNotice(String paymentToken) { + Notice notice = new Notice(); + notice.setPaymentToken(paymentToken); + notice.setPaTaxCode(PA_TAX_CODE); + notice.setNoticeNumber(NOTICE_NUMBER); + notice.setAmount(AMOUNT); + notice.setDescription("Test payment notice"); + notice.setCompany("Test company"); + notice.setOffice("Test office"); + return notice; + } + + public static Preset getPreset(String presetId, String subscriberId) { + Preset preset = new Preset(); + preset.setSubscriberId(subscriberId); + preset.setPresetId(presetId); + preset.setPaTaxCode(PA_TAX_CODE); + return preset; + } + + public static PresetEntity getPresetEntity(String presetId, String subscriberId) { + + String timestamp = LocalDateTime.ofInstant(Instant.now().minus(1, ChronoUnit.MINUTES).truncatedTo(ChronoUnit.SECONDS), ZoneOffset.UTC).toString(); + + PresetOperation presetOperation = new PresetOperation(); + presetOperation.setPresetId(presetId); + presetOperation.setCreationTimestamp(timestamp); + presetOperation.setNoticeNumber("485564829563528563"); + presetOperation.setNoticeTaxCode(PA_TAX_CODE); + presetOperation.setOperationType(OperationType.PAYMENT_NOTICE.name()); + presetOperation.setPaTaxCode(PA_TAX_CODE); + presetOperation.setStatus(PresetStatus.TO_EXECUTE.name()); + presetOperation.setStatusTimestamp(timestamp); + presetOperation.setSubscriberId(subscriberId); + + PresetEntity presetEntity = new PresetEntity(); + presetEntity.id = presetId; + presetEntity.presetOperation = presetOperation; + + return presetEntity; + } + + public static PaymentTransaction getPaymentTransaction(PaymentTransactionStatus status, + Map headers, + Preset preset, + int tokens) { + + String transactionId = RandomStringUtils.random(32, true, true); + + if (status == PaymentTransactionStatus.ABORTED) throw new IllegalArgumentException(); + + String timestamp = LocalDateTime.ofInstant(Instant.now().truncatedTo(ChronoUnit.SECONDS), ZoneOffset.UTC).toString(); + + var paymentTransaction = new PaymentTransaction(); + paymentTransaction.setTransactionId(transactionId); + paymentTransaction.setAcquirerId(headers.get("AcquirerId")); + paymentTransaction.setChannel(headers.get("Channel")); + paymentTransaction.setMerchantId(headers.get("MerchantId")); + paymentTransaction.setTerminalId(headers.get("TerminalId")); + paymentTransaction.setInsertTimestamp(timestamp); + + List notices = new ArrayList<>(); + for (int i = 0; i < tokens; i++) { + notices.add(getNotice(RandomStringUtils.random(32, true, true))); + } + + paymentTransaction.setNotices(notices); + paymentTransaction.setTotalAmount(notices.stream().map(Notice::getAmount).reduce(Long::sum).orElse(0L)); + + paymentTransaction.setFee(100L); + paymentTransaction.setStatus(status.name()); + + switch (status) { + case PRE_CLOSE -> {} + case PENDING,ERROR_ON_PAYMENT, ERROR_ON_CLOSE -> { + paymentTransaction.setPaymentMethod("PAGOBANCOMAT"); + paymentTransaction.setPaymentTimestamp(timestamp); + paymentTransaction.setCloseTimestamp(timestamp); + } + case CLOSED, ERROR_ON_RESULT -> { + paymentTransaction.setPaymentMethod("PAGOBANCOMAT"); + paymentTransaction.setPaymentTimestamp(timestamp); + paymentTransaction.setCloseTimestamp(timestamp); + paymentTransaction.setPaymentDate(timestamp); + paymentTransaction.setCallbackTimestamp(timestamp); + notices.forEach(n -> { + n.setDebtor("Mario Rossi"); + n.setCreditorReferenceId("abcde"); + }); + } + } + + paymentTransaction.setPreset(preset); + + return paymentTransaction; + + } + + public static final String PA_TAX_CODE = "15376371009"; + public static final String NOTICE_NUMBER = "000000000000000000"; + public static final long AMOUNT = 9999; + + // ACQUIRER ID + public static final String ACQUIRER_ID_KNOWN = "4585625"; + public static final String ACQUIRER_ID_NOT_KNOWN = "4585626"; + + private PresetTestData() { + } + + +} diff --git a/src/test/java/it/pagopa/swclient/mil/preset/util/TestUtils.java b/src/test/java/it/pagopa/swclient/mil/preset/util/TestUtils.java new file mode 100644 index 0000000..4bf29dc --- /dev/null +++ b/src/test/java/it/pagopa/swclient/mil/preset/util/TestUtils.java @@ -0,0 +1,206 @@ +package it.pagopa.swclient.mil.preset.util; + +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.ws.rs.core.Response; +import org.jboss.resteasy.reactive.ClientWebApplicationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.beans.IntrospectionException; +import java.beans.PropertyDescriptor; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Map; + +public class TestUtils { + + static final Logger logger = LoggerFactory.getLogger(TestUtils.class); + + private static final ObjectMapper objectMapper = new ObjectMapper(); + + private TestUtils() {} + + public static T getClonedObject(T objectToClone, Class clazz) { + try { + return objectMapper.readValue(objectMapper.writeValueAsString(objectToClone), clazz); + } catch (JsonProcessingException e) { + logger.error("Error while cloning object {}", objectToClone); + return objectToClone; + } + } + +// +// public static Stream provideNodeIntegrationErrorCases() { +// return Stream.of( +// Arguments.of(ExceptionType.CLIENT_WEB_APPLICATION_EXCEPTION_400, ErrorCode.ERROR_CALLING_NODE_SOAP_SERVICES), +// Arguments.of(ExceptionType.CLIENT_WEB_APPLICATION_EXCEPTION_500, ErrorCode.ERROR_CALLING_NODE_SOAP_SERVICES), +// Arguments.of(ExceptionType.TIMEOUT_EXCEPTION, ErrorCode.ERROR_CALLING_NODE_SOAP_SERVICES), +// Arguments.of(ExceptionType.UNPARSABLE_EXCEPTION, ErrorCode.ERROR_CALLING_NODE_SOAP_SERVICES) +// ); +// } +// +// public static Stream provideMilIntegrationErrorCases() { +// return Stream.of( +// Arguments.of(ExceptionType.CLIENT_WEB_APPLICATION_EXCEPTION_400, ErrorCode.ERROR_CALLING_MIL_REST_SERVICES), +// Arguments.of(ExceptionType.CLIENT_WEB_APPLICATION_EXCEPTION_404, ErrorCode.UNKNOWN_ACQUIRER_ID), +// Arguments.of(ExceptionType.CLIENT_WEB_APPLICATION_EXCEPTION_500, ErrorCode.ERROR_CALLING_MIL_REST_SERVICES), +// Arguments.of(ExceptionType.TIMEOUT_EXCEPTION, ErrorCode.ERROR_CALLING_MIL_REST_SERVICES), +// Arguments.of(ExceptionType.UNPARSABLE_EXCEPTION, ErrorCode.ERROR_CALLING_MIL_REST_SERVICES) +// ); +// } +// +// public static Stream provideHeaderValidationErrorCases() { +// return Stream.of( +// // RequestId null +// Arguments.of(removeAndGet(PaymentTestData.getMilHeaders(false, true), "RequestId"), it.pagopa.swclient.mil.ErrorCode.REQUEST_ID_MUST_NOT_BE_NULL ), +// // RequestId invalid regex +// Arguments.of(putAndGet(PaymentTestData.getMilHeaders(false, true), "RequestId", "dmmmm0d654e6-97da-4848-b568-99fedccb642ba"), it.pagopa.swclient.mil.ErrorCode.REQUEST_ID_MUST_MATCH_REGEXP ), +// // Version longer than max size +// Arguments.of(putAndGet(PaymentTestData.getMilHeaders(false, true), "Version", "1.0.0-alpha-a.b-c-somethinglong+build.1-aef.1-its-okayokayokayokayokayokayokayokay"), it.pagopa.swclient.mil.ErrorCode.VERSION_SIZE_MUST_BE_AT_MOST_MAX ), +// // Version invalid regex +// Arguments.of(putAndGet(PaymentTestData.getMilHeaders(false, true), "Version", ".1.0.0-alpha-a.b-c-somethinglong+build.1-aef.1-its-okay"), it.pagopa.swclient.mil.ErrorCode.VERSION_MUST_MATCH_REGEXP ), +// // AcquirerId null +// Arguments.of(removeAndGet(PaymentTestData.getMilHeaders(false, true), "AcquirerId"), it.pagopa.swclient.mil.ErrorCode.ACQUIRER_ID_MUST_NOT_BE_NULL ), +// // AcquirerId invalid regex +// Arguments.of(putAndGet(PaymentTestData.getMilHeaders(false, true), "AcquirerId", "45856bb25"), it.pagopa.swclient.mil.ErrorCode.ACQUIRER_ID_MUST_MATCH_REGEXP ), +// // Channel null +// Arguments.of(removeAndGet(PaymentTestData.getMilHeaders(false, true), "Channel"), it.pagopa.swclient.mil.ErrorCode.CHANNEL_MUST_NOT_BE_NULL ), +// // Channel invalid regex +// Arguments.of(putAndGet(PaymentTestData.getMilHeaders(false, true), "Channel", "ATOM"), it.pagopa.swclient.mil.ErrorCode.CHANNEL_MUST_MATCH_REGEXP ), +// // TerminalId null +// Arguments.of(removeAndGet(PaymentTestData.getMilHeaders(false, true), "TerminalId"), it.pagopa.swclient.mil.ErrorCode.TERMINAL_ID_MUST_NOT_BE_NULL ), +// // TerminalId invalid regex +// Arguments.of(putAndGet(PaymentTestData.getMilHeaders(false, true), "TerminalId", "0aB9wXyZ0029DDDsno9"), it.pagopa.swclient.mil.ErrorCode.TERMINAL_ID_MUST_MATCH_REGEXP ), +// // Merchant invalid regex +// Arguments.of(putAndGet(PaymentTestData.getMilHeaders(true, true), "MerchantId", "0aB9wXyZ00_29DDDsno9"), it.pagopa.swclient.mil.ErrorCode.MERCHANT_ID_MUST_MATCH_REGEXP ), +// // Merchant null if pos +// Arguments.of(removeAndGet(PaymentTestData.getMilHeaders(true, true), "MerchantId"), it.pagopa.swclient.mil.ErrorCode.MERCHANT_ID_MUST_NOT_BE_NULL_FOR_POS ) +// ); +// } +// +// public static Stream provideQrCodeValidationErrorCases() { +// +// byte[] bytes = Base64.getUrlEncoder().withoutPadding().encode("https://www.test.com".getBytes(StandardCharsets.UTF_8)); +// String encodedWrongString = new String(bytes, StandardCharsets.UTF_8); +// +// bytes = Base64.getUrlEncoder().withoutPadding().encode(PaymentTestData.QR_CODE.concat("|001").getBytes(StandardCharsets.UTF_8)); +// String encodedInvalidQrCode = new String(bytes, StandardCharsets.UTF_8); +// +// return Stream.of( +// Arguments.of(encodedWrongString, ErrorCode.ENCODED_QRCODE_MUST_MATCH_REGEXP), +// Arguments.of(encodedInvalidQrCode, ErrorCode.QRCODE_FORMAT_IS_NOT_VALID) +// ); +// } +// +// public static Stream providePaTaxCodeNoticeNumberValidationErrorCases() { +// +// return Stream.of( +// Arguments.of("abcde", "100000000000000000", ErrorCode.PA_TAX_CODE_MUST_MATCH_REGEXP), +// Arguments.of("20000000000", "abcde", ErrorCode.NOTICE_NUMBER_MUST_MATCH_REGEXP) +// ); +// } +// +// public static Stream provideActivateRequestValidationErrorCases() { +// +// return Stream.of( +// Arguments.of(setAndGet(PaymentTestData.getActivatePaymentRequest(), "idempotencyKey", null), ErrorCode.ERROR_IDEMPOTENCY_KEY_MUST_NOT_BE_NULL), +// Arguments.of(setAndGet(PaymentTestData.getActivatePaymentRequest(), "idempotencyKey", "77777777777abcDEF1238"), ErrorCode.ERROR_IDEMPOTENCY_KEY_MUST_MATCH_REGEXP), +// Arguments.of(setAndGet(PaymentTestData.getActivatePaymentRequest(), "amount", null), ErrorCode.ERROR_AMOUNT_MUST_NOT_BE_NULL), +// Arguments.of(setAndGet(PaymentTestData.getActivatePaymentRequest(), "amount", 0L), ErrorCode.ERROR_AMOUNT_MUST_BE_GREATER_THAN), +// Arguments.of(setAndGet(PaymentTestData.getActivatePaymentRequest(), "amount", 199999999999L), ErrorCode.ERROR_AMOUNT_MUST_BE_LESS_THAN) +// ); +// } +// +// public static Stream providePreCloseRequestValidationErrorCases() { +// +// return Stream.of( +// Arguments.of(setAndGet(PaymentTestData.getPreCloseRequest(true, 1), "outcome", null), ErrorCode.ERROR_OUTCOME_MUST_NOT_BE_NULL), +// Arguments.of(setAndGet(PaymentTestData.getPreCloseRequest(true, 1), "outcome", "OK"), ErrorCode.ERROR_OUTCOME_MUST_MATCH_MATCH_REGEXP), +// Arguments.of(setAndGet(PaymentTestData.getPreCloseRequest(true, 1), "paymentTokens", null), ErrorCode.ERROR_PAYMENT_TOKEN_LIST_MUST_NOT_BE_NULL), +// Arguments.of(setAndGet(PaymentTestData.getPreCloseRequest(true, 1), "paymentTokens", List.of("100","101","102","103","104","105")), ErrorCode.ERROR_PAYMENT_TOKEN_LIST_MUST_HAVE_AT_MOST), +// Arguments.of(setAndGet(PaymentTestData.getPreCloseRequest(true, 1), "paymentTokens", List.of("123456789012345678901234567890123456")), ErrorCode.ERROR_PAYMENT_TOKEN_MATCH_MATCH_REGEXP), +// Arguments.of(setAndGet(PaymentTestData.getPreCloseRequest(true, 1), "transactionId", null), ErrorCode.ERROR_TRANSACTION_ID_MUST_NOT_BE_NULL), +// Arguments.of(setAndGet(PaymentTestData.getPreCloseRequest(true, 1), "transactionId", "abc"), ErrorCode.ERROR_TRANSACTION_ID_MUST_MATCH_REGEXP), +// Arguments.of(setAndGet(PaymentTestData.getPreCloseRequest(true, 1), "totalAmount", null), ErrorCode.ERROR_TOTAL_AMOUNT_MUST_NOT_BE_NULL), +// Arguments.of(setAndGet(PaymentTestData.getPreCloseRequest(true, 1), "totalAmount", 0L), ErrorCode.ERROR_TOTAL_AMOUNT_MUST_BE_GREATER_THAN), +// Arguments.of(setAndGet(PaymentTestData.getPreCloseRequest(true, 1), "totalAmount", 199999999999L), ErrorCode.ERROR_TOTAL_AMOUNT_MUST_BE_LESS_THAN), +// Arguments.of(setAndGet(PaymentTestData.getPreCloseRequest(true, 1), "totalAmount", 12345L), ErrorCode.ERROR_TOTAL_AMOUNT_MUST_MATCH_TOTAL_CACHED_VALUE), +// Arguments.of(setAndGet(PaymentTestData.getPreCloseRequest(true, 1), "fee", null), ErrorCode.ERROR_FEE_MUST_NOT_BE_NULL), +// Arguments.of(setAndGet(PaymentTestData.getPreCloseRequest(true, 1), "fee", 0L), ErrorCode.ERROR_FEE_MUST_BE_GREATER_THAN), +// Arguments.of(setAndGet(PaymentTestData.getPreCloseRequest(true, 1), "fee", 199999999999L), ErrorCode.ERROR_FEE_MUST_BE_LESS_THAN) +// ); +// } +// +// public static Stream provideCloseRequestValidationErrorCases() { +// +// return Stream.of( +// Arguments.of(setAndGet(PaymentTestData.getClosePaymentRequest(true), "outcome", null), ErrorCode.ERROR_OUTCOME_MUST_NOT_BE_NULL), +// Arguments.of(setAndGet(PaymentTestData.getClosePaymentRequest(true), "outcome", "O"), ErrorCode.ERROR_OUTCOME_MUST_MATCH_MATCH_REGEXP), +// Arguments.of(setAndGet(PaymentTestData.getClosePaymentRequest(true), "paymentMethod", null), ErrorCode.ERROR_PAYMENT_METHOD_MUST_NOT_BE_NULL), +// Arguments.of(setAndGet(PaymentTestData.getClosePaymentRequest(true), "paymentMethod", "INVALID_PAYMENT_METHOD"), ErrorCode.ERROR_PAYMENT_METHOD_MUST_MATCH_REGEXP), +// Arguments.of(setAndGet(PaymentTestData.getClosePaymentRequest(true), "paymentTimestamp", null), ErrorCode.ERROR_PAYMENT_TIMESTAMP_MUST_NOT_BE_NULL), +// Arguments.of(setAndGet(PaymentTestData.getClosePaymentRequest(true), "paymentTimestamp", "abcde"), ErrorCode.ERROR_PAYMENT_TIMESTAMP_MUST_MATCH_REGEXP) +// ); +// } +// +// public static Throwable getException(ExceptionType exceptionType) { +// return switch (exceptionType) { +// case TIMEOUT_EXCEPTION -> new TimeoutException(); +// case CLIENT_WEB_APPLICATION_EXCEPTION_400 -> new ClientWebApplicationException(400); +// case CLIENT_WEB_APPLICATION_EXCEPTION_404 -> new ClientWebApplicationException(404); +// case CLIENT_WEB_APPLICATION_EXCEPTION_500 -> new ClientWebApplicationException(500); +// case UNPARSABLE_EXCEPTION -> new ClientWebApplicationException(new JsonParseException(getJsonParser(), "")); +// case REDIS_TIMEOUT_EXCEPTION -> new SSLHandshakeException("Timeout"); +// case DB_TIMEOUT_EXCEPTION -> new TimeoutException(); // TODO generate correct exception +// case DB_DUPLICATED_KEY -> { +// WriteError writeError = new WriteError(11000, +// "'E11000 duplicate key error collection: mil.paymentTransactions index: _id_", +// new BsonDocument("", new BsonString(""))); +// ServerAddress serverAddress = new ServerAddress("127.0.0.1", 27017); +// yield new MongoWriteException(writeError, serverAddress); +// } +// }; +// } + + public static ClientWebApplicationException getExceptionWithEntity(int statusCode) { + return new ClientWebApplicationException(Response.status(statusCode).entity("").build()); + } + + private static JsonParser getJsonParser() { + JsonParser jsonParser = null; + try { + jsonParser = new JsonFactory().createParser("{}"); + } catch (IOException ignored) { + } + return jsonParser; + } + + private static Map removeAndGet(Map map, K key) { + map.remove(key); + return map; + } + private static Map putAndGet(Map map, K key, V value) { + map.put(key, value); + return map; + } + + private static T setAndGet(T object, String propertyName, V propertyValue) { + + try { + PropertyDescriptor desc = new PropertyDescriptor(propertyName, object.getClass()); + Method setter = desc.getWriteMethod(); + setter.invoke(object, propertyValue); + } + catch (IntrospectionException | IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + + return object; + } + + +} From 8156992c8800475023ca551f45914b66479bb553 Mon Sep 17 00:00:00 2001 From: "d.sabatini" Date: Mon, 29 May 2023 10:47:14 +0200 Subject: [PATCH 4/9] Added junit and integration tests for Kafka --- pom.xml | 14 ++ .../pagopa/swclient/mil/preset/ErrorCode.java | 43 +++-- .../mil/preset/bean/CreatePresetRequest.java | 6 +- .../mil/preset/bean/SubscribeRequest.java | 7 +- .../preset/resource/PresetTopicResource.java | 4 +- .../mil/preset/resource/PresetsResource.java | 27 +-- .../preset/resource/TerminalsResource.java | 38 +++-- src/main/resources/application.properties | 34 ++-- .../mil/preset/PresetTopicResourceTest.java | 4 +- ...urceTest.java => PresetsResourceTest.java} | 14 +- .../mil/preset/TerminalsResourceTest.java | 8 +- .../mil/preset/it/IntegrationTestProfile.java | 38 +++++ .../preset/it/PresetTopicResourceTestIT.java | 159 ++++++++++++++++-- .../resource/CustomRedpandaContainer.java | 37 ++++ ...er.java => KafkaInMemoryTestResource.java} | 4 +- .../preset/resource/MongoTestResource.java | 103 ++++++------ .../preset/resource/RedpandaTestResource.java | 103 ++++++++++++ .../resources/{ => it/mongo}/mongoInit.js | 0 18 files changed, 502 insertions(+), 141 deletions(-) rename src/test/java/it/pagopa/swclient/mil/preset/{PresetResourceTest.java => PresetsResourceTest.java} (98%) create mode 100644 src/test/java/it/pagopa/swclient/mil/preset/it/IntegrationTestProfile.java create mode 100644 src/test/java/it/pagopa/swclient/mil/preset/resource/CustomRedpandaContainer.java rename src/test/java/it/pagopa/swclient/mil/preset/resource/{KafkaTestResourceLifecycleManager.java => KafkaInMemoryTestResource.java} (77%) create mode 100644 src/test/java/it/pagopa/swclient/mil/preset/resource/RedpandaTestResource.java rename src/test/resources/{ => it/mongo}/mongoInit.js (100%) diff --git a/pom.xml b/pom.xml index a83ae56..23a15fd 100644 --- a/pom.xml +++ b/pom.xml @@ -82,6 +82,10 @@ io.quarkus quarkus-smallrye-reactive-messaging-kafka + + io.quarkus + quarkus-smallrye-jwt + io.smallrye.reactive smallrye-reactive-messaging-in-memory @@ -117,6 +121,16 @@ quarkus-jacoco test + + org.testcontainers + redpanda + test + + + org.awaitility + awaitility + test + diff --git a/src/main/java/it/pagopa/swclient/mil/preset/ErrorCode.java b/src/main/java/it/pagopa/swclient/mil/preset/ErrorCode.java index 49fd1b3..6b20f83 100644 --- a/src/main/java/it/pagopa/swclient/mil/preset/ErrorCode.java +++ b/src/main/java/it/pagopa/swclient/mil/preset/ErrorCode.java @@ -2,19 +2,21 @@ public final class ErrorCode { public static final String MODULE_ID = "00A"; - - public static final String PA_TAX_CODE_MUST_NOT_BE_NULL = MODULE_ID + "000001"; - public static final String PA_TAX_CODE_MUST_MATCH_REGEXP = MODULE_ID + "000002"; - - public static final String ERROR_COMMUNICATION_MONGO_DB = MODULE_ID + "000003"; - - public static final String SUBSCRIBER_ID_MUST_NOT_BE_NULL = MODULE_ID + "000004"; - public static final String SUBSCRIBER_ID_MUST_MATCH_REGEXP = MODULE_ID + "000005"; - - public static final String ERROR_SUBSCRIBER_NOT_FOUND = MODULE_ID + "000006"; - - public static final String ERROR_STORING_TERMINAL_IN_DB = MODULE_ID + "000007"; - public static final String ERROR_CONFLICT_TERMINAL_IN_DB = MODULE_ID + "000008"; + + + // validation errors + public static final String SUBSCRIBE_REQUEST_MUST_NOT_BE_EMPTY = MODULE_ID + "000001"; + + public static final String PA_TAX_CODE_MUST_NOT_BE_NULL = MODULE_ID + "000002"; + public static final String PA_TAX_CODE_MUST_MATCH_REGEXP = MODULE_ID + "000003"; + + public static final String LABEL_MUST_NOT_BE_NULL = MODULE_ID + "000004"; + public static final String LABEL_MUST_MATCH_REGEXP = MODULE_ID + "000005"; + + public static final String CREATE_PRESET_REQUEST_MUST_NOT_BE_EMPTY = MODULE_ID + "000006"; + + public static final String SUBSCRIBER_ID_MUST_NOT_BE_NULL = MODULE_ID + "000007"; + public static final String SUBSCRIBER_ID_MUST_MATCH_REGEXP = MODULE_ID + "000008"; public static final String OPERATION_TYPE_MUST_NOT_BE_NULL = MODULE_ID + "000009"; public static final String OPERATION_TYPE_MUST_MATCH_REGEXP = MODULE_ID + "00000A"; @@ -24,9 +26,18 @@ public final class ErrorCode { public static final String NOTICE_NUMBER_MUST_NOT_BE_NULL = MODULE_ID + "00000D"; public static final String NOTICE_NUMBER_MUST_MATCH_REGEXP = MODULE_ID + "00000E"; - - public static final String ERROR_PRESET_OPERATION_NOT_FOUND = MODULE_ID + "00000F"; - + + // business logic errors + public static final String SUBSCRIBER_NOT_FOUND = MODULE_ID + "00000F"; + public static final String SUBSCRIBER_ALREADY_EXISTS = MODULE_ID + "00000F"; + public static final String PRESET_OPERATION_NOT_FOUND = MODULE_ID + "000010"; + + + // integration errors + public static final String ERROR_WRITING_DATA_IN_DB = MODULE_ID + "000011"; + public static final String ERROR_READING_DATA_FROM_DB = MODULE_ID + "000012"; + + private ErrorCode() { } diff --git a/src/main/java/it/pagopa/swclient/mil/preset/bean/CreatePresetRequest.java b/src/main/java/it/pagopa/swclient/mil/preset/bean/CreatePresetRequest.java index 7c902cf..7a4c26a 100644 --- a/src/main/java/it/pagopa/swclient/mil/preset/bean/CreatePresetRequest.java +++ b/src/main/java/it/pagopa/swclient/mil/preset/bean/CreatePresetRequest.java @@ -12,7 +12,7 @@ public class CreatePresetRequest { /* * Operation of payment of a notice */ - @NotNull(message = "[" + ErrorCode.PA_TAX_CODE_MUST_NOT_BE_NULL + "] operationType must not be null") + @NotNull(message = "[" + ErrorCode.OPERATION_TYPE_MUST_NOT_BE_NULL + "] operationType must not be null") @Pattern(regexp = "PAYMENT_NOTICE", message = "[" + ErrorCode.OPERATION_TYPE_MUST_MATCH_REGEXP + "] operationType must match \"{regexp}\"") private String operationType; @@ -43,8 +43,8 @@ public class CreatePresetRequest { /* * Notice number */ - @NotNull(message = "[" + ErrorCode.SUBSCRIBER_ID_MUST_NOT_BE_NULL + "] noticeNumber must not be null") - @Pattern(regexp = "^[0-9]{18}$", message = "[" + ErrorCode.SUBSCRIBER_ID_MUST_MATCH_REGEXP + "] noticeNumber must match \"{regexp}\"") + @NotNull(message = "[" + ErrorCode.NOTICE_NUMBER_MUST_NOT_BE_NULL + "] noticeNumber must not be null") + @Pattern(regexp = "^[0-9]{18}$", message = "[" + ErrorCode.NOTICE_NUMBER_MUST_MATCH_REGEXP + "] noticeNumber must match \"{regexp}\"") private String noticeNumber; /** diff --git a/src/main/java/it/pagopa/swclient/mil/preset/bean/SubscribeRequest.java b/src/main/java/it/pagopa/swclient/mil/preset/bean/SubscribeRequest.java index ef5b44e..5c41cc7 100644 --- a/src/main/java/it/pagopa/swclient/mil/preset/bean/SubscribeRequest.java +++ b/src/main/java/it/pagopa/swclient/mil/preset/bean/SubscribeRequest.java @@ -4,19 +4,24 @@ package it.pagopa.swclient.mil.preset.bean; import it.pagopa.swclient.mil.preset.ErrorCode; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Null; import jakarta.validation.constraints.Pattern; public class SubscribeRequest { + /* * Tax code of the creditor company */ + @NotNull(message = "[" + ErrorCode.PA_TAX_CODE_MUST_NOT_BE_NULL + "] paTaxCode must not be null") @Pattern(regexp = "^[0-9]{11}$", message = "[" + ErrorCode.PA_TAX_CODE_MUST_MATCH_REGEXP + "] paTaxCode must match \"{regexp}\"") private String paTaxCode; /* * Mnemonic terminal label */ - @Pattern(regexp = "^[\\u0001-\\uD7FF\\uE000-\\uFFFD\\u10000-\\u10FFFF]{1,256}$") + @NotNull(message = "[" + ErrorCode.LABEL_MUST_NOT_BE_NULL + "] label must not be null") + @Pattern(regexp = "^[\\u0001-\\uD7FF\\uE000-\\uFFFD\\u1000-\\u10FF]{1,256}$", message = "[" + ErrorCode.LABEL_MUST_MATCH_REGEXP + "] paTaxCode must match \"{regexp}\"") private String label; /** diff --git a/src/main/java/it/pagopa/swclient/mil/preset/resource/PresetTopicResource.java b/src/main/java/it/pagopa/swclient/mil/preset/resource/PresetTopicResource.java index 4c28518..ffdebaf 100644 --- a/src/main/java/it/pagopa/swclient/mil/preset/resource/PresetTopicResource.java +++ b/src/main/java/it/pagopa/swclient/mil/preset/resource/PresetTopicResource.java @@ -82,9 +82,9 @@ private Uni findPresetsOperation(PaymentTransaction paymentTransac private Uni updatePreset(PaymentTransaction inputPaymentTransaction, PresetEntity presetEntity) { Log.debugf("Updating Preset"); - if (!PaymentTransactionStatus.PRE_CLOSE.name().equals(inputPaymentTransaction.getStatus())) { + //if (!PaymentTransactionStatus.PRE_CLOSE.name().equals(inputPaymentTransaction.getStatus())) { presetEntity.presetOperation.setStatus(PresetStatus.EXECUTED.name()); - } + //} presetEntity.presetOperation.setStatusTimestamp(DateUtils.getCurrentTimestamp()); presetEntity.presetOperation.setStatusDetails(inputPaymentTransaction); diff --git a/src/main/java/it/pagopa/swclient/mil/preset/resource/PresetsResource.java b/src/main/java/it/pagopa/swclient/mil/preset/resource/PresetsResource.java index 16d75f6..2f233b9 100644 --- a/src/main/java/it/pagopa/swclient/mil/preset/resource/PresetsResource.java +++ b/src/main/java/it/pagopa/swclient/mil/preset/resource/PresetsResource.java @@ -22,6 +22,7 @@ import it.pagopa.swclient.mil.preset.utils.DateUtils; import jakarta.inject.Inject; import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import jakarta.ws.rs.BeanParam; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.GET; @@ -69,17 +70,21 @@ public class PresetsResource { @POST @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - public Uni createPreset(@Valid @BeanParam InstitutionPortalHeaders portalHeaders, @Valid CreatePresetRequest createPresetRequest) { + public Uni createPreset(@Valid @BeanParam InstitutionPortalHeaders portalHeaders, + + @Valid + @NotNull(message = "[" + ErrorCode.CREATE_PRESET_REQUEST_MUST_NOT_BE_EMPTY + "] request must not be empty") + CreatePresetRequest createPresetRequest) { Log.debugf("createPreset - Input parameters: %s,: %s", portalHeaders, createPresetRequest); return findSubscriber(createPresetRequest.getPaTaxCode(), createPresetRequest.getSubscriberId()) .chain(subscriberEntity -> { if (subscriberEntity == null) { - Log.errorf("[%s] No subscriber found on DB", ErrorCode.ERROR_SUBSCRIBER_NOT_FOUND); + Log.errorf("[%s] No subscriber found on DB", ErrorCode.SUBSCRIBER_NOT_FOUND); return Uni.createFrom().item( Response.status(Status.BAD_REQUEST) - .entity(new Errors(List.of(ErrorCode.ERROR_SUBSCRIBER_NOT_FOUND))) + .entity(new Errors(List.of(ErrorCode.SUBSCRIBER_NOT_FOUND))) .build()); } else { // update last usage timestamp @@ -158,10 +163,10 @@ private Uni findSubscriber(String paTaxCode, String subscriber return subscriberRepository.list(SUBSCRIBER_FILTER, Parameters.with("paTaxCode", paTaxCode).and("subscriberId", subscriberId).map()) .onFailure().transform(err -> { - Log.errorf(err, "[%s] Error while retrieving data from DB", ErrorCode.ERROR_COMMUNICATION_MONGO_DB); + Log.errorf(err, "[%s] Error while retrieving data from DB", ErrorCode.ERROR_READING_DATA_FROM_DB); return new InternalServerErrorException( Response.status(Status.INTERNAL_SERVER_ERROR) - .entity(new Errors(List.of(ErrorCode.ERROR_COMMUNICATION_MONGO_DB))) + .entity(new Errors(List.of(ErrorCode.ERROR_READING_DATA_FROM_DB))) .build()); }) .map(entityList -> entityList.isEmpty() ? null : entityList.get(0)); @@ -178,10 +183,10 @@ private Uni> findPresetOperations(String paTaxCode, String return presetRepository.list(PRESET_FILTER, Parameters.with("paTaxCode", paTaxCode).and("subscriberId", subscriberId).map()) .onFailure().transform(err -> { - Log.errorf(err, "[%s] Error while retrieving data from DB", ErrorCode.ERROR_COMMUNICATION_MONGO_DB); + Log.errorf(err, "[%s] Error while retrieving data from DB", ErrorCode.ERROR_READING_DATA_FROM_DB); return new InternalServerErrorException( Response.status(Status.INTERNAL_SERVER_ERROR) - .entity(new Errors(List.of(ErrorCode.ERROR_COMMUNICATION_MONGO_DB))) + .entity(new Errors(List.of(ErrorCode.ERROR_READING_DATA_FROM_DB))) .build()); }) .map(entities -> entities.stream().map(entity -> entity.presetOperation).toList()); @@ -205,10 +210,10 @@ private Uni findLatestPresetOperation(String paTaxCode, String ) .firstResult() .onFailure().transform(err -> { - Log.errorf(err, "[%s] Error while retrieving data from DB", ErrorCode.ERROR_COMMUNICATION_MONGO_DB); + Log.errorf(err, "[%s] Error while retrieving data from DB", ErrorCode.ERROR_READING_DATA_FROM_DB); return new InternalServerErrorException( Response.status(Status.INTERNAL_SERVER_ERROR) - .entity(new Errors(List.of(ErrorCode.ERROR_COMMUNICATION_MONGO_DB))) + .entity(new Errors(List.of(ErrorCode.ERROR_READING_DATA_FROM_DB))) .build()); } ) @@ -244,10 +249,10 @@ private Uni persistPreset(Subscriber subscriber, return presetRepository.persist(entity) .onFailure().transform(f -> { - Log.errorf(f, "[%s] Error while storing data in the DB", ErrorCode.ERROR_STORING_TERMINAL_IN_DB); + Log.errorf(f, "[%s] Error while storing data in the DB", ErrorCode.ERROR_WRITING_DATA_IN_DB); return new InternalServerErrorException( Response.status(Status.INTERNAL_SERVER_ERROR) - .entity(new Errors(List.of(ErrorCode.ERROR_STORING_TERMINAL_IN_DB))) + .entity(new Errors(List.of(ErrorCode.ERROR_WRITING_DATA_IN_DB))) .build()); }); diff --git a/src/main/java/it/pagopa/swclient/mil/preset/resource/TerminalsResource.java b/src/main/java/it/pagopa/swclient/mil/preset/resource/TerminalsResource.java index 8de5654..0e64c4e 100644 --- a/src/main/java/it/pagopa/swclient/mil/preset/resource/TerminalsResource.java +++ b/src/main/java/it/pagopa/swclient/mil/preset/resource/TerminalsResource.java @@ -15,6 +15,7 @@ import it.pagopa.swclient.mil.preset.dao.SubscriberEntity; import it.pagopa.swclient.mil.preset.dao.SubscriberRepository; import it.pagopa.swclient.mil.preset.utils.DateUtils; +import jakarta.annotation.security.RolesAllowed; import jakarta.inject.Inject; import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; @@ -28,11 +29,14 @@ import jakarta.ws.rs.Path; import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.Response.Status; +import jakarta.ws.rs.core.SecurityContext; import org.apache.commons.lang3.RandomStringUtils; import org.eclipse.microprofile.config.inject.ConfigProperty; +import org.eclipse.microprofile.jwt.JsonWebToken; import java.net.URI; import java.security.SecureRandom; @@ -45,6 +49,9 @@ public class TerminalsResource { @Inject SubscriberRepository subscriberRepository; + @Inject + JsonWebToken jwt; + /** * The base URL for the location header returned by the subscribe API (i.e. the API management base URL) */ @@ -59,22 +66,25 @@ public class TerminalsResource { */ @GET @Path("/{paTaxCode}") + @RolesAllowed({ "InstitutionPortal" }) @Produces(MediaType.APPLICATION_JSON) public Uni getSubscribers(@Valid @BeanParam InstitutionPortalHeaders portalHeaders, @PathParam(value = "paTaxCode") @NotNull(message = "[" + ErrorCode.PA_TAX_CODE_MUST_NOT_BE_NULL + "] paTaxCode must not be null") @Pattern(regexp = "^[0-9]{11}$", message = "[" + ErrorCode.PA_TAX_CODE_MUST_MATCH_REGEXP + "] paTaxCode must match \"{regexp}\"") - String paTaxCode) { + String paTaxCode, - Log.debugf("getSubscribers - Input parameters: %s, taxCode: %s", portalHeaders, paTaxCode); + @Context SecurityContext ctx) { + + Log.debugf("getSubscribers - Input parameters: %s, taxCode: %s, %s", portalHeaders, paTaxCode, ctx); return subscriberRepository.list("subscriber.paTaxCode", paTaxCode) .onFailure().transform(err -> { - Log.errorf(err, "[%s] Error while retrieving data from DB", ErrorCode.ERROR_COMMUNICATION_MONGO_DB); + Log.errorf(err, "[%s] Error while retrieving data from DB", ErrorCode.ERROR_READING_DATA_FROM_DB); return new InternalServerErrorException(Response .status(Status.INTERNAL_SERVER_ERROR) - .entity(new Errors(List.of(ErrorCode.ERROR_COMMUNICATION_MONGO_DB))) + .entity(new Errors(List.of(ErrorCode.ERROR_READING_DATA_FROM_DB))) .build()); }) .map(subs -> { @@ -109,10 +119,10 @@ public Uni unsubscribe(@Valid @BeanParam UnsubscribeHeaders headers, S .map() ) .onFailure().transform(err -> { - Log.debugf("[%s] Error while deleting data from DB", ErrorCode.ERROR_COMMUNICATION_MONGO_DB); + Log.debugf("[%s] Error while deleting data from DB", ErrorCode.ERROR_WRITING_DATA_IN_DB); return new InternalServerErrorException(Response .status(Status.INTERNAL_SERVER_ERROR) - .entity(new Errors(List.of(ErrorCode.ERROR_COMMUNICATION_MONGO_DB))) + .entity(new Errors(List.of(ErrorCode.ERROR_WRITING_DATA_IN_DB))) .build()); }) .map(deleted -> { @@ -139,7 +149,11 @@ public Uni unsubscribe(@Valid @BeanParam UnsubscribeHeaders headers, S @POST @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - public Uni subscribe(@Valid @BeanParam CommonHeader commonHeader, @Valid SubscribeRequest subscribeRequest) { + public Uni subscribe(@Valid @BeanParam CommonHeader commonHeader, + + @Valid + @NotNull(message = "[" + ErrorCode.SUBSCRIBE_REQUEST_MUST_NOT_BE_EMPTY + "] request must not be empty") + SubscribeRequest subscribeRequest) { Log.debugf("subscribe - Input parameters: %s, %s", commonHeader, subscribeRequest); @@ -153,9 +167,9 @@ public Uni subscribe(@Valid @BeanParam CommonHeader commonHeader, @Val SubscriberEntity entity = buildSubscriberEntity(subscribeRequest, commonHeader, subscriberId); return subscriberRepository.persist(entity) .onFailure().transform( f -> { - Log.errorf(f, "[%s] Error while storing data in the DB", ErrorCode.ERROR_STORING_TERMINAL_IN_DB, subscriberId); + Log.errorf(f, "[%s] Error while storing data in the DB", ErrorCode.ERROR_WRITING_DATA_IN_DB, subscriberId); return new InternalServerErrorException(Response.status(Status.INTERNAL_SERVER_ERROR) - .entity(new Errors(List.of(ErrorCode.ERROR_STORING_TERMINAL_IN_DB))) + .entity(new Errors(List.of(ErrorCode.ERROR_WRITING_DATA_IN_DB))) .build()); }) .map(m -> { @@ -166,7 +180,7 @@ public Uni subscribe(@Valid @BeanParam CommonHeader commonHeader, @Val } else { final URI locationURI = buildLocationPath(subscribeRequest.getPaTaxCode(), subscriber.getSubscriberId()); - Log.debugf("Terminal already subscribed", ErrorCode.ERROR_CONFLICT_TERMINAL_IN_DB, subscriber.getSubscriberId()); + Log.debugf("Terminal already subscribed", ErrorCode.SUBSCRIBER_ALREADY_EXISTS, subscriber.getSubscriberId()); return Uni.createFrom().item(Response.status(Status.CONFLICT).location(locationURI).build()); } }); @@ -196,10 +210,10 @@ private Uni findSubscriber(CommonHeader commonHeader, String paTaxCo .and("paTaxCode", paTaxCode) .map()) .onFailure().transform(err -> { - Log.errorf(err, "[%s] Error while retrieving data from DB", ErrorCode.ERROR_COMMUNICATION_MONGO_DB); + Log.errorf(err, "[%s] Error while retrieving data from DB", ErrorCode.ERROR_READING_DATA_FROM_DB); return new InternalServerErrorException(Response .status(Status.INTERNAL_SERVER_ERROR) - .entity(new Errors(List.of(ErrorCode.ERROR_COMMUNICATION_MONGO_DB))) + .entity(new Errors(List.of(ErrorCode.ERROR_READING_DATA_FROM_DB))) .build()); } ) diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 0704fc0..1f9383c 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -27,7 +27,7 @@ quarkus.log.min-level=DEBUG # # mongo-connect-timeout = 5s # mongo-read-timeout = 10s -# mongo-server-selecion-timeout = 5s +# mongo-server-selection-timeout = 5s # ------------------------------------------------------------------------------ %dev.quarkus.mongodb.connect-timeout=5 @@ -42,20 +42,25 @@ quarkus.log.min-level=DEBUG %prod.quarkus.mongodb.connect-timeout=${mongo-connect-timeout} %prod.quarkus.mongodb.read-timeout=${mongo-read-timeout} -%prod.quarkus.mongodb.server-selection-timeout=${mongo-server-selecion-timeout} +%prod.quarkus.mongodb.server-selection-timeout=${mongo-server-selection-timeout} %prod.quarkus.mongodb.connection-string=${mongo-connection-string-1},${mongo-connection-string-2} +# ------------------------------------------------------------------------------ +# Kafka / Azure Event Bus configuration +# +# mongo-connect-timeout = 5s +# mongo-read-timeout = 10s +# mongo-server-selection-timeout = 5s +# ------------------------------------------------------------------------------ -#%dev.kafka.bootstrap.servers=kafka:9092 -#%prod.kafka.bootstrap.servers=${kafka-bootsrtap-server} -#%test.kafka.bootstrap.servers=kafka:9092 -#mp.messaging.incoming.prices.connector=smallrye-kafka +%dev.kafka.bootstrap.servers=localhost:19092 +%test.kafka.bootstrap.servers=kafka:9092 +%prod.kafka.bootstrap.servers=${kafka-bootstrap-server} -quarkus.kafka.devservices.enabled=false +mp.messaging.incoming.presets.connector=smallrye-kafka +mp.messaging.incoming.presets.group.id=preset-processor -#%prod.kafka.bootstrap.servers=kafka:9092 -#mp.messaging.outgoing.prices-out.connector=smallrye-kafka -#mp.messaging.outgoing.prices-out.topic=prestes +quarkus.kafka.devservices.enabled=false #quarkus.reactive-messaging.auto-connector-attachment=false @@ -71,6 +76,15 @@ quarkus.kafka.devservices.enabled=false #mp.messaging.incoming.presets.topic=presets #mp.messaging.incoming.presets.value.deserializer=it.pagopa.swclient.mil.preset.utils.PresetDeserializer +# ------------------------------------------------------------------------------ +# JWT RBAC configurations +# ------------------------------------------------------------------------------ + +%dev.mp.jwt.verify.publickey.location=http://localhost:8088/realms/mil-test/protocol/openid-connect/certs +%test.mp.jwt.verify.publickey.location=http://localhost:8088/realms/mil-test/protocol/openid-connect/certs +%prod.mp.jwt.verify.publickey.location=${jwt-publickey-location} + + # ------------------------------------------------------------------------------ # Service configurations # ------------------------------------------------------------------------------ diff --git a/src/test/java/it/pagopa/swclient/mil/preset/PresetTopicResourceTest.java b/src/test/java/it/pagopa/swclient/mil/preset/PresetTopicResourceTest.java index 96406b2..4231f7c 100644 --- a/src/test/java/it/pagopa/swclient/mil/preset/PresetTopicResourceTest.java +++ b/src/test/java/it/pagopa/swclient/mil/preset/PresetTopicResourceTest.java @@ -11,7 +11,7 @@ import it.pagopa.swclient.mil.preset.bean.PresetOperation; import it.pagopa.swclient.mil.preset.dao.PresetEntity; import it.pagopa.swclient.mil.preset.dao.PresetRepository; -import it.pagopa.swclient.mil.preset.resource.KafkaTestResourceLifecycleManager; +import it.pagopa.swclient.mil.preset.resource.KafkaInMemoryTestResource; import it.pagopa.swclient.mil.preset.util.PresetTestData; import it.pagopa.swclient.mil.preset.util.TestUtils; import jakarta.enterprise.inject.Any; @@ -29,7 +29,7 @@ @QuarkusTest -@QuarkusTestResource(KafkaTestResourceLifecycleManager.class) +@QuarkusTestResource(KafkaInMemoryTestResource.class) class PresetTopicResourceTest { static final Logger logger = LoggerFactory.getLogger(PresetTopicResourceTest.class); diff --git a/src/test/java/it/pagopa/swclient/mil/preset/PresetResourceTest.java b/src/test/java/it/pagopa/swclient/mil/preset/PresetsResourceTest.java similarity index 98% rename from src/test/java/it/pagopa/swclient/mil/preset/PresetResourceTest.java rename to src/test/java/it/pagopa/swclient/mil/preset/PresetsResourceTest.java index 6de82b5..1015055 100644 --- a/src/test/java/it/pagopa/swclient/mil/preset/PresetResourceTest.java +++ b/src/test/java/it/pagopa/swclient/mil/preset/PresetsResourceTest.java @@ -41,9 +41,9 @@ @QuarkusTest @TestHTTPEndpoint(PresetsResource.class) @TestInstance(TestInstance.Lifecycle.PER_CLASS) -class PresetResourceTest { +class PresetsResourceTest { - static final Logger logger = LoggerFactory.getLogger(PresetResourceTest.class); + static final Logger logger = LoggerFactory.getLogger(PresetsResourceTest.class); final static String SESSION_ID = "a6a666e6-97da-4848-b568-99fedccb642c"; final static String API_VERSION = "1.0.0-alpha-a.b-c-somethinglong+build.1-aef.1-its-okay"; @@ -273,7 +273,7 @@ void createPreset_400_subscriberNotFound() { Assertions.assertEquals(400, response.statusCode()); Assertions.assertNull(response.getHeader("Location")); - Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_SUBSCRIBER_NOT_FOUND)); + Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.SUBSCRIBER_NOT_FOUND)); } @Test @@ -301,7 +301,7 @@ void createPreset_500_dbError_listSubscribers() { .response(); Assertions.assertEquals(500, response.statusCode()); - Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_COMMUNICATION_MONGO_DB)); + Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_READING_DATA_FROM_DB)); Assertions.assertNull(response.getHeader("Location")); } @@ -339,7 +339,7 @@ void createPreset_500_dbError_persistPreset() { .response(); Assertions.assertEquals(500, response.statusCode()); - Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_STORING_TERMINAL_IN_DB)); + Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_WRITING_DATA_IN_DB)); Assertions.assertNull(response.getHeader("Location")); } @@ -493,7 +493,7 @@ void getPresets_500_dbError_listPresets() { .response(); Assertions.assertEquals(500, response.statusCode()); - Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_COMMUNICATION_MONGO_DB)); + Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_READING_DATA_FROM_DB)); Assertions.assertNull(response.getHeader("Location")); } @@ -595,7 +595,7 @@ void getLastPresetsOperation_500_dbError_findPreset() { .response(); Assertions.assertEquals(500, response.statusCode()); - Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_COMMUNICATION_MONGO_DB)); + Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_READING_DATA_FROM_DB)); } } diff --git a/src/test/java/it/pagopa/swclient/mil/preset/TerminalsResourceTest.java b/src/test/java/it/pagopa/swclient/mil/preset/TerminalsResourceTest.java index d6059ab..a70093c 100644 --- a/src/test/java/it/pagopa/swclient/mil/preset/TerminalsResourceTest.java +++ b/src/test/java/it/pagopa/swclient/mil/preset/TerminalsResourceTest.java @@ -172,7 +172,7 @@ void getSubscribers_500_dbError_listSubscribers() { .response(); Assertions.assertEquals(500, response.statusCode()); - Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_COMMUNICATION_MONGO_DB)); + Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_READING_DATA_FROM_DB)); Assertions.assertNull(response.jsonPath().getJsonObject("subscribers")); } @@ -258,7 +258,7 @@ void unsubscribe_500_dbError_deleteSubscriber() { .response(); Assertions.assertEquals(500, response.statusCode()); - Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_COMMUNICATION_MONGO_DB)); + Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_WRITING_DATA_IN_DB)); } /* **** subscribe **** */ @@ -378,7 +378,7 @@ void subscribe_500_dbError_listSubscribers() { .response(); Assertions.assertEquals(500, response.statusCode()); - Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_COMMUNICATION_MONGO_DB)); + Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_READING_DATA_FROM_DB)); } @@ -409,7 +409,7 @@ void subscribe_500_dbError_persistSubscriber() { .response(); Assertions.assertEquals(500, response.statusCode()); - Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_STORING_TERMINAL_IN_DB)); + Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_WRITING_DATA_IN_DB)); } } diff --git a/src/test/java/it/pagopa/swclient/mil/preset/it/IntegrationTestProfile.java b/src/test/java/it/pagopa/swclient/mil/preset/it/IntegrationTestProfile.java new file mode 100644 index 0000000..95c915b --- /dev/null +++ b/src/test/java/it/pagopa/swclient/mil/preset/it/IntegrationTestProfile.java @@ -0,0 +1,38 @@ +package it.pagopa.swclient.mil.preset.it; + +import com.google.common.collect.ImmutableList; +import io.quarkus.test.junit.QuarkusTestProfile; +import it.pagopa.swclient.mil.preset.resource.MongoTestResource; +import it.pagopa.swclient.mil.preset.resource.RedpandaTestResource; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class IntegrationTestProfile implements QuarkusTestProfile { + + @Override + public Map getConfigOverrides() { + + Map configOverrides = new HashMap<>(); + + configOverrides.put("preset.quarkus-log-level", "DEBUG"); + configOverrides.put("preset.app-log-level", "DEBUG"); + + return configOverrides; + } + + @Override + public List testResources() { + return ImmutableList.of( + new TestResourceEntry(MongoTestResource.class), + new TestResourceEntry(RedpandaTestResource.class) + ); + } + + @Override + public boolean disableGlobalTestResources() { + return true; + } + +} diff --git a/src/test/java/it/pagopa/swclient/mil/preset/it/PresetTopicResourceTestIT.java b/src/test/java/it/pagopa/swclient/mil/preset/it/PresetTopicResourceTestIT.java index bfaa801..1fac7bb 100644 --- a/src/test/java/it/pagopa/swclient/mil/preset/it/PresetTopicResourceTestIT.java +++ b/src/test/java/it/pagopa/swclient/mil/preset/it/PresetTopicResourceTestIT.java @@ -1,32 +1,156 @@ package it.pagopa.swclient.mil.preset.it; +import com.mongodb.MongoClientSettings; +import com.mongodb.client.FindIterable; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoCursor; +import com.mongodb.client.model.Filters; +import io.quarkus.kafka.client.serialization.ObjectMapperSerializer; +import io.quarkus.test.common.DevServicesContext; import io.quarkus.test.junit.QuarkusIntegrationTest; +import io.quarkus.test.junit.TestProfile; +import it.pagopa.swclient.mil.preset.PresetStatus; import it.pagopa.swclient.mil.preset.bean.Notice; import it.pagopa.swclient.mil.preset.bean.PaymentTransaction; +import it.pagopa.swclient.mil.preset.bean.PaymentTransactionStatus; import it.pagopa.swclient.mil.preset.bean.Preset; +import it.pagopa.swclient.mil.preset.bean.PresetOperation; +import it.pagopa.swclient.mil.preset.dao.PresetEntity; +import it.pagopa.swclient.mil.preset.util.PresetTestData; +import it.pagopa.swclient.mil.preset.utils.DateUtils; +import org.apache.kafka.clients.producer.KafkaProducer; +import org.apache.kafka.clients.producer.ProducerRecord; +import org.apache.kafka.common.serialization.StringSerializer; +import org.bson.codecs.configuration.CodecRegistries; +import org.bson.codecs.configuration.CodecRegistry; +import org.bson.codecs.pojo.PojoCodecProvider; +import org.bson.conversions.Bson; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testcontainers.shaded.org.awaitility.Awaitility; import java.util.ArrayList; import java.util.List; +import java.util.Properties; +import java.util.UUID; @QuarkusIntegrationTest -//@QuarkusTestResource(value=MongoTestResource.class,restrictToAnnotatedClass = true) -//@TestHTTPEndpoint(PresetsResource.class) +@TestProfile(IntegrationTestProfile.class) @TestInstance(TestInstance.Lifecycle.PER_CLASS) -//@QuarkusTestResource(KafkaCompanionResource.class) -class PresetTopicResourceTestIT { -// @InjectKafkaCompanion - // KafkaCompanion companion; - -// @Test -// void preset_200() { -// -// ProducerTask producerTask = companion.produce(byte[].class).usingGenerator(i -> new ProducerRecord<>("presets",SerializationUtils.serialize(getPaymentTransaction())),1); -// long count = producerTask.awaitCompletion().count(); -// System.out.println(">[" + count + "]<"); -// System.out.println(">>>>a"); -// } - +class PresetTopicResourceTestIT implements DevServicesContext.ContextAware { + + static final Logger logger = LoggerFactory.getLogger(PresetTopicResourceTestIT.class); + + DevServicesContext devServicesContext; + + KafkaProducer paymentTransactionProducer; + + CodecRegistry pojoCodecRegistry; + + MongoClient mongoClient; + + @Override + public void setIntegrationTestContext(DevServicesContext devServicesContext) { + this.devServicesContext = devServicesContext; + } + + @BeforeAll + void createTestData() { + + // initialize mongo client + pojoCodecRegistry = CodecRegistries.fromRegistries(MongoClientSettings.getDefaultCodecRegistry(), + CodecRegistries.fromProviders(PojoCodecProvider.builder().automatic(true).build())); + + String mongoExposedPort = devServicesContext.devServicesProperties().get("test.mongo.exposed-port"); + mongoClient = MongoClients.create("mongodb://127.0.0.1:" + mongoExposedPort); + + // initialize kafka producer + Properties kafkaConfig = new Properties(); + kafkaConfig.put("bootstrap.servers", devServicesContext.devServicesProperties().get("test.kafka.bootstrap-server")); + kafkaConfig.put("linger.ms", 1); + + paymentTransactionProducer = new KafkaProducer<>(kafkaConfig, new StringSerializer(), new ObjectMapperSerializer<>()); + } + + @Test + void consume_close_ok() { + + String presetId = UUID.randomUUID().toString(); + + PaymentTransaction paymentTransaction = PresetTestData.getPaymentTransaction( + PaymentTransactionStatus.PENDING, + PresetTestData.getMilHeaders(true, true), + PresetTestData.getPreset(presetId, "x46tr3"), + 1); + + PresetEntity presetEntity = PresetTestData.getPresetEntity(presetId, "x46tr3"); + + mongoClient.getDatabase("mil") + .getCollection("presets", PresetEntity.class) + .withCodecRegistry(pojoCodecRegistry) + .insertOne(presetEntity); + + String currentTimestamp = DateUtils.getCurrentTimestamp(); + + paymentTransactionProducer.send(new ProducerRecord<>("presets", paymentTransaction)); + + Awaitility.await().until(() -> { + PresetOperation presetOperation = getPresetOperation(presetId); + return presetOperation.getStatusTimestamp().compareTo(currentTimestamp) > 0; + }); + + checkDatabaseData(presetId, PresetStatus.EXECUTED, paymentTransaction); + + } + + private PresetOperation getPresetOperation(String presetId) { + + MongoCollection collection = mongoClient.getDatabase("mil") + .getCollection("presets", PresetEntity.class) + .withCodecRegistry(pojoCodecRegistry); + + Bson filter = Filters.in("_id", presetId); + FindIterable documents = collection.find(filter); + + try (MongoCursor iterator = documents.iterator()) { + Assertions.assertTrue(iterator.hasNext()); + PresetEntity presetEntity = iterator.next(); + logger.info("Found preset operation entry on DB: {}", presetEntity.presetOperation); + return presetEntity.presetOperation; + } + } + + private void checkDatabaseData(String presetId, PresetStatus transactionStatus, PaymentTransaction paymentTransaction) { + + PresetOperation presetOperation = getPresetOperation(presetId); + + Assertions.assertEquals(PresetStatus.EXECUTED.name(), presetOperation.getStatus()); + + } + + @AfterAll + void tearDown() { + + try { + mongoClient.close(); + } catch (Exception e){ + logger.error("Error while closing mongo client", e); + } + try { + paymentTransactionProducer.close(); + } catch (Exception e){ + logger.error("Error while closing kafka producer", e); + } + + } + private PaymentTransaction getPaymentTransaction() { PaymentTransaction transaction = new PaymentTransaction(); transaction.setTransactionId("517a4216840E461fB011036A0fd134E1"); @@ -63,5 +187,6 @@ private PaymentTransaction getPaymentTransaction() { transaction.setCloseTimestamp("2023-05-21T10:29:34.526"); return transaction; } - + + } diff --git a/src/test/java/it/pagopa/swclient/mil/preset/resource/CustomRedpandaContainer.java b/src/test/java/it/pagopa/swclient/mil/preset/resource/CustomRedpandaContainer.java new file mode 100644 index 0000000..5710f23 --- /dev/null +++ b/src/test/java/it/pagopa/swclient/mil/preset/resource/CustomRedpandaContainer.java @@ -0,0 +1,37 @@ +package it.pagopa.swclient.mil.preset.resource; + +import com.github.dockerjava.api.command.InspectContainerResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testcontainers.images.builder.Transferable; +import org.testcontainers.redpanda.RedpandaContainer; +import org.testcontainers.utility.DockerImageName; + +public class CustomRedpandaContainer extends RedpandaContainer { + + private static final Logger logger = LoggerFactory.getLogger(CustomRedpandaContainer.class); + + public CustomRedpandaContainer(String image) { + super(image); + } + + public CustomRedpandaContainer(DockerImageName imageName) { + super(imageName); + } + + protected void containerIsStarting(InspectContainerResponse containerInfo) { + super.containerIsStarting(containerInfo); + + logger.info("getNetworkAliases() -> {}", this.getNetworkAliases()); + + String command = "#!/bin/bash\n"; + command = command + "/usr/bin/rpk redpanda start --mode dev-container "; + command = command + "--kafka-addr PLAINTEXT://0.0.0.0:29092,OUTSIDE://0.0.0.0:9092 "; + command = command + "--advertise-kafka-addr PLAINTEXT://" + this.getNetworkAliases().get(this.getNetworkAliases().size()-1) + ":29092,OUTSIDE://" + this.getHost() + ":" + this.getMappedPort(9092); + this.copyFileToContainer(Transferable.of(command, 511), "/testcontainers_start.sh"); + + + + } + +} diff --git a/src/test/java/it/pagopa/swclient/mil/preset/resource/KafkaTestResourceLifecycleManager.java b/src/test/java/it/pagopa/swclient/mil/preset/resource/KafkaInMemoryTestResource.java similarity index 77% rename from src/test/java/it/pagopa/swclient/mil/preset/resource/KafkaTestResourceLifecycleManager.java rename to src/test/java/it/pagopa/swclient/mil/preset/resource/KafkaInMemoryTestResource.java index 121cee8..9b5bdd0 100644 --- a/src/test/java/it/pagopa/swclient/mil/preset/resource/KafkaTestResourceLifecycleManager.java +++ b/src/test/java/it/pagopa/swclient/mil/preset/resource/KafkaInMemoryTestResource.java @@ -8,9 +8,9 @@ import java.util.HashMap; import java.util.Map; -public class KafkaTestResourceLifecycleManager implements QuarkusTestResourceLifecycleManager { +public class KafkaInMemoryTestResource implements QuarkusTestResourceLifecycleManager { - static final Logger logger = LoggerFactory.getLogger(KafkaTestResourceLifecycleManager.class); + static final Logger logger = LoggerFactory.getLogger(KafkaInMemoryTestResource.class); @Override public Map start() { diff --git a/src/test/java/it/pagopa/swclient/mil/preset/resource/MongoTestResource.java b/src/test/java/it/pagopa/swclient/mil/preset/resource/MongoTestResource.java index 71b4656..1dd5d07 100644 --- a/src/test/java/it/pagopa/swclient/mil/preset/resource/MongoTestResource.java +++ b/src/test/java/it/pagopa/swclient/mil/preset/resource/MongoTestResource.java @@ -14,12 +14,12 @@ import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.utility.DockerImageName; -import java.util.Iterator; import java.util.Map; public class MongoTestResource implements QuarkusTestResourceLifecycleManager, DevServicesContext.ContextAware { private static final Logger logger = LoggerFactory.getLogger(MongoTestResource.class); + private static final String MONGO_NETWORK_ALIAS = "mongo-it"; private GenericContainer mongoContainer; @@ -30,79 +30,74 @@ public class MongoTestResource implements QuarkusTestResourceLifecycleManager, D public void setIntegrationTestContext(DevServicesContext devServicesContext){ this.devServicesContext = devServicesContext; } - - + @Override public Map start() { - - // create a "fake" network using the same id as the one that will be used by Quarkus - // using the network is the only way to make the withNetworkAliases work - logger.info("devServicesContext.containerNetworkId() -> " + devServicesContext.containerNetworkId()); - Network testNetwork = new Network() { - @Override - public String getId() { - return devServicesContext.containerNetworkId().get(); - } - - @Override - public void close() { - - } - - @Override - public Statement apply(Statement statement, Description description) { - return null; - } - }; - - mongoContainer = new GenericContainer<>(DockerImageName.parse("mongo:latest")) - .withNetwork(testNetwork) + + logger.info("Starting Mongo container..."); + + mongoContainer = new GenericContainer<>(DockerImageName.parse("mongo:4.2")) + .withExposedPorts(27017) + .withNetwork(getNetwork()) .withNetworkAliases(MONGO_NETWORK_ALIAS) //.withNetworkMode(devServicesContext.containerNetworkId().get()) .waitingFor(Wait.forListeningPort()); mongoContainer.withLogConsumer(new Slf4jLogConsumer(logger)); - mongoContainer.withFileSystemBind("./src/test/resources", "/home/mongo"); -// mongoContainer.setCommand("--verbose"); + mongoContainer.withFileSystemBind("./src/test/resources/it/mongo", "/home/mongo"); + //mongoContainer.setCommand("--verbose"); mongoContainer.start(); - - try { - logger.info("----------------------execInContainer START ----------------------"); - - - ExecResult result = mongoContainer.execInContainer("mongosh", "<", "/home/mongo/mongoInit.js"); - - logger.info("----------------------script executed {} ----------------------",result); - + final Integer exposedPort = mongoContainer.getMappedPort(27017); + devServicesContext.devServicesProperties().put("test.mongo.exposed-port", exposedPort.toString()); - logger.info("----------------------execInContainer END ----------------------"); - } catch (Exception e) { - logger.error("ERROR ", e); - e.printStackTrace(); + try { + ExecResult result = mongoContainer.execInContainer("mongosh", "<", "/home/mongo/mongoInit.js"); + logger.info("Init script result {}", result); + } + catch (Exception e) { + logger.error("Error while importing data into DB", e); } // Pass the configuration to the application under test - - Map map = ImmutableMap.of( - "quarkus.log.level", "DEBUG", - "quarkus.log.category.\"it.pagopa.swclient.mil.preset\".level", "DEBUG", - "quarkus.mongodb.connection-string","mongodb://" + MONGO_NETWORK_ALIAS + ":" + 27017 - ); - - Iterator> itr = map.entrySet().iterator(); - - while (itr.hasNext()) { - System.out.println(itr.next()); - } - return map; + return ImmutableMap.of( + "mongo-connection-string-1","mongodb://" + MONGO_NETWORK_ALIAS + ":" + 27017, + "mongo-connection-string-2",MONGO_NETWORK_ALIAS + ":" + 27017, + "mongo-connect-timeout", "30", + "mongo-read-timeout", "30", + "mongo-server-selection-timeout", "30" + ); + } + + // create a "fake" network using the same id as the one that will be used by Quarkus + // using the network is the only way to make the withNetworkAliases work + private Network getNetwork() { + logger.info("devServicesContext.containerNetworkId() -> " + devServicesContext.containerNetworkId()); + return new Network() { + @Override + public String getId() { + return devServicesContext.containerNetworkId().get(); + } + + @Override + public void close() { + + } + + @Override + public Statement apply(Statement statement, Description description) { + return null; + } + }; } @Override public void stop() { if (null != mongoContainer) { + logger.info("Stopping Mongo container..."); mongoContainer.stop(); + logger.info("Mongo container stopped"); } } diff --git a/src/test/java/it/pagopa/swclient/mil/preset/resource/RedpandaTestResource.java b/src/test/java/it/pagopa/swclient/mil/preset/resource/RedpandaTestResource.java new file mode 100644 index 0000000..2ad14b8 --- /dev/null +++ b/src/test/java/it/pagopa/swclient/mil/preset/resource/RedpandaTestResource.java @@ -0,0 +1,103 @@ +package it.pagopa.swclient.mil.preset.resource; + +import com.google.common.collect.ImmutableMap; +import io.quarkus.test.common.DevServicesContext; +import io.quarkus.test.common.QuarkusTestResourceLifecycleManager; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testcontainers.containers.Network; +import org.testcontainers.containers.output.Slf4jLogConsumer; +import org.testcontainers.redpanda.RedpandaContainer; +import org.testcontainers.utility.DockerImageName; + +import java.util.Map; + +public class RedpandaTestResource implements QuarkusTestResourceLifecycleManager, DevServicesContext.ContextAware { + + private static final Logger logger = LoggerFactory.getLogger(RedpandaTestResource.class); + + private static final String REDPANDA_NETWORK_ALIAS = "redpanda-it"; + + private RedpandaContainer redpandaContainer; + + private DevServicesContext devServicesContext; + + @Override + public void setIntegrationTestContext(DevServicesContext devServicesContext){ + this.devServicesContext = devServicesContext; + } + + @Override + public Map start() { + + try { + logger.info("Starting Redpanda container..."); + + // this version of testcontainers is not compatible with redpandadata/redpanda + DockerImageName myImage = DockerImageName.parse("redpandadata/redpanda:v23.1.9").asCompatibleSubstituteFor("docker.redpanda.com/vectorized/redpanda"); + + redpandaContainer = new CustomRedpandaContainer(myImage); + redpandaContainer + .withNetwork(getNetwork()) + .withNetworkAliases(REDPANDA_NETWORK_ALIAS); + + redpandaContainer.withLogConsumer(new Slf4jLogConsumer(logger)); + + //redpandaContainer.withFileSystemBind("./src/test/resources/it/mongo", "/home/mongo"); + //redpandaContainer.setCommand("--verbose"); + redpandaContainer.start(); + + final Integer exposedPort = redpandaContainer.getMappedPort(9092); + final String bootstrapServers = redpandaContainer.getBootstrapServers(); + logger.info("Redpanda bootstrap servers: {}", bootstrapServers); + + final String calculatedBootstrapServers = REDPANDA_NETWORK_ALIAS + ":" + exposedPort; + logger.info("Redpanda calculated bootstrap servers: {}", calculatedBootstrapServers); + + devServicesContext.devServicesProperties().put("test.kafka.bootstrap-server", "localhost:" + exposedPort); + + // Pass the configuration to the application under test + return ImmutableMap.of( + "kafka-bootstrap-server", REDPANDA_NETWORK_ALIAS + ":" + 29092 + ); + } catch (Exception e) { + logger.error("Error while starting redpanda", e); + throw e; + } + } + + // create a "fake" network using the same id as the one that will be used by Quarkus + // using the network is the only way to make the withNetworkAliases work + private Network getNetwork() { + logger.info("devServicesContext.containerNetworkId() -> " + devServicesContext.containerNetworkId()); + return new Network() { + @Override + public String getId() { + return devServicesContext.containerNetworkId().get(); + } + + @Override + public void close() { + + } + + @Override + public Statement apply(Statement statement, Description description) { + return null; + } + }; + } + + @Override + public void stop() { + if (null != redpandaContainer) { + logger.info("Stopping Redpanda container..."); + redpandaContainer.stop(); + logger.info("Redpanda container stopped"); + } + + } + +} diff --git a/src/test/resources/mongoInit.js b/src/test/resources/it/mongo/mongoInit.js similarity index 100% rename from src/test/resources/mongoInit.js rename to src/test/resources/it/mongo/mongoInit.js From 9e5241afeb09e2ce8baa4a8b82b4523850b77f59 Mon Sep 17 00:00:00 2001 From: "fabrizio.guerrini" Date: Tue, 6 Jun 2023 11:32:26 +0200 Subject: [PATCH 5/9] managed integration test --- pom.xml | 3 +- .../mil/preset/resource/PresetsResource.java | 2 +- .../preset/resource/TerminalsResource.java | 21 +- src/main/resources/application.properties | 33 +- .../mil/preset/TerminalsResourceTest.java | 30 +- .../mil/preset/it/IntegrationTestProfile.java | 13 +- .../mil/preset/it/PresetResourceTestIT.java | 449 +++++++++++------- .../preset/it/PresetTopicResourceTestIT.java | 82 +++- .../preset/it/SubscribeResourceTestIT.java | 350 ++++++++------ .../preset/resource/MongoTestResource.java | 17 +- .../preset/resource/RedpandaTestResource.java | 66 ++- .../mil/preset/util/SubscriberTestData.java | 31 ++ 12 files changed, 694 insertions(+), 403 deletions(-) create mode 100644 src/test/java/it/pagopa/swclient/mil/preset/util/SubscriberTestData.java diff --git a/pom.xml b/pom.xml index 23a15fd..a56a13a 100644 --- a/pom.xml +++ b/pom.xml @@ -82,10 +82,11 @@ io.quarkus quarkus-smallrye-reactive-messaging-kafka + io.smallrye.reactive smallrye-reactive-messaging-in-memory diff --git a/src/main/java/it/pagopa/swclient/mil/preset/resource/PresetsResource.java b/src/main/java/it/pagopa/swclient/mil/preset/resource/PresetsResource.java index 2f233b9..68b7175 100644 --- a/src/main/java/it/pagopa/swclient/mil/preset/resource/PresetsResource.java +++ b/src/main/java/it/pagopa/swclient/mil/preset/resource/PresetsResource.java @@ -202,7 +202,7 @@ private Uni> findPresetOperations(String paTaxCode, String private Uni findLatestPresetOperation(String paTaxCode, String subscriberId) { return presetRepository.find(LAST_PRESET_FILTER, - Sort.by("creationTimestamp").descending(), + Sort.by("presetOperation.creationTimestamp").descending(), Parameters .with("paTaxCode", paTaxCode) .and("subscriberId", subscriberId) diff --git a/src/main/java/it/pagopa/swclient/mil/preset/resource/TerminalsResource.java b/src/main/java/it/pagopa/swclient/mil/preset/resource/TerminalsResource.java index 0e64c4e..2be3493 100644 --- a/src/main/java/it/pagopa/swclient/mil/preset/resource/TerminalsResource.java +++ b/src/main/java/it/pagopa/swclient/mil/preset/resource/TerminalsResource.java @@ -1,5 +1,12 @@ package it.pagopa.swclient.mil.preset.resource; +import java.net.URI; +import java.security.SecureRandom; +import java.util.List; + +import org.apache.commons.lang3.RandomStringUtils; +import org.eclipse.microprofile.config.inject.ConfigProperty; + import io.quarkus.logging.Log; import io.quarkus.panache.common.Parameters; import io.smallrye.mutiny.Uni; @@ -15,7 +22,6 @@ import it.pagopa.swclient.mil.preset.dao.SubscriberEntity; import it.pagopa.swclient.mil.preset.dao.SubscriberRepository; import it.pagopa.swclient.mil.preset.utils.DateUtils; -import jakarta.annotation.security.RolesAllowed; import jakarta.inject.Inject; import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; @@ -34,13 +40,6 @@ import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.Response.Status; import jakarta.ws.rs.core.SecurityContext; -import org.apache.commons.lang3.RandomStringUtils; -import org.eclipse.microprofile.config.inject.ConfigProperty; -import org.eclipse.microprofile.jwt.JsonWebToken; - -import java.net.URI; -import java.security.SecureRandom; -import java.util.List; @Path("/terminals") @@ -49,8 +48,8 @@ public class TerminalsResource { @Inject SubscriberRepository subscriberRepository; - @Inject - JsonWebToken jwt; +// @Inject +// JsonWebToken jwt; /** * The base URL for the location header returned by the subscribe API (i.e. the API management base URL) @@ -66,7 +65,7 @@ public class TerminalsResource { */ @GET @Path("/{paTaxCode}") - @RolesAllowed({ "InstitutionPortal" }) +// @RolesAllowed({ "InstitutionPortal" }) @Produces(MediaType.APPLICATION_JSON) public Uni getSubscribers(@Valid @BeanParam InstitutionPortalHeaders portalHeaders, diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 1f9383c..59c640b 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -53,36 +53,29 @@ quarkus.log.min-level=DEBUG # mongo-server-selection-timeout = 5s # ------------------------------------------------------------------------------ -%dev.kafka.bootstrap.servers=localhost:19092 -%test.kafka.bootstrap.servers=kafka:9092 -%prod.kafka.bootstrap.servers=${kafka-bootstrap-server} - mp.messaging.incoming.presets.connector=smallrye-kafka mp.messaging.incoming.presets.group.id=preset-processor quarkus.kafka.devservices.enabled=false -#quarkus.reactive-messaging.auto-connector-attachment=false - -#kafka.bootstrap.servers=kafka:9092 -#mp.messaging.incoming.presets.connector=smallrye-kafka -#mp.messaging.incoming.presets.auto.offset.reset=earliest -#mp.messaging.incoming.presets.topic=presets -#mp.messaging.outgoing.preset-result.connector=smallrye-kafka -#mp.messaging.outgoing.preset-result.topic=preset-result +%dev.kafka.bootstrap.servers=milops.servicebus.windows.net:9093 +%dev.kafka.security.protocol=SASL_SSL +%dev.kafka.sasl.mechanism=PLAIN +%dev.kafka.sasl.jaas.config=org.apache.kafka.common.security.plain.PlainLoginModule required username="" password=""; -#mp.messaging.incoming.presets.connector=smallrye-kafka -#mp.messaging.incoming.presets.topic=presets -#mp.messaging.incoming.presets.value.deserializer=it.pagopa.swclient.mil.preset.utils.PresetDeserializer +%prod.kafka.bootstrap.servers=${kafka-bootstrap-server} +%prod.kafka.security.protocol=${kafka-security-protocol} +%prod.kafka.sasl.mechanism=${kafka-sasl-mechanism} +%prod.kafka.sasl.jaas.config=${kafka-sasl-jaas-config} # ------------------------------------------------------------------------------ # JWT RBAC configurations # ------------------------------------------------------------------------------ -%dev.mp.jwt.verify.publickey.location=http://localhost:8088/realms/mil-test/protocol/openid-connect/certs -%test.mp.jwt.verify.publickey.location=http://localhost:8088/realms/mil-test/protocol/openid-connect/certs -%prod.mp.jwt.verify.publickey.location=${jwt-publickey-location} +#%dev.mp.jwt.verify.publickey.location=http://localhost:8088/realms/mil-test/protocol/openid-connect/certs +#%test.mp.jwt.verify.publickey.location=http://localhost:8088/realms/mil-test/protocol/openid-connect/certs +#%prod.mp.jwt.verify.publickey.location=${jwt-publickey-location} # ------------------------------------------------------------------------------ @@ -91,4 +84,6 @@ quarkus.kafka.devservices.enabled=false %dev.preset.location.base-url=https://mil-d-apim.azure-api.net/mil-preset %test.preset.location.base-url=https://mil-d-apim.azure-api.net/mil-preset -%prod.preset.location.base-url=https://mil-d-apim.azure-api.net/mil-preset \ No newline at end of file +%prod.preset.location.base-url=https://mil-d-apim.azure-api.net/mil-preset + +quarkus.log.category."io.quarkus.mongodb.panache.runtime".level=DEBUG diff --git a/src/test/java/it/pagopa/swclient/mil/preset/TerminalsResourceTest.java b/src/test/java/it/pagopa/swclient/mil/preset/TerminalsResourceTest.java index a70093c..206dee3 100644 --- a/src/test/java/it/pagopa/swclient/mil/preset/TerminalsResourceTest.java +++ b/src/test/java/it/pagopa/swclient/mil/preset/TerminalsResourceTest.java @@ -1,5 +1,20 @@ package it.pagopa.swclient.mil.preset; +import static io.restassured.RestAssured.given; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeoutException; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; + import io.quarkus.test.common.http.TestHTTPEndpoint; import io.quarkus.test.junit.QuarkusTest; import io.quarkus.test.junit.mockito.InjectMock; @@ -11,20 +26,6 @@ import it.pagopa.swclient.mil.preset.dao.SubscriberEntity; import it.pagopa.swclient.mil.preset.dao.SubscriberRepository; import it.pagopa.swclient.mil.preset.resource.TerminalsResource; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInstance; -import org.mockito.ArgumentCaptor; -import org.mockito.Mockito; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.TimeoutException; - -import static io.restassured.RestAssured.given; @QuarkusTest @@ -77,6 +78,7 @@ void createTestObjects() { /* **** get Subscribers **** */ @Test +// @TestSecurity( roles = {"InstitutionPortal"}) void getSubscribers_200() { Mockito diff --git a/src/test/java/it/pagopa/swclient/mil/preset/it/IntegrationTestProfile.java b/src/test/java/it/pagopa/swclient/mil/preset/it/IntegrationTestProfile.java index 95c915b..a2992db 100644 --- a/src/test/java/it/pagopa/swclient/mil/preset/it/IntegrationTestProfile.java +++ b/src/test/java/it/pagopa/swclient/mil/preset/it/IntegrationTestProfile.java @@ -1,14 +1,15 @@ package it.pagopa.swclient.mil.preset.it; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import com.google.common.collect.ImmutableList; + import io.quarkus.test.junit.QuarkusTestProfile; import it.pagopa.swclient.mil.preset.resource.MongoTestResource; import it.pagopa.swclient.mil.preset.resource.RedpandaTestResource; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - public class IntegrationTestProfile implements QuarkusTestProfile { @Override @@ -16,7 +17,7 @@ public Map getConfigOverrides() { Map configOverrides = new HashMap<>(); - configOverrides.put("preset.quarkus-log-level", "DEBUG"); + configOverrides.put("preset.quarkus-log-level", "INFO"); configOverrides.put("preset.app-log-level", "DEBUG"); return configOverrides; @@ -25,7 +26,7 @@ public Map getConfigOverrides() { @Override public List testResources() { return ImmutableList.of( - new TestResourceEntry(MongoTestResource.class), + new TestResourceEntry(MongoTestResource.class) , new TestResourceEntry(RedpandaTestResource.class) ); } diff --git a/src/test/java/it/pagopa/swclient/mil/preset/it/PresetResourceTestIT.java b/src/test/java/it/pagopa/swclient/mil/preset/it/PresetResourceTestIT.java index 7858d09..eedc77f 100644 --- a/src/test/java/it/pagopa/swclient/mil/preset/it/PresetResourceTestIT.java +++ b/src/test/java/it/pagopa/swclient/mil/preset/it/PresetResourceTestIT.java @@ -1,31 +1,117 @@ package it.pagopa.swclient.mil.preset.it; -import io.quarkus.test.common.QuarkusTestResource; -import io.quarkus.test.common.http.TestHTTPEndpoint; -import io.quarkus.test.junit.QuarkusIntegrationTest; -import it.pagopa.swclient.mil.preset.resource.MongoTestResource; -import it.pagopa.swclient.mil.preset.resource.PresetsResource; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.TestInstance; +import static io.restassured.RestAssured.given; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.UUID; + +import org.bson.codecs.configuration.CodecRegistries; +import org.bson.codecs.configuration.CodecRegistry; +import org.bson.codecs.pojo.PojoCodecProvider; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.mongodb.MongoClientSettings; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoCollection; + +import io.quarkus.test.common.DevServicesContext; +import io.quarkus.test.common.http.TestHTTPEndpoint; +import io.quarkus.test.junit.QuarkusIntegrationTest; +import io.quarkus.test.junit.TestProfile; +import io.restassured.http.ContentType; +import io.restassured.response.Response; + +import it.pagopa.swclient.mil.preset.ErrorCode; +import it.pagopa.swclient.mil.preset.bean.CreatePresetRequest; +import it.pagopa.swclient.mil.preset.bean.Notice; +import it.pagopa.swclient.mil.preset.bean.PaymentTransaction; +import it.pagopa.swclient.mil.preset.bean.PaymentTransactionStatus; +import it.pagopa.swclient.mil.preset.bean.PresetOperation; +import it.pagopa.swclient.mil.preset.bean.Subscriber; +import it.pagopa.swclient.mil.preset.dao.PresetEntity; +import it.pagopa.swclient.mil.preset.dao.SubscriberEntity; +import it.pagopa.swclient.mil.preset.resource.PresetsResource; +import it.pagopa.swclient.mil.preset.util.PresetTestData; +import it.pagopa.swclient.mil.preset.util.SubscriberTestData; @QuarkusIntegrationTest -@QuarkusTestResource(value=MongoTestResource.class,restrictToAnnotatedClass = true) +@TestProfile(IntegrationTestProfile.class) @TestHTTPEndpoint(PresetsResource.class) @TestInstance(TestInstance.Lifecycle.PER_CLASS) class PresetResourceTestIT { + + static final Logger logger = LoggerFactory.getLogger(PresetResourceTestIT.class); + final static String SESSION_ID = "a6a666e6-97da-4848-b568-99fedccb642c"; final static String API_VERSION = "1.0.0-alpha-a.b-c-somethinglong+build.1-aef.1-its-okay"; final static String PA_TAX_CODE = "15376371009"; final static String SUBSCRIBER_ID = "a25tr0"; + DevServicesContext devServicesContext; + + Map validMilHeaders; + + MongoClient mongoClient; + + CodecRegistry pojoCodecRegistry; + Map commonHeaders; Map presetHeaders; + SubscriberEntity subscriberEntity; + @BeforeAll void createTestObjects() { + validMilHeaders = PresetTestData.getMilHeaders(true, true); + + // initialize mongo client + pojoCodecRegistry = CodecRegistries.fromRegistries(MongoClientSettings.getDefaultCodecRegistry(), + CodecRegistries.fromProviders(PojoCodecProvider.builder().automatic(true).build())); + + String mongoExposedPort = devServicesContext.devServicesProperties().get("test.mongo.exposed-port"); + mongoClient = MongoClients.create("mongodb://127.0.0.1:" + mongoExposedPort); + + List subscriberIdList = List.of( + SubscriberTestData.SUBCRIBER_FOUND, + SubscriberTestData.SUBCRIBER_NOT_FOUND + ); + + List subscriberEntityEntities = subscriberIdList.stream() + .map(subId -> SubscriberTestData.getSubscribers(subId)) + .toList(); + + + MongoCollection collection = mongoClient.getDatabase("mil") + .getCollection("subscribers", SubscriberEntity.class) + .withCodecRegistry(pojoCodecRegistry); + + collection.insertMany(subscriberEntityEntities); + + + MongoCollection collectionPreset = mongoClient.getDatabase("mil") + .getCollection("presets", PresetEntity.class) + .withCodecRegistry(pojoCodecRegistry); + + final String presetId = UUID.randomUUID().toString(); + + PresetEntity presetEntity = PresetTestData.getPresetEntity("77457c64-0870-407a-b2cb-0f948b04fb9a","x46tr3"); + PaymentTransaction paymentTransaction = PresetTestData.getPaymentTransaction( + PaymentTransactionStatus.PENDING, + PresetTestData.getMilHeaders(true, true), + PresetTestData.getPreset(presetId, "x46tr3"), + 1); + presetEntity.presetOperation.setStatusDetails(paymentTransaction); + collectionPreset.insertOne(presetEntity); + presetHeaders = new HashMap<>(); presetHeaders.put("RequestId", "d0d654e6-97da-4848-b568-99fedccb642b"); presetHeaders.put("Version", API_VERSION); @@ -38,165 +124,196 @@ void createTestObjects() { commonHeaders.put("TerminalId", "0aB9wXyZ"); commonHeaders.put("SessionId", SESSION_ID); commonHeaders.put("MerchantId", "4585625"); + + Subscriber subscriber = new Subscriber(); + subscriber.setAcquirerId("4585625"); + subscriber.setChannel("POS"); + subscriber.setLabel("Reception POS"); + subscriber.setLastUsageTimestamp("2023-05-08T10:55:57"); + subscriber.setMerchantId("28405fHfk73x88D"); + subscriber.setPaTaxCode("15376371009"); + subscriber.setSubscriberId(SUBSCRIBER_ID); + subscriber.setSubscriptionTimestamp("2023-05-05T09:31:33"); + subscriber.setTerminalId("0aB9wXyZ"); + + subscriberEntity = new SubscriberEntity(); + subscriberEntity.id = SUBSCRIBER_ID; + subscriberEntity.subscriber = subscriber; + } -// @Test -// void createPreset_201() { -// -// PresetRequest request = new PresetRequest(); -// request.setNoticeNumber("485564829563528563"); -// request.setNoticeTaxCode("15376371009"); -// request.setOperationType("PAYMENT_NOTICE"); -// request.setPaTaxCode("15376371009"); -// request.setSubscriberId("x46tr4"); -// -// Response response = given() -// .contentType(ContentType.JSON) -// .headers(presetHeaders) -// .body(request) -// .and() -// .when() -// .post() -// .then() -// .extract() -// .response(); -// -// Assertions.assertEquals(201, response.statusCode()); -// -// Assertions.assertNotNull(response.getHeader(SubscribeResource.LOCATION)); -// } -// -// @Test -// void createPreset_400_subscriberNotFound() { -// -// PresetRequest request = new PresetRequest(); -// request.setNoticeNumber("485564829563528563"); -// request.setNoticeTaxCode("15376371009"); -// request.setOperationType("PAYMENT_NOTICE"); -// request.setPaTaxCode("15376371111"); -// request.setSubscriberId("x46tr4"); -// -// Response response = given() -// .contentType(ContentType.JSON) -// .headers(presetHeaders) -// .body(request) -// .and() -// .when() -// .post() -// .then() -// .extract() -// .response(); -// -// Assertions.assertEquals(400, response.statusCode()); -// -// Assertions.assertNull(response.getHeader(SubscribeResource.LOCATION)); -// Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_SUBSCRIBER_NOT_FOUND)); -// } -// @Test -// void getPresets_200() { -// Response response = given() -// .contentType(ContentType.JSON) -// .headers(presetHeaders) -// .and() -// .when() -// .get("/15376371009/x46tr3") -// .then() -// .extract() -// .response(); -// -// Assertions.assertEquals(200, response.statusCode()); -// -// Assertions.assertNotNull(response.jsonPath().getJsonObject("presets")); -// List arr = response.jsonPath().getList("presets", PresetResponse.class); -// -// Assertions.assertNotNull(arr.get(0).getCreationTimestamp()); -// Assertions.assertNotNull(arr.get(0).getNoticeNumber()); -// -// Assertions.assertNotNull(arr.get(0).getNoticeTaxCode()); -// Assertions.assertNotNull(arr.get(0).getOperationType()); -// Assertions.assertNotNull(arr.get(0).getPaTaxCode()); -// Assertions.assertNotNull(arr.get(0).getPresetId()); -// Assertions.assertNotNull(arr.get(0).getStatus()); -// Assertions.assertNotNull(arr.get(0).getStatusTimestamp()); -// Assertions.assertNotNull(arr.get(0).getSubscriberId()); -// PaymentTransaction statDetails = arr.get(0).getStatusDetails(); -// Assertions.assertNotNull(statDetails.getAcquirerId()); -// Assertions.assertNotNull(statDetails.getChannel()); -// Assertions.assertNotNull(statDetails.getInsertTimestamp()); -// Assertions.assertNotNull(statDetails.getAcquirerId()); -// Assertions.assertNotNull(statDetails.getStatus()); -// Assertions.assertNotNull(statDetails.getNotices()); -// List noticesResponse = statDetails.getNotices(); -// Assertions.assertNotNull(noticesResponse.get(0).getAmount()); -// Assertions.assertNotNull(noticesResponse.get(0).getCompany()); -// Assertions.assertNotNull(noticesResponse.get(0).getDescription()); -// Assertions.assertNotNull(noticesResponse.get(0).getNoticeNumber()); -// Assertions.assertNotNull(noticesResponse.get(0).getOffice()); -// Assertions.assertNotNull(noticesResponse.get(0).getPaTaxCode()); -// Assertions.assertNotNull(noticesResponse.get(0).getPaymentToken()); -// } -// -// @Test -// void getPresets_200_emptyPreset() { -// -// Response response = given() -// .contentType(ContentType.JSON) -// .headers(presetHeaders) -// .and() -// .when() -// .get("/15376371009/46t000") -// .then() -// .extract() -// .response(); -// -// Assertions.assertEquals(200, response.statusCode()); -// -// Assertions.assertNotNull(response.jsonPath().getJsonObject("presets")); -// List arr = response.jsonPath().getList("presets", PresetResponse.class); -// -// Assertions.assertEquals(0,arr.size()); -// } -// -// @Test -// void getLastPreset_200() { -// -// Response response = given() -// .contentType(ContentType.JSON) -// .headers(commonHeaders) -// .and() -// .when() -// .get("/15376371009/x46tr3/last_to_execute") -// .then() -// .extract() -// .response(); -// -// Assertions.assertEquals(200, response.statusCode()); -// -// Assertions.assertNotNull(response.jsonPath().getString("creationTimestamp")); -// Assertions.assertNotNull(response.jsonPath().getString("noticeNumber")); -// Assertions.assertNotNull(response.jsonPath().getString("noticeTaxCode")); -// Assertions.assertNotNull(response.jsonPath().getString("operationType")); -// Assertions.assertNotNull(response.jsonPath().getString("paTaxCode")); -// Assertions.assertNotNull(response.jsonPath().getString("presetId")); -// Assertions.assertNotNull(response.jsonPath().getString("status")); -// Assertions.assertNotNull(response.jsonPath().getString("statusTimestamp")); -// Assertions.assertNotNull(response.jsonPath().getString("subscriberId")); -// System.out.println(">>>>>" + response.jsonPath()); -// Assertions.assertNotNull(response.jsonPath().getJsonObject("statusDetails")); -// PaymentTransaction statDetails = response.jsonPath().getObject("statusDetails", PaymentTransaction.class); -// Assertions.assertNotNull(statDetails.getChannel()); -// Assertions.assertNotNull(statDetails.getInsertTimestamp()); -// Assertions.assertNotNull(statDetails.getAcquirerId()); -// Assertions.assertNotNull(statDetails.getStatus()); -// Assertions.assertNotNull(statDetails.getNotices()); -// List noticesResponse = statDetails.getNotices(); -// Assertions.assertNotNull(noticesResponse.get(0).getAmount()); -// Assertions.assertNotNull(noticesResponse.get(0).getCompany()); -// Assertions.assertNotNull(noticesResponse.get(0).getDescription()); -// Assertions.assertNotNull(noticesResponse.get(0).getNoticeNumber()); -// Assertions.assertNotNull(noticesResponse.get(0).getOffice()); -// Assertions.assertNotNull(noticesResponse.get(0).getPaTaxCode()); -// Assertions.assertNotNull(noticesResponse.get(0).getPaymentToken()); -// } + @AfterAll + void destroyTestObjects() { + + try { + mongoClient.close(); + } catch (Exception e){ + logger.error("Error while closing mongo client", e); + } + + } + + + @Test + void createPreset_201() { + + CreatePresetRequest request = new CreatePresetRequest(); + request.setNoticeNumber("485564829563528563"); + request.setNoticeTaxCode("15376371009"); + request.setOperationType("PAYMENT_NOTICE"); + request.setPaTaxCode("15376371009"); + request.setSubscriberId("x46tr0"); + + Response response = given() + .contentType(ContentType.JSON) + .headers(presetHeaders) + .body(request) + .and() + .when() + .post() + .then() + .extract() + .response(); + + Assertions.assertEquals(201, response.statusCode()); + Assertions.assertEquals(0, response.body().asString().length()); + + + final String locationPath = "/presets/" + PA_TAX_CODE + "/" + SubscriberTestData.SUBCRIBER_FOUND + "/"; + Assertions.assertTrue(response.getHeader("Location") != null && response.getHeader("Location").contains(locationPath)); + } + + @Test + void createPreset_400_subscriberNotFound() { + + CreatePresetRequest request = new CreatePresetRequest(); + request.setNoticeNumber("485564829563528563"); + request.setNoticeTaxCode("15376371009"); + request.setOperationType("PAYMENT_NOTICE"); + request.setPaTaxCode("15376371111"); + request.setSubscriberId("x46tr4"); + + Response response = given() + .contentType(ContentType.JSON) + .headers(presetHeaders) + .body(request) + .and() + .when() + .post() + .then() + .extract() + .response(); + + Assertions.assertEquals(400, response.statusCode()); + + Assertions.assertNull(response.getHeader("Location")); + Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.SUBSCRIBER_NOT_FOUND)); + } + + @Test + void getPresets_200() { + Response response = given() + .contentType(ContentType.JSON) + .headers(presetHeaders) + .and() + .when() + .get("/15376371009/x46tr3") + .then() + .extract() + .response(); + + Assertions.assertEquals(200, response.statusCode()); + + Assertions.assertNotNull(response.jsonPath().getJsonObject("presets")); + + List arr = response.jsonPath().getList("presets", PresetOperation.class); + + Assertions.assertNotNull(arr.get(0).getCreationTimestamp()); + Assertions.assertNotNull(arr.get(0).getNoticeNumber()); + + Assertions.assertNotNull(arr.get(0).getNoticeTaxCode()); + Assertions.assertNotNull(arr.get(0).getOperationType()); + Assertions.assertNotNull(arr.get(0).getPaTaxCode()); + Assertions.assertNotNull(arr.get(0).getPresetId()); + Assertions.assertNotNull(arr.get(0).getStatus()); + Assertions.assertNotNull(arr.get(0).getStatusTimestamp()); + Assertions.assertNotNull(arr.get(0).getSubscriberId()); + PaymentTransaction statDetails = arr.get(0).getStatusDetails(); + Assertions.assertNotNull(statDetails.getAcquirerId()); + Assertions.assertNotNull(statDetails.getChannel()); + Assertions.assertNotNull(statDetails.getInsertTimestamp()); + Assertions.assertNotNull(statDetails.getAcquirerId()); + Assertions.assertNotNull(statDetails.getStatus()); + Assertions.assertNotNull(statDetails.getNotices()); + List noticesResponse = statDetails.getNotices(); + Assertions.assertNotNull(noticesResponse.get(0).getAmount()); + Assertions.assertNotNull(noticesResponse.get(0).getCompany()); + Assertions.assertNotNull(noticesResponse.get(0).getDescription()); + Assertions.assertNotNull(noticesResponse.get(0).getNoticeNumber()); + Assertions.assertNotNull(noticesResponse.get(0).getOffice()); + Assertions.assertNotNull(noticesResponse.get(0).getPaTaxCode()); + Assertions.assertNotNull(noticesResponse.get(0).getPaymentToken()); + } + + @Test + void getPresets_200_emptyPreset() { + + Response response = given() + .contentType(ContentType.JSON) + .headers(presetHeaders) + .and() + .when() + .get("/15376371009/46t000") + .then() + .extract() + .response(); + + Assertions.assertEquals(200, response.statusCode()); + + Assertions.assertNotNull(response.jsonPath().getJsonObject("presets")); + List arr = response.jsonPath().getList("presets", PresetOperation.class); + + Assertions.assertEquals(0,arr.size()); + } + + @Test + void getLastPreset_200() { + + Response response = given() + .contentType(ContentType.JSON) + .headers(commonHeaders) + .and() + .when() + .get("/15376371009/x46tr3/last_to_execute") + .then() + .extract() + .response(); + + Assertions.assertEquals(200, response.statusCode()); + Assertions.assertNotNull(response.jsonPath().getString("creationTimestamp")); + Assertions.assertNotNull(response.jsonPath().getString("noticeNumber")); + Assertions.assertNotNull(response.jsonPath().getString("noticeTaxCode")); + Assertions.assertNotNull(response.jsonPath().getString("operationType")); + Assertions.assertNotNull(response.jsonPath().getString("paTaxCode")); + Assertions.assertNotNull(response.jsonPath().getString("presetId")); + Assertions.assertNotNull(response.jsonPath().getString("status")); + Assertions.assertNotNull(response.jsonPath().getString("statusTimestamp")); + Assertions.assertNotNull(response.jsonPath().getString("subscriberId")); + Assertions.assertNotNull(response.jsonPath().getJsonObject("statusDetails")); + PaymentTransaction statDetails = response.jsonPath().getObject("statusDetails", PaymentTransaction.class); + Assertions.assertNotNull(statDetails.getChannel()); + Assertions.assertNotNull(statDetails.getInsertTimestamp()); + Assertions.assertNotNull(statDetails.getAcquirerId()); + Assertions.assertNotNull(statDetails.getStatus()); + Assertions.assertNotNull(statDetails.getNotices()); + List noticesResponse = statDetails.getNotices(); + Assertions.assertNotNull(noticesResponse.get(0).getAmount()); + Assertions.assertNotNull(noticesResponse.get(0).getCompany()); + Assertions.assertNotNull(noticesResponse.get(0).getDescription()); + Assertions.assertNotNull(noticesResponse.get(0).getNoticeNumber()); + Assertions.assertNotNull(noticesResponse.get(0).getOffice()); + Assertions.assertNotNull(noticesResponse.get(0).getPaTaxCode()); + Assertions.assertNotNull(noticesResponse.get(0).getPaymentToken()); + } } diff --git a/src/test/java/it/pagopa/swclient/mil/preset/it/PresetTopicResourceTestIT.java b/src/test/java/it/pagopa/swclient/mil/preset/it/PresetTopicResourceTestIT.java index 1fac7bb..12e4dcc 100644 --- a/src/test/java/it/pagopa/swclient/mil/preset/it/PresetTopicResourceTestIT.java +++ b/src/test/java/it/pagopa/swclient/mil/preset/it/PresetTopicResourceTestIT.java @@ -1,5 +1,33 @@ package it.pagopa.swclient.mil.preset.it; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import org.apache.kafka.clients.producer.KafkaProducer; +import org.apache.kafka.clients.producer.ProducerRecord; +import org.apache.kafka.clients.producer.RecordMetadata; +import org.apache.kafka.common.serialization.StringSerializer; +import org.bson.codecs.configuration.CodecRegistries; +import org.bson.codecs.configuration.CodecRegistry; +import org.bson.codecs.pojo.PojoCodecProvider; +import org.bson.conversions.Bson; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testcontainers.shaded.org.awaitility.Awaitility; + import com.mongodb.MongoClientSettings; import com.mongodb.client.FindIterable; import com.mongodb.client.MongoClient; @@ -7,6 +35,7 @@ import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoCursor; import com.mongodb.client.model.Filters; + import io.quarkus.kafka.client.serialization.ObjectMapperSerializer; import io.quarkus.test.common.DevServicesContext; import io.quarkus.test.junit.QuarkusIntegrationTest; @@ -20,27 +49,8 @@ import it.pagopa.swclient.mil.preset.dao.PresetEntity; import it.pagopa.swclient.mil.preset.util.PresetTestData; import it.pagopa.swclient.mil.preset.utils.DateUtils; -import org.apache.kafka.clients.producer.KafkaProducer; -import org.apache.kafka.clients.producer.ProducerRecord; -import org.apache.kafka.common.serialization.StringSerializer; -import org.bson.codecs.configuration.CodecRegistries; -import org.bson.codecs.configuration.CodecRegistry; -import org.bson.codecs.pojo.PojoCodecProvider; -import org.bson.conversions.Bson; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInstance; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.testcontainers.shaded.org.awaitility.Awaitility; - -import java.util.ArrayList; -import java.util.List; -import java.util.Properties; -import java.util.UUID; +@Disabled @QuarkusIntegrationTest @TestProfile(IntegrationTestProfile.class) @TestInstance(TestInstance.Lifecycle.PER_CLASS) @@ -74,6 +84,11 @@ void createTestData() { // initialize kafka producer Properties kafkaConfig = new Properties(); kafkaConfig.put("bootstrap.servers", devServicesContext.devServicesProperties().get("test.kafka.bootstrap-server")); +// kafkaConfig.put("bootstrap.servers", "localhost:19092"); + kafkaConfig.put("security.protocol", "SASL_PLAINTEXT"); + kafkaConfig.put("sasl.mechanism","SCRAM-SHA-256"); + kafkaConfig.put("sasl.jaas.config","org.apache.kafka.common.security.scram.ScramLoginModule required username=\"testuser\" password=\"testuser\";"); + kafkaConfig.put("linger.ms", 1); paymentTransactionProducer = new KafkaProducer<>(kafkaConfig, new StringSerializer(), new ObjectMapperSerializer<>()); @@ -87,10 +102,10 @@ void consume_close_ok() { PaymentTransaction paymentTransaction = PresetTestData.getPaymentTransaction( PaymentTransactionStatus.PENDING, PresetTestData.getMilHeaders(true, true), - PresetTestData.getPreset(presetId, "x46tr3"), + PresetTestData.getPreset(presetId, "y46tr3"), 1); - PresetEntity presetEntity = PresetTestData.getPresetEntity(presetId, "x46tr3"); + PresetEntity presetEntity = PresetTestData.getPresetEntity(presetId, "y46tr3"); mongoClient.getDatabase("mil") .getCollection("presets", PresetEntity.class) @@ -99,11 +114,28 @@ void consume_close_ok() { String currentTimestamp = DateUtils.getCurrentTimestamp(); - paymentTransactionProducer.send(new ProducerRecord<>("presets", paymentTransaction)); + logger.info("-------------------------------------------------------------------"); + Future resp = paymentTransactionProducer.send(new ProducerRecord<>("presets", paymentTransaction)); + + try { + RecordMetadata r = resp.get(10, TimeUnit.SECONDS); + + logger.info("DONE {}", resp.isDone()); + logger.info("TOPIC {}", r.topic()); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (ExecutionException e) { + e.printStackTrace(); + } catch (TimeoutException e) { + e.printStackTrace(); + } - Awaitility.await().until(() -> { + logger.info("-------------------------------------------------------------------"); + + Awaitility.await().pollDelay(Duration.ofSeconds(2)).until(() -> { PresetOperation presetOperation = getPresetOperation(presetId); - return presetOperation.getStatusTimestamp().compareTo(currentTimestamp) > 0; +// return presetOperation.getStatusTimestamp().compareTo(currentTimestamp) > 0; + return presetOperation.getStatus().equals(PresetStatus.EXECUTED.name()); }); checkDatabaseData(presetId, PresetStatus.EXECUTED, paymentTransaction); diff --git a/src/test/java/it/pagopa/swclient/mil/preset/it/SubscribeResourceTestIT.java b/src/test/java/it/pagopa/swclient/mil/preset/it/SubscribeResourceTestIT.java index b35d450..bb958c6 100644 --- a/src/test/java/it/pagopa/swclient/mil/preset/it/SubscribeResourceTestIT.java +++ b/src/test/java/it/pagopa/swclient/mil/preset/it/SubscribeResourceTestIT.java @@ -1,33 +1,86 @@ package it.pagopa.swclient.mil.preset.it; +import static io.restassured.RestAssured.given; -import io.quarkus.test.common.QuarkusTestResource; -import io.quarkus.test.common.http.TestHTTPEndpoint; -import io.quarkus.test.junit.QuarkusIntegrationTest; -import it.pagopa.swclient.mil.preset.resource.MongoTestResource; -import it.pagopa.swclient.mil.preset.resource.TerminalsResource; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.bson.codecs.configuration.CodecRegistries; +import org.bson.codecs.configuration.CodecRegistry; +import org.bson.codecs.pojo.PojoCodecProvider; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -import java.util.HashMap; -import java.util.Map; +import com.mongodb.MongoClientSettings; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoCollection; + +import io.quarkus.test.common.DevServicesContext; +import io.quarkus.test.common.http.TestHTTPEndpoint; +import io.quarkus.test.junit.QuarkusIntegrationTest; +import io.quarkus.test.junit.TestProfile; +import io.restassured.http.ContentType; +import io.restassured.response.Response; +import it.pagopa.swclient.mil.preset.bean.SubscribeRequest; +import it.pagopa.swclient.mil.preset.bean.Subscriber; +import it.pagopa.swclient.mil.preset.dao.SubscriberEntity; +import it.pagopa.swclient.mil.preset.resource.TerminalsResource; +import it.pagopa.swclient.mil.preset.util.SubscriberTestData; @QuarkusIntegrationTest -@QuarkusTestResource(value=MongoTestResource.class,restrictToAnnotatedClass = true) +@TestProfile(IntegrationTestProfile.class) @TestHTTPEndpoint(TerminalsResource.class) @TestInstance(TestInstance.Lifecycle.PER_CLASS) class SubscribeResourceTestIT { + static final Logger logger = LoggerFactory.getLogger(SubscribeResourceTestIT.class); + final static String SESSION_ID = "a6a666e6-97da-4848-b568-99fedccb642c"; final static String API_VERSION = "1.0.0-alpha-a.b-c-somethinglong+build.1-aef.1-its-okay"; final static String PA_TAX_CODE = "15376371009"; final static String SUBSCRIBER_ID = "a25tr0"; + DevServicesContext devServicesContext; + + MongoClient mongoClient; + + CodecRegistry pojoCodecRegistry; + Map commonHeaders; Map presetHeaders; @BeforeAll void createTestObjects() { + + // initialize mongo client + pojoCodecRegistry = CodecRegistries.fromRegistries(MongoClientSettings.getDefaultCodecRegistry(), + CodecRegistries.fromProviders(PojoCodecProvider.builder().automatic(true).build())); + + String mongoExposedPort = devServicesContext.devServicesProperties().get("test.mongo.exposed-port"); + mongoClient = MongoClients.create("mongodb://127.0.0.1:" + mongoExposedPort); + + List subscriberIdList = List.of( + + SubscriberTestData.UNSUBCRIBE + ); + List subscriberEntityEntities = subscriberIdList.stream() + .map(subId -> SubscriberTestData.getSubscribers(subId)) + .toList(); + + + MongoCollection collection = mongoClient.getDatabase("mil") + .getCollection("subscribers", SubscriberEntity.class) + .withCodecRegistry(pojoCodecRegistry); + + collection.insertMany(subscriberEntityEntities); + presetHeaders = new HashMap<>(); presetHeaders.put("RequestId", "d0d654e6-97da-4848-b568-99fedccb642b"); presetHeaders.put("Version", API_VERSION); @@ -39,141 +92,152 @@ void createTestObjects() { commonHeaders.put("Channel", "POS"); commonHeaders.put("TerminalId", "0aB9wXyZ"); commonHeaders.put("SessionId", SESSION_ID); - commonHeaders.put("MerchantId", "4585625"); + commonHeaders.put("MerchantId", "23533"); + } + + + @AfterAll + void destroyTestObjects() { + + try { + mongoClient.close(); + } catch (Exception e){ + logger.error("Error while closing mongo client", e); + } + + } + + + /* **** get Subscribers **** */ + @Test + void getSubscribers_200() { + + + Response response = given() + .contentType(ContentType.JSON) + .headers(presetHeaders) + .and() + .when() + .get("/" + PA_TAX_CODE) + .then() + .extract() + .response(); + + Assertions.assertEquals(200, response.statusCode()); + + Assertions.assertNotNull(response.jsonPath().getJsonObject("subscribers")); + List res = response.jsonPath().getList("subscribers", Subscriber.class); + Assertions.assertNotNull(res.get(0).getChannel()); + Assertions.assertNotNull(res.get(0).getMerchantId()); + Assertions.assertNotNull(res.get(0).getTerminalId()); + Assertions.assertNotNull(res.get(0).getPaTaxCode()); + Assertions.assertNotNull(res.get(0).getSubscriberId()); + Assertions.assertNotNull(res.get(0).getLabel()); + Assertions.assertNotNull(res.get(0).getSubscriptionTimestamp()); + Assertions.assertNotNull(res.get(0).getLastUsageTimestamp()); + } + + @Test + void getSubscribers_200_emptyListOfSubribers() { + + Response response = given() + .contentType(ContentType.JSON) + .headers(presetHeaders) + .and() + .when() + .get("/" + "00000000000") + .then() + .extract() + .response(); + + Assertions.assertEquals(200, response.statusCode()); + + Assertions.assertNotNull(response.jsonPath().getJsonObject("subscribers")); + List res = response.jsonPath().getList("subscribers", Subscriber.class); + + Assertions.assertEquals(0,res.size()); + } -// -// /* **** get Subscribers **** */ -// @Test -// void getSubscribers_200() { -// -// -// Response response = given() -// .contentType(ContentType.JSON) -// .headers(presetHeaders) -// .and() -// .when() -// .get("/" + PA_TAX_CODE) -// .then() -// .extract() -// .response(); -// -// Assertions.assertEquals(200, response.statusCode()); -// -// Assertions.assertNotNull(response.jsonPath().getJsonObject("subscribers")); -// List res = response.jsonPath().getList("subscribers", SubscriberResponse.class); -// System.out.println("RESPONSE " + res); -// System.out.println("RESPONSE size " + res.size()); -// Assertions.assertNotNull(res.get(0).getChannel()); -// Assertions.assertNotNull(res.get(0).getMerchantId()); -// Assertions.assertNotNull(res.get(0).getTerminalId()); -// Assertions.assertNotNull(res.get(0).getPaTaxCode()); -// Assertions.assertNotNull(res.get(0).getSubscriberId()); -// Assertions.assertNotNull(res.get(0).getLabel()); -// Assertions.assertNotNull(res.get(0).getSubscriptionTimestamp()); -// Assertions.assertNotNull(res.get(0).getLastUsageTimestamp()); -// } -// -// @Test -// void getSubscribers_200_emptyListOfSubribers() { -// -// Response response = given() -// .contentType(ContentType.JSON) -// .headers(presetHeaders) -// .and() -// .when() -// .get("/" + "00000000000") -// .then() -// .extract() -// .response(); -// -// Assertions.assertEquals(200, response.statusCode()); -// -// Assertions.assertNotNull(response.jsonPath().getJsonObject("subscribers")); -// List res = response.jsonPath().getList("subscribers", SubscriberResponse.class); -// -// Assertions.assertEquals(0,res.size()); -// -// } -// -// /* **** unsubscribe **** */ -// @Test -// void unsubscriber_200() { -// -// Response response = given() -// .contentType(ContentType.JSON) -// .headers(commonHeaders) -// .and() -// .when() -// .delete("/11111111111/a25tr0") -// .then() -// .extract() -// .response(); -// -// Assertions.assertEquals(204, response.statusCode()); -// Assertions.assertEquals(0,response.body().asString().length()); -// } -// -// @Test -// void unsubscriber_404() { -// -// Response response = given() -// .contentType(ContentType.JSON) -// .headers(commonHeaders) -// .and() -// .when() -// .delete("/" + PA_TAX_CODE + "/a00aa0") -// .then() -// .extract() -// .response(); -// -// Assertions.assertEquals(404, response.statusCode()); -// Assertions.assertEquals(0,response.body().asString().length()); -// } -// -// /* **** subscribe **** */ -// @Test -// void subscribe_200() { -// -// SubscriberRequest request = new SubscriberRequest(); -// request.setPaTaxCode("34576371029"); -// request.setLabel("Reception POS"); -// -// Response response = given() -// .contentType(ContentType.JSON) -// .headers(commonHeaders) -// .body(request) -// .and() -// .when() -// .post() -// .then() -// .extract() -// .response(); -// -// Assertions.assertEquals(201, response.statusCode()); -// Assertions.assertEquals(0,response.body().asString().length()); -// Assertions.assertNotNull(response.getHeader(SubscribeResource.LOCATION)); -// } -// @Test -// void subscribe_409() { -// -// SubscriberRequest request = new SubscriberRequest(); -// request.setPaTaxCode("15376371009"); -// request.setLabel("Reception POS"); -// -// Response response = given() -// .contentType(ContentType.JSON) -// .headers(commonHeaders) -// .body(request) -// .and() -// .when() -// .post() -// .then() -// .extract() -// .response(); -// -// Assertions.assertEquals(409, response.statusCode()); -// Assertions.assertTrue(response.jsonPath().getList("errors").contains(ErrorCode.ERROR_CONFLICT_TERMINAL_IN_DB)); -// Assertions.assertNotNull(response.getHeader(SubscribeResource.LOCATION)); -// } + /* **** unsubscribe **** */ + @Test + void unsubscriber_200() { + + Response response = given() + .contentType(ContentType.JSON) + .headers(commonHeaders) + .and() + .when() + .delete("/15376371009/" + SubscriberTestData.UNSUBCRIBE) + .then() + .extract() + .response(); + + Assertions.assertEquals(204, response.statusCode()); + Assertions.assertEquals(0,response.body().asString().length()); + } + + @Test + void unsubscriber_404() { + + Response response = given() + .contentType(ContentType.JSON) + .headers(commonHeaders) + .and() + .when() + .delete("/" + PA_TAX_CODE + "/a00aa0") + .then() + .extract() + .response(); + + Assertions.assertEquals(404, response.statusCode()); + Assertions.assertEquals(0,response.body().asString().length()); + } + + /* **** subscribe **** */ + @Test + void subscribe_200() { + + SubscribeRequest request = new SubscribeRequest(); + request.setPaTaxCode("34576371029"); + request.setLabel("Reception POS"); + + Response response = given() + .contentType(ContentType.JSON) + .headers(commonHeaders) + .body(request) + .and() + .when() + .post() + .then() + .extract() + .response(); + + Assertions.assertEquals(201, response.statusCode()); + Assertions.assertEquals(0,response.body().asString().length()); + final String locationPath = "/terminals/34576371029/" ; + Assertions.assertTrue(response.getHeader("Location") != null && response.getHeader("Location").contains(locationPath)); + } + @Test + void subscribe_409() { + + SubscribeRequest request = new SubscribeRequest(); + request.setPaTaxCode("15376371009"); + request.setLabel("Reception POS"); + + Response response = given() + .contentType(ContentType.JSON) + .headers(commonHeaders) + .body(request) + .and() + .when() + .post() + .then() + .extract() + .response(); + + Assertions.assertEquals(409, response.statusCode()); + final String locationPath = "/terminals/15376371009/" ; + Assertions.assertTrue(response.getHeader("Location") != null && response.getHeader("Location").contains(locationPath)); + } } diff --git a/src/test/java/it/pagopa/swclient/mil/preset/resource/MongoTestResource.java b/src/test/java/it/pagopa/swclient/mil/preset/resource/MongoTestResource.java index 1dd5d07..6fb02ff 100644 --- a/src/test/java/it/pagopa/swclient/mil/preset/resource/MongoTestResource.java +++ b/src/test/java/it/pagopa/swclient/mil/preset/resource/MongoTestResource.java @@ -52,13 +52,16 @@ public Map start() { final Integer exposedPort = mongoContainer.getMappedPort(27017); devServicesContext.devServicesProperties().put("test.mongo.exposed-port", exposedPort.toString()); - try { - ExecResult result = mongoContainer.execInContainer("mongosh", "<", "/home/mongo/mongoInit.js"); - logger.info("Init script result {}", result); - } - catch (Exception e) { - logger.error("Error while importing data into DB", e); - } +// try { +// ExecResult ls = mongoContainer.execInContainer("ls", "-lrt", "/home/mongo/"); +// logger.info("ls {}", ls); +// +// ExecResult result = mongoContainer.execInContainer("mongosh", "<", "/home/mongo/mongoInit.js"); +// logger.info("Init script result {}", result); +// } +// catch (Exception e) { +// logger.error("Error while importing data into DB", e); +// } // Pass the configuration to the application under test return ImmutableMap.of( diff --git a/src/test/java/it/pagopa/swclient/mil/preset/resource/RedpandaTestResource.java b/src/test/java/it/pagopa/swclient/mil/preset/resource/RedpandaTestResource.java index 2ad14b8..665057b 100644 --- a/src/test/java/it/pagopa/swclient/mil/preset/resource/RedpandaTestResource.java +++ b/src/test/java/it/pagopa/swclient/mil/preset/resource/RedpandaTestResource.java @@ -1,18 +1,20 @@ package it.pagopa.swclient.mil.preset.resource; -import com.google.common.collect.ImmutableMap; -import io.quarkus.test.common.DevServicesContext; -import io.quarkus.test.common.QuarkusTestResourceLifecycleManager; +import java.util.Map; + import org.junit.runner.Description; import org.junit.runners.model.Statement; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.testcontainers.containers.Container.ExecResult; import org.testcontainers.containers.Network; -import org.testcontainers.containers.output.Slf4jLogConsumer; import org.testcontainers.redpanda.RedpandaContainer; import org.testcontainers.utility.DockerImageName; -import java.util.Map; +import com.google.common.collect.ImmutableMap; + +import io.quarkus.test.common.DevServicesContext; +import io.quarkus.test.common.QuarkusTestResourceLifecycleManager; public class RedpandaTestResource implements QuarkusTestResourceLifecycleManager, DevServicesContext.ContextAware { @@ -36,19 +38,59 @@ public Map start() { logger.info("Starting Redpanda container..."); // this version of testcontainers is not compatible with redpandadata/redpanda - DockerImageName myImage = DockerImageName.parse("redpandadata/redpanda:v23.1.9").asCompatibleSubstituteFor("docker.redpanda.com/vectorized/redpanda"); + DockerImageName myImage = DockerImageName.parse("redpandadata/redpanda:v23.1.9") + .asCompatibleSubstituteFor("docker.redpanda.com/vectorized/redpanda"); redpandaContainer = new CustomRedpandaContainer(myImage); redpandaContainer .withNetwork(getNetwork()) .withNetworkAliases(REDPANDA_NETWORK_ALIAS); - redpandaContainer.withLogConsumer(new Slf4jLogConsumer(logger)); - +// redpandaContainer.withLogConsumer(new Slf4jLogConsumer(logger)); + + + //redpandaContainer.withFileSystemBind("./src/test/resources/it/mongo", "/home/mongo"); //redpandaContainer.setCommand("--verbose"); redpandaContainer.start(); - + + try { + ExecResult result = redpandaContainer.execInContainer("rpk", "cluster", "config", "set", "enable_sasl", "true"); + logger.info("1>>>>>>>>>>>>>>>>>>>>>!!!!!!!!!!!!!!!><: {}", result.toString()); + result = redpandaContainer.execInContainer( "rpk", "acl", "user", "create", "admin", "-p", "12345678"); + logger.info("2>>>>>>>>>>>>>>>>>>>>>!!!!!!!!!!!!!!!><: {}", result.toString()); + result = redpandaContainer.execInContainer( "rpk", "cluster", "config", "set", "superusers", "['admin']"); + + logger.info("3>>>>>>>>>>>>>>>>>>>>>!!!!!!!!!!!!!!!><: {}", result.toString()); + result = redpandaContainer.execInContainer("rpk", "acl", "user", "create", "testuser", "-p", "testuser"); + logger.info("4>>>>>>>>>>>>>>>>>>>>>!!!!!!!!!!!!!!!><: {}", result.toString()); + result = redpandaContainer.execInContainer("rpk", "acl", "create", "--allow-principal", "*", "--operation", "all", + "--topic", "presets", "--user", "admin", "--password", "12345678", "--sasl-mechanism", "SCRAM-SHA-256" ); + + logger.info("5>>>>>>>>>>>>>>>>>>>>>!!!!!!!!!!!!!!!><: {}", result.toString()); + + +// String stdout = result.getStdout(); + + }catch (Exception e) { + logger.error(">>>>>>>>>>>>>>>>>>>!!!!!!!!!!!!11>Error ",e); + } +// try { +//// ExecResult result = redpandaContainer.execInContainer("bash", "rpk", "cluster", "config", "set", "superusers", "['admin']"); +//// logger.info(">>>>>>>>>>>>>>>>>>>>>><: {}", result.toString()); +// +// +// +// +// +//// result = redpandaContainer.execInContainer("rpk", "acl", "create", "--allow-principal", "User:testuser", "--operation", "create,describe", +//// "--cluster", "--user", "suname", "--password", "12345678", "--sasl-mechanism", "SCRAM-SHA-256"); +//// logger.info(">>>>>>>>>>>>>>>>>>>>>!!!!!!!!!!!!!!!><: {}", result.toString()); +//// String stdout = result.getStdout(); +// +// }catch (Exception e) { +// logger.error(">>>>>>>>>>>>>>>>>>>>Error ",e); +// } final Integer exposedPort = redpandaContainer.getMappedPort(9092); final String bootstrapServers = redpandaContainer.getBootstrapServers(); logger.info("Redpanda bootstrap servers: {}", bootstrapServers); @@ -60,7 +102,10 @@ public Map start() { // Pass the configuration to the application under test return ImmutableMap.of( - "kafka-bootstrap-server", REDPANDA_NETWORK_ALIAS + ":" + 29092 + "kafka-bootstrap-server", REDPANDA_NETWORK_ALIAS + ":" + 29092, + "kafka-security-protocol", "SASL_PLAINTEXT", + "kafka-sasl-mechanism","SCRAM-SHA-256", + "kafka-sasl-jaas-config","org.apache.kafka.common.security.scram.ScramLoginModule required username=\"testuser\" password=\"testuser\";" ); } catch (Exception e) { logger.error("Error while starting redpanda", e); @@ -94,6 +139,7 @@ public Statement apply(Statement statement, Description description) { public void stop() { if (null != redpandaContainer) { logger.info("Stopping Redpanda container..."); + redpandaContainer.stop(); logger.info("Redpanda container stopped"); } diff --git a/src/test/java/it/pagopa/swclient/mil/preset/util/SubscriberTestData.java b/src/test/java/it/pagopa/swclient/mil/preset/util/SubscriberTestData.java new file mode 100644 index 0000000..526b042 --- /dev/null +++ b/src/test/java/it/pagopa/swclient/mil/preset/util/SubscriberTestData.java @@ -0,0 +1,31 @@ +/** + * + */ +package it.pagopa.swclient.mil.preset.util; + +import it.pagopa.swclient.mil.preset.bean.Subscriber; +import it.pagopa.swclient.mil.preset.dao.SubscriberEntity; + +public class SubscriberTestData { + public static final String SUBCRIBER_FOUND = "x46tr0"; + public static final String SUBCRIBER_NOT_FOUND = "aaaaaa"; + public static final String UNSUBCRIBE = "bbbbbb"; + + public static SubscriberEntity getSubscribers(String subscriberId) { + SubscriberEntity subscriberEntity = new SubscriberEntity(); + Subscriber subscriber = new Subscriber(); + subscriber.setAcquirerId("4585625"); + subscriber.setChannel("POS"); + subscriber.setLabel("test label"); + subscriber.setLastUsageTimestamp("2023-05-17T14:50:05.446"); + subscriber.setMerchantId("23533"); + subscriber.setPaTaxCode("15376371009"); + subscriber.setSubscriberId(subscriberId); + subscriber.setSubscriptionTimestamp("2023-05-17T14:50:05.446"); + subscriber.setTerminalId("0aB9wXyZ"); + + subscriberEntity.subscriber = subscriber; + subscriberEntity.id = subscriberId; + return subscriberEntity; + } +} From 10dc8e2c9ce356e2b85b818b3cee04a9f0e6d793 Mon Sep 17 00:00:00 2001 From: "d.sabatini" Date: Tue, 6 Jun 2023 14:46:55 +0200 Subject: [PATCH 6/9] Fixed SonarLint issues, added kafka container for integration test --- pom.xml | 12 +- .../mil/preset/bean/SubscribeRequest.java | 1 - .../preset/resource/PresetTopicResource.java | 13 +- .../mil/preset/resource/PresetsResource.java | 45 +++--- .../preset/resource/TerminalsResource.java | 4 - src/main/resources/application.properties | 31 ++-- .../mil/preset/it/IntegrationTestProfile.java | 3 +- .../preset/it/PresetTopicResourceTestIT.java | 49 +++---- .../resource/CustomRedpandaContainer.java | 7 +- .../preset/resource/KafkaTestResource.java | 138 ++++++++++++++++++ .../preset/resource/MongoTestResource.java | 2 +- .../preset/resource/RedpandaTestResource.java | 89 ++++------- .../preset/resource/WiremockTestResource.java | 97 ++++++++++++ 13 files changed, 335 insertions(+), 156 deletions(-) create mode 100644 src/test/java/it/pagopa/swclient/mil/preset/resource/KafkaTestResource.java create mode 100644 src/test/java/it/pagopa/swclient/mil/preset/resource/WiremockTestResource.java diff --git a/pom.xml b/pom.xml index a56a13a..703c7b7 100644 --- a/pom.xml +++ b/pom.xml @@ -17,7 +17,7 @@ UTF-8 quarkus-bom io.quarkus.platform - 3.0.2.Final + 3.1.0.Final 2.0.1 true @@ -82,11 +82,6 @@ io.quarkus quarkus-smallrye-reactive-messaging-kafka - io.smallrye.reactive smallrye-reactive-messaging-in-memory @@ -132,6 +127,11 @@ awaitility test + + com.nimbusds + nimbus-jose-jwt + test + diff --git a/src/main/java/it/pagopa/swclient/mil/preset/bean/SubscribeRequest.java b/src/main/java/it/pagopa/swclient/mil/preset/bean/SubscribeRequest.java index 5c41cc7..35fc797 100644 --- a/src/main/java/it/pagopa/swclient/mil/preset/bean/SubscribeRequest.java +++ b/src/main/java/it/pagopa/swclient/mil/preset/bean/SubscribeRequest.java @@ -5,7 +5,6 @@ import it.pagopa.swclient.mil.preset.ErrorCode; import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Null; import jakarta.validation.constraints.Pattern; public class SubscribeRequest { diff --git a/src/main/java/it/pagopa/swclient/mil/preset/resource/PresetTopicResource.java b/src/main/java/it/pagopa/swclient/mil/preset/resource/PresetTopicResource.java index ffdebaf..f4138a2 100644 --- a/src/main/java/it/pagopa/swclient/mil/preset/resource/PresetTopicResource.java +++ b/src/main/java/it/pagopa/swclient/mil/preset/resource/PresetTopicResource.java @@ -6,7 +6,6 @@ import io.smallrye.mutiny.unchecked.Unchecked; import it.pagopa.swclient.mil.preset.PresetStatus; import it.pagopa.swclient.mil.preset.bean.PaymentTransaction; -import it.pagopa.swclient.mil.preset.bean.PaymentTransactionStatus; import it.pagopa.swclient.mil.preset.dao.PresetEntity; import it.pagopa.swclient.mil.preset.dao.PresetRepository; import it.pagopa.swclient.mil.preset.utils.DateUtils; @@ -35,12 +34,8 @@ public void consume(PaymentTransaction paymentTransaction) { .chain(entity -> updatePreset(paymentTransaction, entity)) .subscribe() .with( - item -> { - Log.debugf("Item updated %s", item); - }, - error -> { - Log.debugf("Error while updating item", error); - } + item -> Log.debugf("Item updated %s", item), + error -> Log.debugf("Error while updating item", error) ); } @@ -82,9 +77,7 @@ private Uni findPresetsOperation(PaymentTransaction paymentTransac private Uni updatePreset(PaymentTransaction inputPaymentTransaction, PresetEntity presetEntity) { Log.debugf("Updating Preset"); - //if (!PaymentTransactionStatus.PRE_CLOSE.name().equals(inputPaymentTransaction.getStatus())) { - presetEntity.presetOperation.setStatus(PresetStatus.EXECUTED.name()); - //} + presetEntity.presetOperation.setStatus(PresetStatus.EXECUTED.name()); presetEntity.presetOperation.setStatusTimestamp(DateUtils.getCurrentTimestamp()); presetEntity.presetOperation.setStatusDetails(inputPaymentTransaction); diff --git a/src/main/java/it/pagopa/swclient/mil/preset/resource/PresetsResource.java b/src/main/java/it/pagopa/swclient/mil/preset/resource/PresetsResource.java index 68b7175..573ed5e 100644 --- a/src/main/java/it/pagopa/swclient/mil/preset/resource/PresetsResource.java +++ b/src/main/java/it/pagopa/swclient/mil/preset/resource/PresetsResource.java @@ -46,6 +46,8 @@ public class PresetsResource { public static final String PRESET_FILTER = "presetOperation.paTaxCode = :paTaxCode and presetOperation.subscriberId = :subscriberId"; public static final String LAST_PRESET_FILTER = PRESET_FILTER + " and presetOperation.status = 'TO_EXECUTE'"; + public static final String PA_TAX_CODE = "paTaxCode"; + public static final String SUBSCRIBER_ID = "subscriberId"; /** * The base URL for the location header returned by the createPreset API (i.e. the API management base URL) @@ -161,14 +163,8 @@ public Uni getLastPresetsOperation(@Valid @BeanParam CommonHeader head */ private Uni findSubscriber(String paTaxCode, String subscriberId) { - return subscriberRepository.list(SUBSCRIBER_FILTER, Parameters.with("paTaxCode", paTaxCode).and("subscriberId", subscriberId).map()) - .onFailure().transform(err -> { - Log.errorf(err, "[%s] Error while retrieving data from DB", ErrorCode.ERROR_READING_DATA_FROM_DB); - return new InternalServerErrorException( - Response.status(Status.INTERNAL_SERVER_ERROR) - .entity(new Errors(List.of(ErrorCode.ERROR_READING_DATA_FROM_DB))) - .build()); - }) + return subscriberRepository.list(SUBSCRIBER_FILTER, Parameters.with(PA_TAX_CODE, paTaxCode).and(SUBSCRIBER_ID, subscriberId).map()) + .onFailure().transform(PresetsResource::manageDbReadError) .map(entityList -> entityList.isEmpty() ? null : entityList.get(0)); } @@ -181,14 +177,8 @@ private Uni findSubscriber(String paTaxCode, String subscriber */ private Uni> findPresetOperations(String paTaxCode, String subscriberId) { - return presetRepository.list(PRESET_FILTER, Parameters.with("paTaxCode", paTaxCode).and("subscriberId", subscriberId).map()) - .onFailure().transform(err -> { - Log.errorf(err, "[%s] Error while retrieving data from DB", ErrorCode.ERROR_READING_DATA_FROM_DB); - return new InternalServerErrorException( - Response.status(Status.INTERNAL_SERVER_ERROR) - .entity(new Errors(List.of(ErrorCode.ERROR_READING_DATA_FROM_DB))) - .build()); - }) + return presetRepository.list(PRESET_FILTER, Parameters.with(PA_TAX_CODE, paTaxCode).and(SUBSCRIBER_ID, subscriberId).map()) + .onFailure().transform(PresetsResource::manageDbReadError) .map(entities -> entities.stream().map(entity -> entity.presetOperation).toList()); } @@ -204,23 +194,15 @@ private Uni findLatestPresetOperation(String paTaxCode, String return presetRepository.find(LAST_PRESET_FILTER, Sort.by("presetOperation.creationTimestamp").descending(), Parameters - .with("paTaxCode", paTaxCode) - .and("subscriberId", subscriberId) + .with(PA_TAX_CODE, paTaxCode) + .and(SUBSCRIBER_ID, subscriberId) .map() ) .firstResult() - .onFailure().transform(err -> { - Log.errorf(err, "[%s] Error while retrieving data from DB", ErrorCode.ERROR_READING_DATA_FROM_DB); - return new InternalServerErrorException( - Response.status(Status.INTERNAL_SERVER_ERROR) - .entity(new Errors(List.of(ErrorCode.ERROR_READING_DATA_FROM_DB))) - .build()); - } - ) + .onFailure().transform(PresetsResource::manageDbReadError) .map(presetEntity -> presetEntity != null ? presetEntity.presetOperation : null); } - /** * Update the subscriber info * @@ -308,4 +290,13 @@ private URI buildLocationPath(String paTaxCode, String subscriberId, String pres location.append(presetId); return URI.create(presetLocationBaseURL + location.toString()); } + + private static InternalServerErrorException manageDbReadError(Throwable err) { + Log.errorf(err, "[%s] Error while retrieving data from DB", ErrorCode.ERROR_READING_DATA_FROM_DB); + return new InternalServerErrorException( + Response.status(Status.INTERNAL_SERVER_ERROR) + .entity(new Errors(List.of(ErrorCode.ERROR_READING_DATA_FROM_DB))) + .build()); + } + } diff --git a/src/main/java/it/pagopa/swclient/mil/preset/resource/TerminalsResource.java b/src/main/java/it/pagopa/swclient/mil/preset/resource/TerminalsResource.java index 2be3493..7d4431f 100644 --- a/src/main/java/it/pagopa/swclient/mil/preset/resource/TerminalsResource.java +++ b/src/main/java/it/pagopa/swclient/mil/preset/resource/TerminalsResource.java @@ -48,9 +48,6 @@ public class TerminalsResource { @Inject SubscriberRepository subscriberRepository; -// @Inject -// JsonWebToken jwt; - /** * The base URL for the location header returned by the subscribe API (i.e. the API management base URL) */ @@ -65,7 +62,6 @@ public class TerminalsResource { */ @GET @Path("/{paTaxCode}") -// @RolesAllowed({ "InstitutionPortal" }) @Produces(MediaType.APPLICATION_JSON) public Uni getSubscribers(@Valid @BeanParam InstitutionPortalHeaders portalHeaders, diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 59c640b..26db7bc 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,4 +1,4 @@ -uarkus.banner.enabled=false +quarkus.banner.enabled=false # ------------------------------------------------------------------------------ # Logging configuration @@ -8,20 +8,15 @@ uarkus.banner.enabled=false # ------------------------------------------------------------------------------ quarkus.log.console.format=%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{requestId}] [%p] [%c{2}] %m%n -quarkus.log.min-level=DEBUG -#%dev.quarkus.log.level=DEBUG +%dev.quarkus.log.level=INFO %dev.quarkus.log.category."it.pagopa.swclient.mil.preset".level=DEBUG -%playground.quarkus.log.level=ERROR -%playground.quarkus.log.category."it.pagopa.swclient.mil.preset".level=DEBUG - %test.quarkus.log.level=DEBUG %test.quarkus.log.category."it.pagopa.swclient.mil.preset".level=DEBUG %prod.quarkus.log.level=${preset.quarkus-log-level} %prod.quarkus.log.category."it.pagopa.swclient.mil.preset".level=${preset.app-log-level} - # ------------------------------------------------------------------------------ # DB configuration # @@ -46,28 +41,28 @@ quarkus.log.min-level=DEBUG %prod.quarkus.mongodb.connection-string=${mongo-connection-string-1},${mongo-connection-string-2} # ------------------------------------------------------------------------------ -# Kafka / Azure Event Bus configuration +# Kafka / Azure Event Bus configuration (see https://quarkus.io/guides/kafka#azure-event-hub) # -# mongo-connect-timeout = 5s -# mongo-read-timeout = 10s -# mongo-server-selection-timeout = 5s +# kafka.bootstrap.servers=.servicebus.windows.net:9093 +# kafka.security.protocol=SASL_SSL +# kafka.sasl.mechanism=PLAIN +# kafka.sasl.jaas.config=org.apache.kafka.common.security.plain.PlainLoginModule required username="$ConnectionString" password=""; # ------------------------------------------------------------------------------ mp.messaging.incoming.presets.connector=smallrye-kafka mp.messaging.incoming.presets.group.id=preset-processor -quarkus.kafka.devservices.enabled=false - - -%dev.kafka.bootstrap.servers=milops.servicebus.windows.net:9093 +%dev.kafka.bootstrap.servers=milops.servicebus.windows.net:9093 %dev.kafka.security.protocol=SASL_SSL %dev.kafka.sasl.mechanism=PLAIN %dev.kafka.sasl.jaas.config=org.apache.kafka.common.security.plain.PlainLoginModule required username="" password=""; +%test.kafka.bootstrap.servers=localhost:2024 +quarkus.kafka.devservices.enabled=false + %prod.kafka.bootstrap.servers=${kafka-bootstrap-server} %prod.kafka.security.protocol=${kafka-security-protocol} %prod.kafka.sasl.mechanism=${kafka-sasl-mechanism} -%prod.kafka.sasl.jaas.config=${kafka-sasl-jaas-config} # ------------------------------------------------------------------------------ # JWT RBAC configurations @@ -77,13 +72,11 @@ quarkus.kafka.devservices.enabled=false #%test.mp.jwt.verify.publickey.location=http://localhost:8088/realms/mil-test/protocol/openid-connect/certs #%prod.mp.jwt.verify.publickey.location=${jwt-publickey-location} - # ------------------------------------------------------------------------------ # Service configurations # ------------------------------------------------------------------------------ %dev.preset.location.base-url=https://mil-d-apim.azure-api.net/mil-preset %test.preset.location.base-url=https://mil-d-apim.azure-api.net/mil-preset -%prod.preset.location.base-url=https://mil-d-apim.azure-api.net/mil-preset +%prod.preset.location.base-url=${preset.location.base-url} -quarkus.log.category."io.quarkus.mongodb.panache.runtime".level=DEBUG diff --git a/src/test/java/it/pagopa/swclient/mil/preset/it/IntegrationTestProfile.java b/src/test/java/it/pagopa/swclient/mil/preset/it/IntegrationTestProfile.java index a2992db..55f0f08 100644 --- a/src/test/java/it/pagopa/swclient/mil/preset/it/IntegrationTestProfile.java +++ b/src/test/java/it/pagopa/swclient/mil/preset/it/IntegrationTestProfile.java @@ -19,6 +19,7 @@ public Map getConfigOverrides() { configOverrides.put("preset.quarkus-log-level", "INFO"); configOverrides.put("preset.app-log-level", "DEBUG"); + configOverrides.put("preset.location.base-url", "https://mil-d-apim.azure-api.net/mil-payment-notice"); return configOverrides; } @@ -26,7 +27,7 @@ public Map getConfigOverrides() { @Override public List testResources() { return ImmutableList.of( - new TestResourceEntry(MongoTestResource.class) , + new TestResourceEntry(MongoTestResource.class), new TestResourceEntry(RedpandaTestResource.class) ); } diff --git a/src/test/java/it/pagopa/swclient/mil/preset/it/PresetTopicResourceTestIT.java b/src/test/java/it/pagopa/swclient/mil/preset/it/PresetTopicResourceTestIT.java index 12e4dcc..a0fbf7c 100644 --- a/src/test/java/it/pagopa/swclient/mil/preset/it/PresetTopicResourceTestIT.java +++ b/src/test/java/it/pagopa/swclient/mil/preset/it/PresetTopicResourceTestIT.java @@ -49,8 +49,27 @@ import it.pagopa.swclient.mil.preset.dao.PresetEntity; import it.pagopa.swclient.mil.preset.util.PresetTestData; import it.pagopa.swclient.mil.preset.utils.DateUtils; +import org.apache.kafka.clients.producer.KafkaProducer; +import org.apache.kafka.clients.producer.ProducerRecord; +import org.apache.kafka.common.serialization.StringSerializer; +import org.bson.codecs.configuration.CodecRegistries; +import org.bson.codecs.configuration.CodecRegistry; +import org.bson.codecs.pojo.PojoCodecProvider; +import org.bson.conversions.Bson; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testcontainers.shaded.org.awaitility.Awaitility; + +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; +import java.util.UUID; -@Disabled @QuarkusIntegrationTest @TestProfile(IntegrationTestProfile.class) @TestInstance(TestInstance.Lifecycle.PER_CLASS) @@ -84,11 +103,6 @@ void createTestData() { // initialize kafka producer Properties kafkaConfig = new Properties(); kafkaConfig.put("bootstrap.servers", devServicesContext.devServicesProperties().get("test.kafka.bootstrap-server")); -// kafkaConfig.put("bootstrap.servers", "localhost:19092"); - kafkaConfig.put("security.protocol", "SASL_PLAINTEXT"); - kafkaConfig.put("sasl.mechanism","SCRAM-SHA-256"); - kafkaConfig.put("sasl.jaas.config","org.apache.kafka.common.security.scram.ScramLoginModule required username=\"testuser\" password=\"testuser\";"); - kafkaConfig.put("linger.ms", 1); paymentTransactionProducer = new KafkaProducer<>(kafkaConfig, new StringSerializer(), new ObjectMapperSerializer<>()); @@ -114,28 +128,11 @@ void consume_close_ok() { String currentTimestamp = DateUtils.getCurrentTimestamp(); - logger.info("-------------------------------------------------------------------"); - Future resp = paymentTransactionProducer.send(new ProducerRecord<>("presets", paymentTransaction)); - - try { - RecordMetadata r = resp.get(10, TimeUnit.SECONDS); - - logger.info("DONE {}", resp.isDone()); - logger.info("TOPIC {}", r.topic()); - } catch (InterruptedException e) { - e.printStackTrace(); - } catch (ExecutionException e) { - e.printStackTrace(); - } catch (TimeoutException e) { - e.printStackTrace(); - } + paymentTransactionProducer.send(new ProducerRecord<>("presets", paymentTransaction)); - logger.info("-------------------------------------------------------------------"); - - Awaitility.await().pollDelay(Duration.ofSeconds(2)).until(() -> { + Awaitility.await().until(() -> { PresetOperation presetOperation = getPresetOperation(presetId); -// return presetOperation.getStatusTimestamp().compareTo(currentTimestamp) > 0; - return presetOperation.getStatus().equals(PresetStatus.EXECUTED.name()); + return presetOperation.getStatusTimestamp().compareTo(currentTimestamp) > 0; }); checkDatabaseData(presetId, PresetStatus.EXECUTED, paymentTransaction); diff --git a/src/test/java/it/pagopa/swclient/mil/preset/resource/CustomRedpandaContainer.java b/src/test/java/it/pagopa/swclient/mil/preset/resource/CustomRedpandaContainer.java index 5710f23..9008c5a 100644 --- a/src/test/java/it/pagopa/swclient/mil/preset/resource/CustomRedpandaContainer.java +++ b/src/test/java/it/pagopa/swclient/mil/preset/resource/CustomRedpandaContainer.java @@ -25,9 +25,12 @@ protected void containerIsStarting(InspectContainerResponse containerInfo) { logger.info("getNetworkAliases() -> {}", this.getNetworkAliases()); String command = "#!/bin/bash\n"; + // command = command + "/usr/bin/rpk redpanda start --mode dev-container "; + // command = command + " --kafka-addr SASL_PLAINTEXT://0.0.0.0:29092,OUTSIDE://0.0.0.0:9092 "; + // command = command + " --advertise-kafka-addr SASL_PLAINTEXT://" + this.getNetworkAliases().get(this.getNetworkAliases().size()-1) + ":29092,OUTSIDE://" + this.getHost() + ":" + this.getMappedPort(9092); command = command + "/usr/bin/rpk redpanda start --mode dev-container "; - command = command + "--kafka-addr PLAINTEXT://0.0.0.0:29092,OUTSIDE://0.0.0.0:9092 "; - command = command + "--advertise-kafka-addr PLAINTEXT://" + this.getNetworkAliases().get(this.getNetworkAliases().size()-1) + ":29092,OUTSIDE://" + this.getHost() + ":" + this.getMappedPort(9092); + command = command + "--kafka-addr PLAINTEXT://0.0.0.0:29092,INTERNAL://0.0.0.0:19092,OUTSIDE://0.0.0.0:9092 "; + command = command + "--advertise-kafka-addr PLAINTEXT://127.0.0.1:29092,INTERNAL://"+this.getNetworkAliases().get(this.getNetworkAliases().size()-1)+":19092,OUTSIDE://" + this.getHost() + ":" + this.getMappedPort(9092); this.copyFileToContainer(Transferable.of(command, 511), "/testcontainers_start.sh"); diff --git a/src/test/java/it/pagopa/swclient/mil/preset/resource/KafkaTestResource.java b/src/test/java/it/pagopa/swclient/mil/preset/resource/KafkaTestResource.java new file mode 100644 index 0000000..817e176 --- /dev/null +++ b/src/test/java/it/pagopa/swclient/mil/preset/resource/KafkaTestResource.java @@ -0,0 +1,138 @@ +package it.pagopa.swclient.mil.preset.resource; + +import com.google.common.collect.ImmutableMap; +import io.quarkus.test.common.DevServicesContext; +import io.quarkus.test.common.QuarkusTestResourceLifecycleManager; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testcontainers.containers.FixedHostPortGenericContainer; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.Network; +import org.testcontainers.containers.output.Slf4jLogConsumer; +import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.images.builder.Transferable; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +public class KafkaTestResource implements QuarkusTestResourceLifecycleManager, DevServicesContext.ContextAware { + + private static final Logger logger = LoggerFactory.getLogger(KafkaTestResource.class); + + private static final String KAFKA_NETWORK_ALIAS = "kafka"; + + private GenericContainer kafkaContainer; + + private DevServicesContext devServicesContext; + + @Override + public void setIntegrationTestContext(DevServicesContext devServicesContext){ + this.devServicesContext = devServicesContext; + } + + @Override + public Map start() { + + try { + logger.info("Starting Kafka container..."); + + Map environmentVariables = new HashMap<>(); + + environmentVariables.put("BITNAMI_DEBUG","true"); + environmentVariables.put("ALLOW_PLAINTEXT_LISTENER", "yes"); + environmentVariables.put("KAFKA_ENABLE_KRAFT", "yes"); + environmentVariables.put("KAFKA_CFG_PROCESS_ROLES", "broker,controller"); + environmentVariables.put("KAFKA_CFG_CONTROLLER_LISTENER_NAMES", "CONTROLLER"); + environmentVariables.put("KAFKA_BROKER_ID", "1"); + environmentVariables.put("KAFKA_CFG_CONTROLLER_QUORUM_VOTERS","1@127.0.0.1:9094"); + environmentVariables.put("KAFKA_CFG_NODE_ID", "1"); + environmentVariables.put("KAFKA_CFG_LISTENERS", "INTERNAL://:9093,CLIENT://:9092,CONTROLLER://:9094,EXTERNAL://:29092"); + environmentVariables.put("KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP", "INTERNAL:SASL_PLAINTEXT,CLIENT:SASL_PLAINTEXT,CONTROLLER:SASL_PLAINTEXT,EXTERNAL:SASL_PLAINTEXT"); + environmentVariables.put("KAFKA_CFG_ADVERTISED_LISTENERS", "INTERNAL://kafka:9093,CLIENT://kafka:9092,EXTERNAL://localhost:29092"); + environmentVariables.put("KAFKA_CFG_INTER_BROKER_LISTENER_NAME", "INTERNAL"); + environmentVariables.put("KAFKA_CFG_SASL_ENABLED_MECHANISMS", "PLAIN"); + environmentVariables.put("KAFKA_CFG_SASL_MECHANISM_INTER_BROKER_PROTOCOL", "PLAIN"); + environmentVariables.put("KAFKA_CFG_SASL_MECHANISM_CONTROLLER_PROTOCOL", "PLAIN"); + environmentVariables.put("KAFKA_CFG_NUM_PARTITIONS", "1"); + + kafkaContainer = new FixedHostPortGenericContainer<>("bitnami/kafka:3.4.0") + .withFixedExposedPort(29092,29092) + .withNetwork(getNetwork()) + .withNetworkAliases(KAFKA_NETWORK_ALIAS) + .withEnv(environmentVariables) + .waitingFor(Wait.forLogMessage(".*Kafka Server started.*", 1)); + + kafkaContainer.withLogConsumer(new Slf4jLogConsumer(logger, true)); + + kafkaContainer.start(); + + logger.info("kafkaContainer.isRunning(): {}", kafkaContainer.isRunning()); + + try { + String config = "sasl.jaas.config=org.apache.kafka.common.security.plain.PlainLoginModule required username=\"user\" password=\"bitnami\";\n"; + config = config + "security.protocol=SASL_PLAINTEXT\n"; + config = config + "sasl.mechanism=PLAIN"; + kafkaContainer.copyFileToContainer(Transferable.of(config, 511), "tmp/config.properties"); + + logger.info(kafkaContainer.execInContainer("/opt/bitnami/kafka/bin/kafka-topics.sh", + "--create", + "--bootstrap-server", "127.0.0.1:9092", + "--replication-factor", "1", + "--partitions", "1", + "--topic", "presets", + "--command-config", "tmp/config.properties").toString()); + } catch (UnsupportedOperationException | IOException | InterruptedException e) { + logger.error("Could not create topic", e); + } + + devServicesContext.devServicesProperties().put("test.kafka.bootstrap-server", "localhost:29092"); + + // Pass the configuration to the application under test + return ImmutableMap.of( + "kafka-bootstrap-server", KAFKA_NETWORK_ALIAS + ":" + 9093, + "kafka-security-protocol", "SASL_PLAINTEXT", + "kafka-sasl-mechanism", "PLAIN", + "kafka-sasl-jaas-config", "org.apache.kafka.common.security.plain.PlainLoginModule required username=\"user\" password=\"bitnami\";" + ); + } + catch (Exception e) { + logger.error("Error while starting kafka", e); + throw e; + } + } + + // create a "fake" network using the same id as the one that will be used by Quarkus + // using the network is the only way to make the withNetworkAliases work + private Network getNetwork() { + logger.info("devServicesContext.containerNetworkId() -> " + devServicesContext.containerNetworkId()); + return new Network() { + @Override + public String getId() { + return devServicesContext.containerNetworkId().orElse(null); + } + + @Override + public void close() { + } + + @Override + public Statement apply(Statement statement, Description description) { + return null; + } + }; + } + + @Override + public void stop() { + if (null != kafkaContainer) { + logger.info("Stopping kafka container..."); + kafkaContainer.stop(); + logger.info("Kafka container stopped"); + } + + } + +} diff --git a/src/test/java/it/pagopa/swclient/mil/preset/resource/MongoTestResource.java b/src/test/java/it/pagopa/swclient/mil/preset/resource/MongoTestResource.java index 6fb02ff..63c77b7 100644 --- a/src/test/java/it/pagopa/swclient/mil/preset/resource/MongoTestResource.java +++ b/src/test/java/it/pagopa/swclient/mil/preset/resource/MongoTestResource.java @@ -43,7 +43,7 @@ public Map start() { //.withNetworkMode(devServicesContext.containerNetworkId().get()) .waitingFor(Wait.forListeningPort()); - mongoContainer.withLogConsumer(new Slf4jLogConsumer(logger)); + mongoContainer.withLogConsumer(new Slf4jLogConsumer(logger, true)); mongoContainer.withFileSystemBind("./src/test/resources/it/mongo", "/home/mongo"); //mongoContainer.setCommand("--verbose"); diff --git a/src/test/java/it/pagopa/swclient/mil/preset/resource/RedpandaTestResource.java b/src/test/java/it/pagopa/swclient/mil/preset/resource/RedpandaTestResource.java index 665057b..ea2842e 100644 --- a/src/test/java/it/pagopa/swclient/mil/preset/resource/RedpandaTestResource.java +++ b/src/test/java/it/pagopa/swclient/mil/preset/resource/RedpandaTestResource.java @@ -1,20 +1,18 @@ package it.pagopa.swclient.mil.preset.resource; -import java.util.Map; - +import com.google.common.collect.ImmutableMap; +import io.quarkus.test.common.DevServicesContext; +import io.quarkus.test.common.QuarkusTestResourceLifecycleManager; import org.junit.runner.Description; import org.junit.runners.model.Statement; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.testcontainers.containers.Container.ExecResult; import org.testcontainers.containers.Network; +import org.testcontainers.containers.output.Slf4jLogConsumer; import org.testcontainers.redpanda.RedpandaContainer; import org.testcontainers.utility.DockerImageName; -import com.google.common.collect.ImmutableMap; - -import io.quarkus.test.common.DevServicesContext; -import io.quarkus.test.common.QuarkusTestResourceLifecycleManager; +import java.util.Map; public class RedpandaTestResource implements QuarkusTestResourceLifecycleManager, DevServicesContext.ContextAware { @@ -46,51 +44,27 @@ public Map start() { .withNetwork(getNetwork()) .withNetworkAliases(REDPANDA_NETWORK_ALIAS); -// redpandaContainer.withLogConsumer(new Slf4jLogConsumer(logger)); - - - - //redpandaContainer.withFileSystemBind("./src/test/resources/it/mongo", "/home/mongo"); - //redpandaContainer.setCommand("--verbose"); + redpandaContainer.withLogConsumer(new Slf4jLogConsumer(logger, true)); + redpandaContainer.start(); - + try { - ExecResult result = redpandaContainer.execInContainer("rpk", "cluster", "config", "set", "enable_sasl", "true"); - logger.info("1>>>>>>>>>>>>>>>>>>>>>!!!!!!!!!!!!!!!><: {}", result.toString()); - result = redpandaContainer.execInContainer( "rpk", "acl", "user", "create", "admin", "-p", "12345678"); - logger.info("2>>>>>>>>>>>>>>>>>>>>>!!!!!!!!!!!!!!!><: {}", result.toString()); - result = redpandaContainer.execInContainer( "rpk", "cluster", "config", "set", "superusers", "['admin']"); - - logger.info("3>>>>>>>>>>>>>>>>>>>>>!!!!!!!!!!!!!!!><: {}", result.toString()); - result = redpandaContainer.execInContainer("rpk", "acl", "user", "create", "testuser", "-p", "testuser"); - logger.info("4>>>>>>>>>>>>>>>>>>>>>!!!!!!!!!!!!!!!><: {}", result.toString()); - result = redpandaContainer.execInContainer("rpk", "acl", "create", "--allow-principal", "*", "--operation", "all", - "--topic", "presets", "--user", "admin", "--password", "12345678", "--sasl-mechanism", "SCRAM-SHA-256" ); - - logger.info("5>>>>>>>>>>>>>>>>>>>>>!!!!!!!!!!!!!!!><: {}", result.toString()); - - -// String stdout = result.getStdout(); - - }catch (Exception e) { - logger.error(">>>>>>>>>>>>>>>>>>>!!!!!!!!!!!!11>Error ",e); + logger.info(redpandaContainer.execInContainer("rpk", "cluster", "config", "set", "enable_sasl", "true").toString()); + + logger.info(redpandaContainer.execInContainer("rpk", "acl", "user", "create", "admin", "-p", "12345678").toString()); + + logger.info(redpandaContainer.execInContainer("rpk", "cluster", "config", "set", "superusers", "['admin']").toString()); + + logger.info(redpandaContainer.execInContainer("rpk", "acl", "user", "create", "testuser", "-p", "testuser").toString()); + + logger.info(redpandaContainer.execInContainer("rpk", "acl", "create", "--allow-principal", "*", "--operation", "all", + "--topic", "presets", "--user", "admin", "--password", "12345678", "--sasl-mechanism", "SCRAM-SHA-256").toString()); + + } + catch (Exception e) { + logger.error("Error while executing commands in container", e); } -// try { -//// ExecResult result = redpandaContainer.execInContainer("bash", "rpk", "cluster", "config", "set", "superusers", "['admin']"); -//// logger.info(">>>>>>>>>>>>>>>>>>>>>><: {}", result.toString()); -// -// -// -// -// -//// result = redpandaContainer.execInContainer("rpk", "acl", "create", "--allow-principal", "User:testuser", "--operation", "create,describe", -//// "--cluster", "--user", "suname", "--password", "12345678", "--sasl-mechanism", "SCRAM-SHA-256"); -//// logger.info(">>>>>>>>>>>>>>>>>>>>>!!!!!!!!!!!!!!!><: {}", result.toString()); -//// String stdout = result.getStdout(); -// -// }catch (Exception e) { -// logger.error(">>>>>>>>>>>>>>>>>>>>Error ",e); -// } + final Integer exposedPort = redpandaContainer.getMappedPort(9092); final String bootstrapServers = redpandaContainer.getBootstrapServers(); logger.info("Redpanda bootstrap servers: {}", bootstrapServers); @@ -102,15 +76,14 @@ public Map start() { // Pass the configuration to the application under test return ImmutableMap.of( - "kafka-bootstrap-server", REDPANDA_NETWORK_ALIAS + ":" + 29092, - "kafka-security-protocol", "SASL_PLAINTEXT", - "kafka-sasl-mechanism","SCRAM-SHA-256", - "kafka-sasl-jaas-config","org.apache.kafka.common.security.scram.ScramLoginModule required username=\"testuser\" password=\"testuser\";" + "kafka-bootstrap-server", REDPANDA_NETWORK_ALIAS + ":" + 29092 ); - } catch (Exception e) { + } + catch (Exception e) { logger.error("Error while starting redpanda", e); throw e; } + } // create a "fake" network using the same id as the one that will be used by Quarkus @@ -120,13 +93,11 @@ private Network getNetwork() { return new Network() { @Override public String getId() { - return devServicesContext.containerNetworkId().get(); + return devServicesContext.containerNetworkId().orElse(null); } @Override - public void close() { - - } + public void close() {} @Override public Statement apply(Statement statement, Description description) { @@ -139,7 +110,7 @@ public Statement apply(Statement statement, Description description) { public void stop() { if (null != redpandaContainer) { logger.info("Stopping Redpanda container..."); - + redpandaContainer.stop(); logger.info("Redpanda container stopped"); } diff --git a/src/test/java/it/pagopa/swclient/mil/preset/resource/WiremockTestResource.java b/src/test/java/it/pagopa/swclient/mil/preset/resource/WiremockTestResource.java new file mode 100644 index 0000000..cfb3fb9 --- /dev/null +++ b/src/test/java/it/pagopa/swclient/mil/preset/resource/WiremockTestResource.java @@ -0,0 +1,97 @@ +package it.pagopa.swclient.mil.preset.resource; + +import com.google.common.collect.ImmutableMap; +import io.quarkus.test.common.DevServicesContext; +import io.quarkus.test.common.QuarkusTestResourceLifecycleManager; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.Network; +import org.testcontainers.containers.output.Slf4jLogConsumer; +import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.utility.DockerImageName; + +import java.util.Map; + + +public class WiremockTestResource implements QuarkusTestResourceLifecycleManager, DevServicesContext.ContextAware { + + private static final Logger logger = LoggerFactory.getLogger(WiremockTestResource.class); + private static final String WIREMOCK_NETWORK_ALIAS = "wiremock-it"; + + private GenericContainer wiremockContainer; + + private DevServicesContext devServicesContext; + + public void setIntegrationTestContext(DevServicesContext devServicesContext) { + this.devServicesContext = devServicesContext; + } + + @Override + public Map start() { + + logger.info("Starting WireMock container..."); + + wiremockContainer = new GenericContainer<>(DockerImageName.parse("wiremock/wiremock:latest")) + .withNetwork(getNetwork()) + .withNetworkAliases(WIREMOCK_NETWORK_ALIAS) + //.withNetworkMode(devServicesContext.containerNetworkId().get()) + .waitingFor(Wait.forListeningPort()); + + wiremockContainer.withLogConsumer(new Slf4jLogConsumer(logger)); + wiremockContainer.setCommand("--verbose --local-response-templating"); + wiremockContainer.withFileSystemBind("./src/test/resources/it/wiremock", "/home/wiremock"); + + wiremockContainer.start(); + + final String wiremockEndpoint = "http://" + WIREMOCK_NETWORK_ALIAS + ":" + 8080; + + // Pass the configuration to the application under test + return ImmutableMap.of( + "node.rest-service.url", wiremockEndpoint, + "node.soap-service.url", wiremockEndpoint + "/nodo/node-for-psp/v1", + "mil.rest-service.url", wiremockEndpoint + ); + + } + + private static void generateMockFilesForAuth() { + + + } + + + // create a "fake" network using the same id as the one that will be used by Quarkus + // using the network is the only way to make the withNetworkAliases work + private Network getNetwork() { + logger.info("devServicesContext.containerNetworkId() -> " + devServicesContext.containerNetworkId()); + return new Network() { + @Override + public String getId() { + return devServicesContext.containerNetworkId().get(); + } + + @Override + public void close() { + + } + + @Override + public Statement apply(Statement statement, Description description) { + return null; + } + }; + } + + @Override + public void stop() { + // Stop the needed container(s) + if (wiremockContainer != null) { + logger.info("Stopping WireMock container..."); + wiremockContainer.stop(); + logger.info("WireMock container stopped!"); + } + } +} From 296e73a8f69ff447790a6384bec73afb0e68691b Mon Sep 17 00:00:00 2001 From: "d.sabatini" Date: Tue, 6 Jun 2023 16:09:56 +0200 Subject: [PATCH 7/9] Fixed Redpanda integration test --- src/main/resources/application.properties | 3 +- .../preset/it/PresetTopicResourceTestIT.java | 46 ++++++------------- .../resource/CustomRedpandaContainer.java | 10 ++-- .../preset/resource/KafkaTestResource.java | 3 +- .../preset/resource/RedpandaTestResource.java | 19 ++++---- 5 files changed, 32 insertions(+), 49 deletions(-) diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 26db7bc..c48129a 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -11,7 +11,7 @@ quarkus.log.console.format=%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{requestId}] [%p] [%c{ %dev.quarkus.log.level=INFO %dev.quarkus.log.category."it.pagopa.swclient.mil.preset".level=DEBUG -%test.quarkus.log.level=DEBUG +%test.quarkus.log.level=INFO %test.quarkus.log.category."it.pagopa.swclient.mil.preset".level=DEBUG %prod.quarkus.log.level=${preset.quarkus-log-level} @@ -63,6 +63,7 @@ quarkus.kafka.devservices.enabled=false %prod.kafka.bootstrap.servers=${kafka-bootstrap-server} %prod.kafka.security.protocol=${kafka-security-protocol} %prod.kafka.sasl.mechanism=${kafka-sasl-mechanism} +%prod.kafka.sasl.jaas.config=${kafka-sasl-jaas-config} # ------------------------------------------------------------------------------ # JWT RBAC configurations diff --git a/src/test/java/it/pagopa/swclient/mil/preset/it/PresetTopicResourceTestIT.java b/src/test/java/it/pagopa/swclient/mil/preset/it/PresetTopicResourceTestIT.java index a0fbf7c..0ee9c19 100644 --- a/src/test/java/it/pagopa/swclient/mil/preset/it/PresetTopicResourceTestIT.java +++ b/src/test/java/it/pagopa/swclient/mil/preset/it/PresetTopicResourceTestIT.java @@ -1,33 +1,5 @@ package it.pagopa.swclient.mil.preset.it; -import java.time.Duration; -import java.util.ArrayList; -import java.util.List; -import java.util.Properties; -import java.util.UUID; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -import org.apache.kafka.clients.producer.KafkaProducer; -import org.apache.kafka.clients.producer.ProducerRecord; -import org.apache.kafka.clients.producer.RecordMetadata; -import org.apache.kafka.common.serialization.StringSerializer; -import org.bson.codecs.configuration.CodecRegistries; -import org.bson.codecs.configuration.CodecRegistry; -import org.bson.codecs.pojo.PojoCodecProvider; -import org.bson.conversions.Bson; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInstance; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.testcontainers.shaded.org.awaitility.Awaitility; - import com.mongodb.MongoClientSettings; import com.mongodb.client.FindIterable; import com.mongodb.client.MongoClient; @@ -35,7 +7,6 @@ import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoCursor; import com.mongodb.client.model.Filters; - import io.quarkus.kafka.client.serialization.ObjectMapperSerializer; import io.quarkus.test.common.DevServicesContext; import io.quarkus.test.junit.QuarkusIntegrationTest; @@ -65,10 +36,13 @@ import org.slf4j.LoggerFactory; import org.testcontainers.shaded.org.awaitility.Awaitility; +import java.time.Duration; +import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.List; import java.util.Properties; import java.util.UUID; +import java.util.concurrent.TimeUnit; @QuarkusIntegrationTest @TestProfile(IntegrationTestProfile.class) @@ -103,6 +77,9 @@ void createTestData() { // initialize kafka producer Properties kafkaConfig = new Properties(); kafkaConfig.put("bootstrap.servers", devServicesContext.devServicesProperties().get("test.kafka.bootstrap-server")); + kafkaConfig.put("security.protocol", "SASL_PLAINTEXT"); + kafkaConfig.put("sasl.mechanism","SCRAM-SHA-256"); + kafkaConfig.put("sasl.jaas.config","org.apache.kafka.common.security.scram.ScramLoginModule required username=\"testuser\" password=\"testuser\";"); kafkaConfig.put("linger.ms", 1); paymentTransactionProducer = new KafkaProducer<>(kafkaConfig, new StringSerializer(), new ObjectMapperSerializer<>()); @@ -130,10 +107,13 @@ void consume_close_ok() { paymentTransactionProducer.send(new ProducerRecord<>("presets", paymentTransaction)); - Awaitility.await().until(() -> { - PresetOperation presetOperation = getPresetOperation(presetId); - return presetOperation.getStatusTimestamp().compareTo(currentTimestamp) > 0; - }); + Awaitility + .with().pollInterval(10, TimeUnit.SECONDS) + .and().timeout(Duration.of(30, ChronoUnit.SECONDS)) + .await().until(() -> { + PresetOperation presetOperation = getPresetOperation(presetId); + return presetOperation.getStatusTimestamp().compareTo(currentTimestamp) > 0; + }); checkDatabaseData(presetId, PresetStatus.EXECUTED, paymentTransaction); diff --git a/src/test/java/it/pagopa/swclient/mil/preset/resource/CustomRedpandaContainer.java b/src/test/java/it/pagopa/swclient/mil/preset/resource/CustomRedpandaContainer.java index 9008c5a..3467560 100644 --- a/src/test/java/it/pagopa/swclient/mil/preset/resource/CustomRedpandaContainer.java +++ b/src/test/java/it/pagopa/swclient/mil/preset/resource/CustomRedpandaContainer.java @@ -25,12 +25,12 @@ protected void containerIsStarting(InspectContainerResponse containerInfo) { logger.info("getNetworkAliases() -> {}", this.getNetworkAliases()); String command = "#!/bin/bash\n"; - // command = command + "/usr/bin/rpk redpanda start --mode dev-container "; - // command = command + " --kafka-addr SASL_PLAINTEXT://0.0.0.0:29092,OUTSIDE://0.0.0.0:9092 "; - // command = command + " --advertise-kafka-addr SASL_PLAINTEXT://" + this.getNetworkAliases().get(this.getNetworkAliases().size()-1) + ":29092,OUTSIDE://" + this.getHost() + ":" + this.getMappedPort(9092); command = command + "/usr/bin/rpk redpanda start --mode dev-container "; - command = command + "--kafka-addr PLAINTEXT://0.0.0.0:29092,INTERNAL://0.0.0.0:19092,OUTSIDE://0.0.0.0:9092 "; - command = command + "--advertise-kafka-addr PLAINTEXT://127.0.0.1:29092,INTERNAL://"+this.getNetworkAliases().get(this.getNetworkAliases().size()-1)+":19092,OUTSIDE://" + this.getHost() + ":" + this.getMappedPort(9092); + command = command + " --kafka-addr PLAINTEXT://0.0.0.0:29092,OUTSIDE://0.0.0.0:9092 "; + command = command + " --advertise-kafka-addr PLAINTEXT://" + this.getNetworkAliases().get(this.getNetworkAliases().size()-1) + ":29092,OUTSIDE://" + this.getHost() + ":" + this.getMappedPort(9092); + // command = command + "/usr/bin/rpk redpanda start --mode dev-container "; + // command = command + "--kafka-addr PLAINTEXT://0.0.0.0:29092,INTERNAL://0.0.0.0:19092,OUTSIDE://0.0.0.0:9092 "; + // command = command + "--advertise-kafka-addr PLAINTEXT://127.0.0.1:29092,INTERNAL://"+this.getNetworkAliases().get(this.getNetworkAliases().size()-1)+":19092,OUTSIDE://" + this.getHost() + ":" + this.getMappedPort(9092); this.copyFileToContainer(Transferable.of(command, 511), "/testcontainers_start.sh"); diff --git a/src/test/java/it/pagopa/swclient/mil/preset/resource/KafkaTestResource.java b/src/test/java/it/pagopa/swclient/mil/preset/resource/KafkaTestResource.java index 817e176..e2939b7 100644 --- a/src/test/java/it/pagopa/swclient/mil/preset/resource/KafkaTestResource.java +++ b/src/test/java/it/pagopa/swclient/mil/preset/resource/KafkaTestResource.java @@ -84,7 +84,8 @@ public Map start() { "--partitions", "1", "--topic", "presets", "--command-config", "tmp/config.properties").toString()); - } catch (UnsupportedOperationException | IOException | InterruptedException e) { + } + catch (UnsupportedOperationException | IOException | InterruptedException e) { logger.error("Could not create topic", e); } diff --git a/src/test/java/it/pagopa/swclient/mil/preset/resource/RedpandaTestResource.java b/src/test/java/it/pagopa/swclient/mil/preset/resource/RedpandaTestResource.java index ea2842e..5fae1d7 100644 --- a/src/test/java/it/pagopa/swclient/mil/preset/resource/RedpandaTestResource.java +++ b/src/test/java/it/pagopa/swclient/mil/preset/resource/RedpandaTestResource.java @@ -50,16 +50,14 @@ public Map start() { try { logger.info(redpandaContainer.execInContainer("rpk", "cluster", "config", "set", "enable_sasl", "true").toString()); - logger.info(redpandaContainer.execInContainer("rpk", "acl", "user", "create", "admin", "-p", "12345678").toString()); - logger.info(redpandaContainer.execInContainer("rpk", "cluster", "config", "set", "superusers", "['admin']").toString()); - logger.info(redpandaContainer.execInContainer("rpk", "acl", "user", "create", "testuser", "-p", "testuser").toString()); - - logger.info(redpandaContainer.execInContainer("rpk", "acl", "create", "--allow-principal", "*", "--operation", "all", - "--topic", "presets", "--user", "admin", "--password", "12345678", "--sasl-mechanism", "SCRAM-SHA-256").toString()); - + logger.info(redpandaContainer.execInContainer("rpk", "acl", "create", + "--allow-principal", "*", "--operation", "all", "--topic", "presets", "--group", "preset-processor", + "--user", "admin", "--password", "12345678", "--sasl-mechanism", "SCRAM-SHA-256").toString()); + logger.info(redpandaContainer.execInContainer("rpk", "topic", "create", "presets", "--user", "testuser", "--password", "testuser", + "--sasl-mechanism", "SCRAM-SHA-256").toString() ); } catch (Exception e) { logger.error("Error while executing commands in container", e); @@ -76,11 +74,14 @@ public Map start() { // Pass the configuration to the application under test return ImmutableMap.of( - "kafka-bootstrap-server", REDPANDA_NETWORK_ALIAS + ":" + 29092 + "kafka-bootstrap-server", REDPANDA_NETWORK_ALIAS + ":" + 29092, + "kafka-security-protocol", "SASL_PLAINTEXT", + "kafka-sasl-mechanism","SCRAM-SHA-256", + "kafka-sasl-jaas-config","org.apache.kafka.common.security.scram.ScramLoginModule required username=\"testuser\" password=\"testuser\";" ); } catch (Exception e) { - logger.error("Error while starting redpanda", e); + logger.error("Error while starting Redpanda", e); throw e; } From e3f301e1ad64616d8eb364c7f6f7dee5ba9cad23 Mon Sep 17 00:00:00 2001 From: "fabrizio.guerrini" Date: Tue, 6 Jun 2023 17:07:12 +0200 Subject: [PATCH 8/9] changed condition to check EXECUTED status --- .../swclient/mil/preset/it/PresetTopicResourceTestIT.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/java/it/pagopa/swclient/mil/preset/it/PresetTopicResourceTestIT.java b/src/test/java/it/pagopa/swclient/mil/preset/it/PresetTopicResourceTestIT.java index 0ee9c19..565b542 100644 --- a/src/test/java/it/pagopa/swclient/mil/preset/it/PresetTopicResourceTestIT.java +++ b/src/test/java/it/pagopa/swclient/mil/preset/it/PresetTopicResourceTestIT.java @@ -112,7 +112,8 @@ void consume_close_ok() { .and().timeout(Duration.of(30, ChronoUnit.SECONDS)) .await().until(() -> { PresetOperation presetOperation = getPresetOperation(presetId); - return presetOperation.getStatusTimestamp().compareTo(currentTimestamp) > 0; + //return presetOperation.getStatusTimestamp().compareTo(currentTimestamp) > 0; + return presetOperation.getStatus().equals(PresetStatus.EXECUTED.name()); }); checkDatabaseData(presetId, PresetStatus.EXECUTED, paymentTransaction); From 8540b86f07ed1f03492549698cab894b72b61e26 Mon Sep 17 00:00:00 2001 From: "fabrizio.guerrini" Date: Tue, 6 Jun 2023 17:16:21 +0200 Subject: [PATCH 9/9] changed version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 703c7b7..447536c 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 it.pagopa.swclient.mil preset - 1.0.1-SNAPSHOT + 1.0.0 Preset Microservice for Multi-channel Integration Layer of SW Client Project 17