SCRUM-1099: Added event message subscribers to create audit logs for catalog, event and workspace bs services

Added unit and integration tests for the catalog, event and workspace streams
This commit is contained in:
Vishal Raut 2025-08-29 13:18:45 +05:30
parent b361f72b33
commit 2256eb408a
43 changed files with 2491 additions and 0 deletions

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
/mvnw text eol=lf
*.cmd text eol=crlf

36
.gitignore vendored Normal file
View File

@ -0,0 +1,36 @@
/logs/
/wp2-be-audit-bs-server/logs/
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/

19
.mvn/wrapper/maven-wrapper.properties vendored Normal file
View File

@ -0,0 +1,19 @@
# 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.
wrapperVersion=3.3.2
distributionType=only-script
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip

38
CHANGELOG.md Normal file
View File

@ -0,0 +1,38 @@
# Audit Changelog
<!--
## Templates for adding change log information
## [Version] - YYYY-MM-DD
### Added
- something
### Changed
- something
### Deprecated
- something
### Removed
- something
### Fixed
- something
### Security
- something
-->
# [1.0.0] - 2025-08-29
### [SCRUM-1099](https://itserr-wp2.atlassian.net/browse/SCRUM-1099)
### Added
- added event subscriber to create audit logs for catalog, event and workspace bs services
- added unit and integration tests for all event subscribers

16
Dockerfile Normal file
View File

@ -0,0 +1,16 @@
FROM openjdk:21-jdk-slim AS runtime
WORKDIR /app
RUN addgroup --system finconsgroup && \
adduser --system --ingroup finconsgroup --disabled-login --shell /sbin/nologin --home /var/cache/finconsgroup finconsgroup
COPY wp2-be-audit-bs-server/target/*.jar /app/app.jar
RUN chown -R finconsgroup:finconsgroup /app
EXPOSE 8080
USER finconsgroup
ENTRYPOINT ["java", "-jar", "/app/app.jar"]

View File

@ -1 +1,53 @@
# Audit Business Service
Audit Business Service is a **Spring Boot** application built with **Maven**,
providing ingest operations for all audit related events by consuming the same
from all the relevant event streams.
## Features
- **Audit Log**
- Create by processing events
- Supported Streams
- Catalog BS
- Event BS
## Getting Started
### Requirements
For building and running the application you need:
- GIT 2.48.1 +
- JDK 21 +
### Clone the repository
```
git clone https://code-repo.d4science.org/Resilience/wp2-be-audit-bs.git
cd wp2-be-audit-bs
```
### Build the project
```
./mvnw clean install
```
### Run the application
```
java -jar wp2-be-audit-bs-server/target/<jar-file>
```
### Access the API
- Base URL: `http://localhost:8080/api/v1/bs`
- Swagger UI URL: `http://localhost:8080/api/v1/bs/swagger-ui/index.html`
### Development
Please review this wiki page and follow the guidelines mentioned -
[Code Management Workflow and Standards](https://itserr-wp2.atlassian.net/wiki/spaces/IW/pages/46465038/Code+Management+Workflow+and+Standards)

16
lombok.config Normal file
View File

@ -0,0 +1,16 @@
## The file with defaults can be generated using command, where M2_REPO points to local maven repository folder
## Also replace version with the value you are using, in this case it is 1.18.36
# java -jar "%M2_REPO%\org\projectlombok\lombok\1.18.36\lombok-1.18.36.jar" config -g --verbose >> lombok.config
##
## Key : lombok.copyableAnnotations
## Type: list of type-name
##
## Copy these annotations to getters, setters, with methods, builder-setters, etc.
##
## Examples:
#
clear lombok.copyableAnnotations
# lombok.copyableAnnotations += <fully.qualified.Type>
# lombok.copyableAnnotations -= <fully.qualified.Type>
#

259
mvnw vendored Normal file
View File

@ -0,0 +1,259 @@
#!/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
#
# 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.
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Apache Maven Wrapper startup batch script, version 3.3.2
#
# Optional ENV vars
# -----------------
# JAVA_HOME - location of a JDK home dir, required when download maven via java source
# MVNW_REPOURL - repo url base for downloading maven distribution
# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output
# ----------------------------------------------------------------------------
set -euf
[ "${MVNW_VERBOSE-}" != debug ] || set -x
# OS specific support.
native_path() { printf %s\\n "$1"; }
case "$(uname)" in
CYGWIN* | MINGW*)
[ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")"
native_path() { cygpath --path --windows "$1"; }
;;
esac
# set JAVACMD and JAVACCMD
set_java_home() {
# For Cygwin and MinGW, ensure paths are in Unix format before anything is touched
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"
JAVACCMD="$JAVA_HOME/jre/sh/javac"
else
JAVACMD="$JAVA_HOME/bin/java"
JAVACCMD="$JAVA_HOME/bin/javac"
if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then
echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2
echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2
return 1
fi
fi
else
JAVACMD="$(
'set' +e
'unset' -f command 2>/dev/null
'command' -v java
)" || :
JAVACCMD="$(
'set' +e
'unset' -f command 2>/dev/null
'command' -v javac
)" || :
if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then
echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2
return 1
fi
fi
}
# hash string like Java String::hashCode
hash_string() {
str="${1:-}" h=0
while [ -n "$str" ]; do
char="${str%"${str#?}"}"
h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296))
str="${str#?}"
done
printf %x\\n $h
}
verbose() { :; }
[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; }
die() {
printf %s\\n "$1" >&2
exit 1
}
trim() {
# MWRAPPER-139:
# Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds.
# Needed for removing poorly interpreted newline sequences when running in more
# exotic environments such as mingw bash on Windows.
printf "%s" "${1}" | tr -d '[:space:]'
}
# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties
while IFS="=" read -r key value; do
case "${key-}" in
distributionUrl) distributionUrl=$(trim "${value-}") ;;
distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;;
esac
done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties"
[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties"
case "${distributionUrl##*/}" in
maven-mvnd-*bin.*)
MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/
case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in
*AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;;
:Darwin*x86_64) distributionPlatform=darwin-amd64 ;;
:Darwin*arm64) distributionPlatform=darwin-aarch64 ;;
:Linux*x86_64*) distributionPlatform=linux-amd64 ;;
*)
echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2
distributionPlatform=linux-amd64
;;
esac
distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip"
;;
maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;;
*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;;
esac
# apply MVNW_REPOURL and calculate MAVEN_HOME
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}"
distributionUrlName="${distributionUrl##*/}"
distributionUrlNameMain="${distributionUrlName%.*}"
distributionUrlNameMain="${distributionUrlNameMain%-bin}"
MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}"
MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")"
exec_maven() {
unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || :
exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD"
}
if [ -d "$MAVEN_HOME" ]; then
verbose "found existing MAVEN_HOME at $MAVEN_HOME"
exec_maven "$@"
fi
case "${distributionUrl-}" in
*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;;
*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;;
esac
# prepare tmp dir
if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then
clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; }
trap clean HUP INT TERM EXIT
else
die "cannot create temp dir"
fi
mkdir -p -- "${MAVEN_HOME%/*}"
# Download and Install Apache Maven
verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
verbose "Downloading from: $distributionUrl"
verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
# select .zip or .tar.gz
if ! command -v unzip >/dev/null; then
distributionUrl="${distributionUrl%.zip}.tar.gz"
distributionUrlName="${distributionUrl##*/}"
fi
# verbose opt
__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR=''
[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v
# normalize http auth
case "${MVNW_PASSWORD:+has-password}" in
'') MVNW_USERNAME='' MVNW_PASSWORD='' ;;
has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;;
esac
if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then
verbose "Found wget ... using wget"
wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl"
elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then
verbose "Found curl ... using curl"
curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl"
elif set_java_home; then
verbose "Falling back to use Java to download"
javaSource="$TMP_DOWNLOAD_DIR/Downloader.java"
targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName"
cat >"$javaSource" <<-END
public class Downloader extends java.net.Authenticator
{
protected java.net.PasswordAuthentication getPasswordAuthentication()
{
return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() );
}
public static void main( String[] args ) throws Exception
{
setDefault( new Downloader() );
java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() );
}
}
END
# For Cygwin/MinGW, switch paths to Windows format before running javac and java
verbose " - Compiling Downloader.java ..."
"$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java"
verbose " - Running Downloader.java ..."
"$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")"
fi
# If specified, validate the SHA-256 sum of the Maven distribution zip file
if [ -n "${distributionSha256Sum-}" ]; then
distributionSha256Result=false
if [ "$MVN_CMD" = mvnd.sh ]; then
echo "Checksum validation is not supported for maven-mvnd." >&2
echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
exit 1
elif command -v sha256sum >/dev/null; then
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then
distributionSha256Result=true
fi
elif command -v shasum >/dev/null; then
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then
distributionSha256Result=true
fi
else
echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2
echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
exit 1
fi
if [ $distributionSha256Result = false ]; then
echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2
echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2
exit 1
fi
fi
# unzip and move
if command -v unzip >/dev/null; then
unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip"
else
tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar"
fi
printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url"
mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME"
clean || :
exec_maven "$@"

149
mvnw.cmd vendored Normal file
View File

@ -0,0 +1,149 @@
<# : batch portion
@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 http://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 Apache Maven Wrapper startup batch script, version 3.3.2
@REM
@REM Optional ENV vars
@REM MVNW_REPOURL - repo url base for downloading maven distribution
@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output
@REM ----------------------------------------------------------------------------
@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0)
@SET __MVNW_CMD__=
@SET __MVNW_ERROR__=
@SET __MVNW_PSMODULEP_SAVE=%PSModulePath%
@SET PSModulePath=
@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @(
IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B)
)
@SET PSModulePath=%__MVNW_PSMODULEP_SAVE%
@SET __MVNW_PSMODULEP_SAVE=
@SET __MVNW_ARG0_NAME__=
@SET MVNW_USERNAME=
@SET MVNW_PASSWORD=
@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*)
@echo Cannot start maven from wrapper >&2 && exit /b 1
@GOTO :EOF
: end batch / begin powershell #>
$ErrorActionPreference = "Stop"
if ($env:MVNW_VERBOSE -eq "true") {
$VerbosePreference = "Continue"
}
# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties
$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl
if (!$distributionUrl) {
Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties"
}
switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) {
"maven-mvnd-*" {
$USE_MVND = $true
$distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip"
$MVN_CMD = "mvnd.cmd"
break
}
default {
$USE_MVND = $false
$MVN_CMD = $script -replace '^mvnw','mvn'
break
}
}
# apply MVNW_REPOURL and calculate MAVEN_HOME
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
if ($env:MVNW_REPOURL) {
$MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" }
$distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')"
}
$distributionUrlName = $distributionUrl -replace '^.*/',''
$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$',''
$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain"
if ($env:MAVEN_USER_HOME) {
$MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain"
}
$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join ''
$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME"
if (Test-Path -Path "$MAVEN_HOME" -PathType Container) {
Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME"
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
exit $?
}
if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) {
Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl"
}
# prepare tmp dir
$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile
$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir"
$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null
trap {
if ($TMP_DOWNLOAD_DIR.Exists) {
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
}
}
New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null
# Download and Install Apache Maven
Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
Write-Verbose "Downloading from: $distributionUrl"
Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
$webclient = New-Object System.Net.WebClient
if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) {
$webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD)
}
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null
# If specified, validate the SHA-256 sum of the Maven distribution zip file
$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum
if ($distributionSha256Sum) {
if ($USE_MVND) {
Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties."
}
Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash
if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) {
Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property."
}
}
# unzip and move
Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null
Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null
try {
Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null
} catch {
if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) {
Write-Error "fail to move MAVEN_HOME"
}
} finally {
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
}
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"

51
pom.xml Normal file
View File

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.finconsgroup.itserr.marketplace</groupId>
<artifactId>core</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<artifactId>wp2-be-audit-bs</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<name>wp2-be-audit-bs</name>
<description>Audit Bs Application</description>
<modules>
<module>wp2-be-audit-bs-client</module>
<module>wp2-be-audit-bs-server</module>
</modules>
<dependencyManagement>
<dependencies>
<!-- WP2 Audit DM Client -->
<dependency>
<groupId>com.finconsgroup.itserr.marketplace</groupId>
<artifactId>wp2-be-audit-dm-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- WP2 Audit BS Client -->
<dependency>
<groupId>com.finconsgroup.itserr.marketplace</groupId>
<artifactId>wp2-be-audit-bs-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- WP2 Audit BS Server -->
<dependency>
<groupId>com.finconsgroup.itserr.marketplace</groupId>
<artifactId>wp2-be-audit-bs-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>

View File

@ -0,0 +1,48 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="audit-bs [clean,install] skipTests" type="MavenRunConfiguration" factoryName="Maven">
<MavenSettings>
<option name="myGeneralSettings" />
<option name="myRunnerSettings">
<MavenRunnerSettings>
<option name="delegateBuildToMaven" value="false" />
<option name="environmentProperties">
<map />
</option>
<option name="jreName" value="#USE_PROJECT_JDK" />
<option name="mavenProperties">
<map />
</option>
<option name="passParentEnv" value="true" />
<option name="runMavenInBackground" value="true" />
<option name="skipTests" value="true" />
<option name="vmOptions" value="" />
</MavenRunnerSettings>
</option>
<option name="myRunnerParameters">
<MavenRunnerParameters>
<option name="cmdOptions" />
<option name="profiles">
<set />
</option>
<option name="goals">
<list>
<option value="clean" />
<option value="install" />
</list>
</option>
<option name="multimoduleDir" />
<option name="pomFileName" />
<option name="profilesMap">
<map />
</option>
<option name="projectsCmdOptionValues">
<list />
</option>
<option name="resolveToWorkspace" value="false" />
<option name="workingDirPath" value="$PROJECT_DIR$/../wp2-be-audit-bs" />
</MavenRunnerParameters>
</option>
</MavenSettings>
<method v="2" />
</configuration>
</component>

View File

@ -0,0 +1,33 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="audit-bs [clean,install]" type="MavenRunConfiguration" factoryName="Maven">
<MavenSettings>
<option name="myGeneralSettings" />
<option name="myRunnerSettings" />
<option name="myRunnerParameters">
<MavenRunnerParameters>
<option name="cmdOptions" />
<option name="profiles">
<set />
</option>
<option name="goals">
<list>
<option value="clean" />
<option value="install" />
</list>
</option>
<option name="multimoduleDir" />
<option name="pomFileName" />
<option name="profilesMap">
<map />
</option>
<option name="projectsCmdOptionValues">
<list />
</option>
<option name="resolveToWorkspace" value="false" />
<option name="workingDirPath" value="$PROJECT_DIR$/../wp2-be-audit-bs" />
</MavenRunnerParameters>
</option>
</MavenSettings>
<method v="2" />
</configuration>
</component>

View File

@ -0,0 +1,14 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="audit-bs all test" type="JUnit" factoryName="JUnit">
<module name="wp2-be-audit-bs-server" />
<option name="PACKAGE_NAME" value="com.finconsgroup.itserr.marketplace.audit.bs" />
<option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="package" />
<option name="VM_PARAMETERS" value="-ea -Xshare:off" />
<option name="WORKING_DIRECTORY" value="$MODULE_WORKING_DIR$" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>

View File

@ -0,0 +1,18 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="audit-bs run develop" type="Application" factoryName="Application">
<option name="ALTERNATIVE_JRE_PATH" value="21" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="true" />
<envs>
<env name="spring.profiles.active" value="develop" />
<env name="audit_bs_swagger_api_server_url" value="http://localhost:8080/api/v1/bs" />
<env name="audit_dm_client_url" value="https://apisix-itserr.d4science.org/api/dm" />
<env name="audit_bs_messaging_enabled" value="false" />
</envs>
<option name="MAIN_CLASS_NAME" value="com.finconsgroup.itserr.marketplace.audit.bs.AuditBsApplication" />
<module name="wp2-be-audit-bs-server" />
<option name="WORKING_DIRECTORY" value="$MODULE_WORKING_DIR$" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>

View File

@ -0,0 +1,18 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="audit-bs run local port per ms" type="Application" factoryName="Application">
<option name="ALTERNATIVE_JRE_PATH" value="21" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="true" />
<envs>
<env name="spring.profiles.active" value="local" />
<env name="server.port" value="8098" />
<env name="audit_bs_swagger_api_server_url" value="http://localhost:8098/api/v1/bs" />
<env name="audit_dm_client_url" value="http://localhost:8097/api/v1/dm" />
</envs>
<option name="MAIN_CLASS_NAME" value="com.finconsgroup.itserr.marketplace.audit.bs.AuditBsApplication" />
<module name="wp2-be-audit-bs-server" />
<option name="WORKING_DIRECTORY" value="$MODULE_WORKING_DIR$" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>

View File

@ -0,0 +1,15 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="audit-bs run local" type="Application" factoryName="Application">
<option name="ALTERNATIVE_JRE_PATH" value="21" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="true" />
<envs>
<env name="spring.profiles.active" value="local" />
</envs>
<option name="MAIN_CLASS_NAME" value="com.finconsgroup.itserr.marketplace.audit.bs.AuditBsApplication" />
<module name="wp2-be-audit-bs-server" />
<option name="WORKING_DIRECTORY" value="$MODULE_WORKING_DIR$" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>

View File

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.finconsgroup.itserr.marketplace</groupId>
<artifactId>wp2-be-audit-bs</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>wp2-be-audit-bs-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>wp2-be-audit-bs-client</name>
<description>Audit Bs Client Library</description>
<properties>
<!-- Skip repackage as it does not have a main class -->
<spring-boot.repackage.skip>true</spring-boot.repackage.skip>
</properties>
<dependencies>
<!-- WP2 Core Library Web -->
<dependency>
<groupId>com.finconsgroup.itserr.marketplace</groupId>
<artifactId>core-web</artifactId>
</dependency>
<!-- WP2 Audit DM Client -->
<dependency>
<groupId>com.finconsgroup.itserr.marketplace</groupId>
<artifactId>wp2-be-audit-dm-client</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Maven Compiler Plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,21 @@
package com.finconsgroup.itserr.marketplace.audit.bs.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import lombok.experimental.SuperBuilder;
/**
* Input DTO for creating AuditLog.
*/
@Schema(name = "InputCreateAuditLogDto", description = "DTO for creating AuditLog")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@SuperBuilder
@AllArgsConstructor
public class InputCreateAuditLogDto extends com.finconsgroup.itserr.marketplace.audit.dm.dto.InputCreateAuditLogDto {
}

View File

@ -0,0 +1,21 @@
package com.finconsgroup.itserr.marketplace.audit.bs.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import lombok.experimental.SuperBuilder;
/**
* Output DTO representing a created AuditLog.
*/
@Schema(name = "OutputAuditLogDto", description = "DTO representing a AuditLog in responses")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@SuperBuilder
@AllArgsConstructor
public class OutputAuditLogDto extends com.finconsgroup.itserr.marketplace.audit.dm.dto.OutputAuditLogDto {
}

View File

@ -0,0 +1,191 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.finconsgroup.itserr.marketplace</groupId>
<artifactId>wp2-be-audit-bs</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>wp2-be-audit-bs-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>wp2-be-audit-bs-server</name>
<description>Audit Bs Application</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- WP2 Core Library Logging -->
<dependency>
<groupId>com.finconsgroup.itserr.marketplace</groupId>
<artifactId>core-logging</artifactId>
</dependency>
<!-- WP2 Core Library Web -->
<dependency>
<groupId>com.finconsgroup.itserr.marketplace</groupId>
<artifactId>core-web</artifactId>
</dependency>
<!-- WP2 Core Library Metrics -->
<dependency>
<groupId>com.finconsgroup.itserr.marketplace</groupId>
<artifactId>core-metrics</artifactId>
</dependency>
<!-- WP2 Core Library i18n -->
<dependency>
<groupId>com.finconsgroup.itserr.marketplace</groupId>
<artifactId>core-i18n</artifactId>
</dependency>
<!-- WP2 Core Library messaging -->
<dependency>
<groupId>com.finconsgroup.itserr.marketplace</groupId>
<artifactId>core-messaging</artifactId>
</dependency>
<!-- WP2 Audit BS Client -->
<dependency>
<groupId>com.finconsgroup.itserr.marketplace</groupId>
<artifactId>wp2-be-audit-bs-client</artifactId>
</dependency>
<!-- Open Api SpringDoc -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
</dependency>
<!-- Mapstruct -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
</dependency>
<!-- Rest Assured -->
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- WP2 Core Library Web Test -->
<dependency>
<groupId>com.finconsgroup.itserr.marketplace</groupId>
<artifactId>core-web-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Test Containers -->
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<!-- Test Containers RabbitMq -->
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>rabbitmq</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Maven Compiler Plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
</path>
</annotationProcessorPaths>
<compilerArgs>
-Amapstruct.unmappedTargetPolicy=ERROR
</compilerArgs>
</configuration>
</plugin>
<!-- Surefire Plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<!--
-javaagent:...
Added to fix java agent warning while running tests
Dynamic loading of agents will be disallowed by default in a future release
https://stackoverflow.com/a/79213258/9714611
-->
<!--
-Xshare:off
Disable Class Data Sharing (CDS) during test execution to avoid JVM warnings like:
"Sharing is only supported for boot loader classes because bootstrap classpath has been appended".
This setting applies only to tests run by the Maven Surefire Plugin.
-->
<argLine>-javaagent:${settings.localRepository}/org/mockito/mockito-core/${mockito.version}/mockito-core-${mockito.version}.jar -Xshare:off @{argLine}</argLine>
<includes>
<include>**/*Test.java</include>
<include>**/*IT.java</include>
</includes>
</configuration>
</plugin>
<!-- Jacoco Plugin -->
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco-plugin.version}</version>
<executions>
<execution>
<id>prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>prepare-package</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,22 @@
package com.finconsgroup.itserr.marketplace.audit.bs;
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.info.Info;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@SpringBootApplication
@OpenAPIDefinition(info = @Info(
title = "Audit BS API",
description = "API definition of the Audit Microservice",
version = "1.0.1"
))
@EnableConfigurationProperties({com.finconsgroup.itserr.marketplace.audit.bs.configuration.properties.AuditBsConfigurationProperties.class})
public class AuditBsApplication {
public static void main(String[] args) {
SpringApplication.run(AuditBsApplication.class, args);
}
}

View File

@ -0,0 +1,40 @@
package com.finconsgroup.itserr.marketplace.audit.bs.api;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
/**
* This interface defines the contract for REST API endpoints used for system testing and debugging.
*
* <p>
* These endpoints are intended for internal use only and
* provide endpoints used for debugging and runtime analysis.
* </p>
*
* <p>Example usage:
* <pre>
* GET /api/v1/bs/diagnostics/download-logs - Download application log for analysis
* </pre>
* </p>
*/
@Tag(
name = "Diagnostics",
description = "Diagnostics API: provides endpoints used for " +
"debugging and runtime analysis."
)
@SecurityRequirement(name = "BearerAuth")
public interface DiagnosticsApi {
@Operation(
summary = "Download log file",
responses = {@ApiResponse(responseCode = "200", description = "OK"),}
)
@GetMapping(path = "/audit/diagnostics/download-logs", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
ResponseEntity<Resource> downloadLogs();
}

View File

@ -0,0 +1,24 @@
package com.finconsgroup.itserr.marketplace.audit.bs.configuration.properties;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;
/**
* Configuration properties for the AuditLog bs service.
* <p>
* These properties are mapped from the {@code audit.bs} prefix in the application configuration.
*/
@Data
@Validated
@ConfigurationProperties(prefix = "audit.bs")
public class AuditBsConfigurationProperties {
/**
* Base URL used by Swagger/OpenAPI documentation.
* Example: {@code http://localhost:8080}
*/
@NotBlank
private String swaggerApiServerUrl;
}

View File

@ -0,0 +1,66 @@
package com.finconsgroup.itserr.marketplace.audit.bs.controller;
import com.finconsgroup.itserr.marketplace.audit.bs.api.DiagnosticsApi;
import com.finconsgroup.itserr.marketplace.core.web.exception.WP2ResourceNotFoundException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.RollingFileAppender;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RestController;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
/**
* REST controller class for handling debugging/analysis related API requests.
*
* <p>Implements the {@link DiagnosticsApi} interface.</p>
*/
@Slf4j
@RestController
@RequiredArgsConstructor
public class DiagnosticsController implements DiagnosticsApi {
// The name of the RollingFile Log4j2 component
// It is not the name of the log file
// We use this to dynamically retrieve the name of the log file.
@Value("${log.log4j2-rolling-file-name}")
private String log4j2RollingFileName;
@Override
public ResponseEntity<Resource> downloadLogs() {
log.debug("call to DiagnosticsController - downloadLogs");
Path filePath = Paths.get(getLogFilePathFromLog4j2());
log.debug("Trying to retrieve log file from: {}", filePath);
File logFile = filePath.toFile();
if (!logFile.exists() || !logFile.isFile()) {
throw new WP2ResourceNotFoundException("Log file not found: %s".formatted(logFile.getAbsolutePath()));
}
Resource resource = new FileSystemResource(logFile);
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, getContentDispositionHeaderValue(logFile.getName()))
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(resource);
}
// private
public String getLogFilePathFromLog4j2() {
LoggerContext context = (LoggerContext) LogManager.getContext(false);
RollingFileAppender appender = context.getConfiguration().getAppender(log4j2RollingFileName);
return appender.getFileName();
}
private static String getContentDispositionHeaderValue(String fileName) {
return "attachment; filename=\"%s\"".formatted(fileName);
}
}

View File

@ -0,0 +1,47 @@
package com.finconsgroup.itserr.marketplace.audit.bs.mapper;
import com.finconsgroup.itserr.marketplace.audit.bs.dto.InputCreateAuditLogDto;
import com.finconsgroup.itserr.marketplace.audit.bs.dto.OutputAuditLogDto;
import com.finconsgroup.itserr.messaging.dto.UntypedMessagingEventDto;
import io.cloudevents.CloudEvent;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Named;
import java.net.URI;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.util.Optional;
@Mapper(config = MapperConfiguration.class)
public interface AuditLogMapper {
String NAME_CLOUD_EVENT_SOURCE_TO_STRING = "cloudEventSourceToString";
@Mapping(target = "eventSource", source = "cloudEvent.source", qualifiedByName = NAME_CLOUD_EVENT_SOURCE_TO_STRING)
@Mapping(target = "eventType", source = "cloudEvent.type")
@Mapping(target = "user", source = "messagingEventDto.user")
@Mapping(target = "resource.id", source = "messagingEventDto.id")
@Mapping(target = "resource.name", source = "messagingEventDto.name")
@Mapping(target = "resource.title", source = "messagingEventDto.title")
@Mapping(target = "resource.status", source = "messagingEventDto.status")
@Mapping(target = "resource.category", source = "messagingEventDto.category")
@Mapping(target = "eventMessage", source = "messagingEventDto.message")
@Mapping(target = "eventActionTime", source = "messagingEventDto.timestamp")
@Mapping(target = "eventAdditionalData", source = "messagingEventDto.additionalData")
@Mapping(target = "eventCreationTime", source = "cloudEvent.time")
InputCreateAuditLogDto messagingEventToInputCreateAuditLogDto(UntypedMessagingEventDto messagingEventDto, CloudEvent cloudEvent);
OutputAuditLogDto auditLogDmDtoToBsDto(com.finconsgroup.itserr.marketplace.audit.dm.dto.OutputAuditLogDto outputAuditLogDmDto);
@Named(NAME_CLOUD_EVENT_SOURCE_TO_STRING)
default String cloudEventSourceToString(URI source) {
return source != null ? source.toString() : null;
}
@SuppressWarnings("unused")
default Instant offsetDateTimeToInstant(OffsetDateTime offsetDateTime) {
return Optional.ofNullable(offsetDateTime).map(OffsetDateTime::toInstant).orElse(null);
}
}

View File

@ -0,0 +1,10 @@
package com.finconsgroup.itserr.marketplace.audit.bs.mapper;
import org.mapstruct.MapperConfig;
import org.mapstruct.MappingConstants;
@MapperConfig(
componentModel = MappingConstants.ComponentModel.SPRING
)
public interface MapperConfiguration {
}

View File

@ -0,0 +1,40 @@
package com.finconsgroup.itserr.marketplace.audit.bs.messaging;
import com.fasterxml.jackson.core.type.TypeReference;
import com.finconsgroup.itserr.marketplace.audit.bs.dto.OutputAuditLogDto;
import com.finconsgroup.itserr.marketplace.audit.bs.service.AuditLogService;
import com.finconsgroup.itserr.messaging.consumer.AbstractEventSubscriber;
import com.finconsgroup.itserr.messaging.consumer.AbstractResourceSubscriber;
import com.finconsgroup.itserr.messaging.dto.UntypedMessagingEventDto;
import io.cloudevents.CloudEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;
/**
* Concrete implementation of {@link AbstractResourceSubscriber} for handling catalog-related resource events.
*/
@Component("messagingEventSubscriber")
@Slf4j
public class MessagingEventSubscriber extends AbstractEventSubscriber {
private static final TypeReference<UntypedMessagingEventDto> TYPE_REFERENCE = new TypeReference<>() {
};
private final AuditLogService auditLogService;
public MessagingEventSubscriber(AuditLogService auditLogService) {
super(TYPE_REFERENCE);
this.auditLogService = auditLogService;
}
@Override
protected <V> void handleEvent(V eventData, @NonNull CloudEvent cloudEvent) {
if (eventData instanceof UntypedMessagingEventDto untypedMessagingEventDto) {
OutputAuditLogDto outputAuditLogDto = auditLogService.createFromMessagingEvent(untypedMessagingEventDto, cloudEvent);
log.info("Created audit log with id: {}", outputAuditLogDto.getId());
} else {
log.warn("Unhandled event type: {}", cloudEvent.getType());
}
}
}

View File

@ -0,0 +1,22 @@
package com.finconsgroup.itserr.marketplace.audit.bs.openapi;
import io.swagger.v3.oas.models.servers.Server;
import org.springdoc.core.customizers.OpenApiCustomizer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.List;
@Configuration
public class OpenApiConfiguration {
@Value("${audit.bs.swagger-api-server-url}")
private String swaggerApiServer;
@Bean
public OpenApiCustomizer customServerOpenApiCustomizer() {
return openApi -> openApi
.setServers(List.of(new Server().url(swaggerApiServer)));
}
}

View File

@ -0,0 +1,37 @@
package com.finconsgroup.itserr.marketplace.audit.bs.service;
import com.finconsgroup.itserr.marketplace.audit.bs.dto.InputCreateAuditLogDto;
import com.finconsgroup.itserr.marketplace.audit.bs.dto.OutputAuditLogDto;
import com.finconsgroup.itserr.messaging.dto.UntypedMessagingEventDto;
import io.cloudevents.CloudEvent;
import org.springframework.lang.NonNull;
/**
* Service for handling business logic related to AuditLog. This interface provides methods to retrieve, create, update, and delete AuditLog,
*
* <p>Example usage:
* <pre>
* Page<OutputAuditLogDto> AuditLog = AuditLogService.findAll(pageable);
* </pre>
* </p>
*/
public interface AuditLogService {
/**
* Creates new AuditLog for user using the provided input data.
*
* @param inputCreateAuditLogDto the input DTO containing AuditLog details
*/
@NonNull
OutputAuditLogDto create(@NonNull InputCreateAuditLogDto inputCreateAuditLogDto);
/**
* Creates new audit log using the provided input data.
*
* @param messagingEventDto the input messaging event DTO containing audit log details
*/
@NonNull
OutputAuditLogDto createFromMessagingEvent(@NonNull UntypedMessagingEventDto messagingEventDto,
@NonNull CloudEvent cloudEvent);
}

View File

@ -0,0 +1,41 @@
package com.finconsgroup.itserr.marketplace.audit.bs.service.impl;
import com.finconsgroup.itserr.marketplace.audit.bs.dto.InputCreateAuditLogDto;
import com.finconsgroup.itserr.marketplace.audit.bs.dto.OutputAuditLogDto;
import com.finconsgroup.itserr.marketplace.audit.bs.mapper.AuditLogMapper;
import com.finconsgroup.itserr.marketplace.audit.bs.service.AuditLogService;
import com.finconsgroup.itserr.marketplace.audit.dm.client.AuditDmClient;
import com.finconsgroup.itserr.messaging.dto.UntypedMessagingEventDto;
import io.cloudevents.CloudEvent;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Service;
/**
* Default implementation of {@link AuditLogService} to perform operations related to AuditLog resources
*/
@Service
@RequiredArgsConstructor
@Slf4j
public class DefaultAuditLogService implements AuditLogService {
private final AuditDmClient auditDmClient;
private final AuditLogMapper auditLogMapper;
@NonNull
@Override
public OutputAuditLogDto create(@NonNull InputCreateAuditLogDto inputCreateAuditLogDto) {
com.finconsgroup.itserr.marketplace.audit.dm.dto.OutputAuditLogDto outputAuditLogDmDto =
auditDmClient.createAuditLog(inputCreateAuditLogDto);
return auditLogMapper.auditLogDmDtoToBsDto(outputAuditLogDmDto);
}
@NonNull
@Override
public OutputAuditLogDto createFromMessagingEvent(@NonNull UntypedMessagingEventDto messagingEventDto,
@NonNull CloudEvent cloudEvent) {
InputCreateAuditLogDto dto = auditLogMapper.messagingEventToInputCreateAuditLogDto(messagingEventDto, cloudEvent);
return create(dto);
}
}

View File

@ -0,0 +1,33 @@
audit_bs_server_port: 8080
audit_bs_zipkin_tracing_export_enabled: false
audit_bs_swagger_api_server_url: https://apisix-itserr.d4science.org/api/bs
audit_dm_client_url: http://be-audit-dm:8080/api/v1/dm
# Messaging
audit_bs_messaging_enabled: true
audit_bs_messaging_host: ${WP2_RABBITMQ_IP}
audit_bs_messaging_port: ${WP2_RABBITMQ_PORT}
audit_bs_messaging_vhost: ${WP2_RABBITMQ_VHOST}
audit_bs_messaging_auth_keycloak_token_url: https://${WP2_KEYCLOAK_HOSTNAME}/auth/realms/d4science/protocol/openid-connect/token
audit_bs_messaging_auth_client_id: ${WP2_RABBITMQ_CLIENTID}
audit_bs_messaging_auth_client_secret: ${WP2_RABBITMQ_SECRET}
audit_bs_messaging_catalog_bs_event_stream_consumer_enabled: true
audit_bs_messaging_catalog_bs_event_stream_name: itserr-stream-catalog-event
audit_bs_messaging_catalog_bs_event_stream_consumer_dlq_name: itserr-stream-catalog-event-dlq
audit_bs_messaging_event_bs_event_stream_consumer_enabled: true
audit_bs_messaging_event_bs_event_stream_name: itserr-stream-event-notification
audit_bs_messaging_event_bs_event_stream_consumer_dlq_name: itserr-stream-event-notification-dlq
audit_bs_messaging_workspace_bs_event_stream_consumer_enabled: true
audit_bs_messaging_workspace_bs_event_stream_name: itserr-stream-workspace-event
audit_bs_messaging_workspace_bs_event_stream_consumer_dlq_name: itserr-stream-workspace-event-dlq
#diagnostics
audit_bs_diagnostics_publish_message_enabled: true
# based on the current Dockerfile, the containerized application
# only has permission to create folders inside the /app folder
audit_bs_log_base_folder: /app/logs

View File

@ -0,0 +1,32 @@
audit_bs_server_port: 8080
audit_bs_zipkin_tracing_export_enabled: false
audit_bs_swagger_api_server_url: http://localhost:8080/api/v1/bs
audit_dm_client_url: http://localhost:8080/api/v1/dm
# Messaging
audit_bs_messaging_enabled: false
audit_bs_messaging_host: localhost
audit_bs_messaging_port: 5552
audit_bs_messaging_vhost: itserr_vhost
audit_bs_messaging_auth_keycloak_token_url:
audit_bs_messaging_auth_client_id: guest
audit_bs_messaging_auth_client_secret: guest
audit_bs_messaging_catalog_bs_event_stream_consumer_enabled: true
audit_bs_messaging_catalog_bs_event_stream_name: itserr-stream-catalog-event
audit_bs_messaging_catalog_bs_event_stream_consumer_dlq_name: itserr-stream-catalog-event-dlq
audit_bs_messaging_event_bs_event_stream_consumer_enabled: true
audit_bs_messaging_event_bs_event_stream_name: itserr-stream-event-notification
audit_bs_messaging_event_bs_event_stream_consumer_dlq_name: itserr-stream-event-notification-dlq
audit_bs_messaging_workspace_bs_event_stream_consumer_enabled: true
audit_bs_messaging_workspace_bs_event_stream_name: itserr-stream-workspace-event
audit_bs_messaging_workspace_bs_event_stream_consumer_dlq_name: itserr-stream-workspace-event-dlq
audit_bs_log_base_folder: logs
logging:
level:
com.finconsgroup.itserr.messaging.utils.CloudEventUtil: TRACE

View File

@ -0,0 +1,130 @@
server:
port: ${audit_bs_server_port}
servlet:
context-path: /api/v1/bs
forward-headers-strategy: NATIVE
spring:
profiles:
group:
develop:
- develop
- log-files
- json-logs
local:
- local
- log-files
application:
name: wp2-be-audit-bs
config:
import: 'optional:configserver:,optional:file:/run/secrets/wp2_services_secret.yml'
jackson:
mapper:
allow-coercion-of-scalars: false
deserialization:
accept-float-as-int: false
springdoc:
api-docs:
path: /audit/api-docs
swagger-ui:
url: /audit/api-docs
management:
endpoints:
web:
exposure:
include: '*'
endpoint:
health:
show-details: always
zipkin:
tracing:
export:
enabled: ${audit_bs_zipkin_tracing_export_enabled}
web:
exception-handler:
method-validation-exception:
field-name-on-field-error: true
api:
client:
enabled: true
instances:
audit-dm-client:
bean-name: AuditDmClient
client-type: FEIGN
service-interface-class: com.finconsgroup.itserr.marketplace.audit.dm.client.AuditDmClient
base-url: ${audit_dm_client_url}
jwt-request-interceptor-enabled: true
jwt-request-interceptor-lenient: true
error-decoder-bean-name: feignCoreErrorDecoder
audit:
bs:
swagger-api-server-url: ${audit_bs_swagger_api_server_url}
consumer-defaults: &consumer_defaults
enabled: true
name: audit-bs-consumer
handler-bean-name: messagingEventSubscriber
concurrency: ${audit_bs_messaging_default_event_stream_consumer_concurrency:1}
retry-attempts: ${audit_bs_messaging_default_event_stream_consumer_retry_attempts:3}
retry-backoff-ms: ${audit_bs_messaging_default_event_stream_consumer_retry_backoff_ms:1000}
offset-strategy: ${audit_bs_messaging_default_event_stream_consumer_offset_strategy:NEXT}
exact-offset: ${audit_bs_messaging_default_event_stream_consumer_exact_offset:0}
single-active-consumer: ${audit_bs_messaging_default_event_stream_consumer_single_active_consumer:false}
# Messaging
messaging:
enabled: ${audit_bs_messaging_enabled}
clients:
- platform: RABBITMQ
host: ${audit_bs_messaging_host}
port: ${audit_bs_messaging_port}
vhost: ${audit_bs_messaging_vhost}
enable-address-resolution: true
refresh-delay: 20s
refresh-period: 20s
keycloak-token-url: ${audit_bs_messaging_auth_keycloak_token_url}
username: ${audit_bs_messaging_auth_client_id}
password: ${audit_bs_messaging_auth_client_secret}
grant-type: client_credentials
oauth-parameters:
scope: openid profile email
streams:
- name: ${audit_bs_messaging_catalog_bs_event_stream_name}
consumer:
<<: *consumer_defaults
enabled: ${audit_bs_messaging_catalog_bs_event_stream_consumer_enabled}
dlq:
name: ${audit_bs_messaging_catalog_bs_event_stream_consumer_dlq_name}
- name: ${audit_bs_messaging_event_bs_event_stream_name}
consumer:
<<: *consumer_defaults
enabled: ${audit_bs_messaging_event_bs_event_stream_consumer_enabled}
dlq:
name: ${audit_bs_messaging_event_bs_event_stream_consumer_dlq_name}
- name: ${audit_bs_messaging_workspace_bs_event_stream_name}
consumer:
<<: *consumer_defaults
enabled: ${audit_bs_messaging_workspace_bs_event_stream_consumer_enabled}
dlq:
name: ${audit_bs_messaging_workspace_bs_event_stream_consumer_dlq_name}
# Logging
log:
log4j2-rolling-file-name: file1App
folder: ${audit_bs_log_base_folder}
logging:
level:
com.finconsgroup.itserr.marketplace: DEBUG
feign: DEBUG
com.rabbitmq: DEBUG

View File

@ -0,0 +1,90 @@
package com.finconsgroup.itserr.marketplace.audit.bs.messaging.integration_tests;
import com.finconsgroup.itserr.marketplace.audit.bs.util.RabbitMqContainerHelper;
import com.finconsgroup.itserr.marketplace.core.web.test.WireMockServerTest;
import io.restassured.RestAssured;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.testcontainers.containers.RabbitMQContainer;
import org.testcontainers.junit.jupiter.Testcontainers;
import java.io.IOException;
/**
* Base class for integration tests.
* <p>
* This class sets up the application context with a Testcontainer
* and configures RestAssured to communicate with the randomly assigned port
* of the Spring Boot application.
*/
@Testcontainers(disabledWithoutDocker = true)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@DirtiesContext
@ActiveProfiles("integration-test")
@Slf4j
public class AbstractIntegrationTest implements WireMockServerTest {
public static final String SPRING_AUDIT_DM_CLIENT_URL_KEY = "audit_dm_client_url";
private static RabbitMQContainer rabbitMQContainer;
@LocalServerPort
private int localServerPort;
/**
* Starts the RabbitMq container before all tests.
*/
@BeforeAll
static void beforeAll() throws IOException, InterruptedException {
rabbitMQContainer = RabbitMqContainerHelper.startRabbitMqContainer();
}
/**
* Registers dynamic properties for the Spring context
* using the running RabbitMq container.
* <p>
* These properties must be defined programmatically at runtime.
* Setting these properties statically in {@code application-*.yml}
* will not work, Spring will fail to connect to the container.
* </p>
*
* @param registry dynamic property registry to be populated
*/
@DynamicPropertySource
static void startRabbitMqContainerAndSetProperties(DynamicPropertyRegistry registry) {
RabbitMqContainerHelper.setDynamicPropertyRegistry(registry, rabbitMQContainer);
registry.add(SPRING_AUDIT_DM_CLIENT_URL_KEY,
() -> getaUDITDmClientUrlValue(WireMockServerTest.getWireMockServerPort()));
}
/**
* Configures RestAssured to use the port assigned by Spring Boot.
*/
@BeforeEach
void beforeEach() {
RestAssured.port = localServerPort;
}
/**
* Stops the RabbitMq container after all tests are completed.
*/
@AfterAll
static void afterAll() {
RabbitMqContainerHelper.stopRabbitMqContainer(rabbitMQContainer);
}
// private
private static String getaUDITDmClientUrlValue(int port) {
return "http://localhost:%s/api/v1/dm".formatted(port);
}
}

View File

@ -0,0 +1,244 @@
package com.finconsgroup.itserr.marketplace.audit.bs.messaging.integration_tests;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.finconsgroup.itserr.marketplace.audit.bs.messaging.MessagingEventSubscriber;
import com.finconsgroup.itserr.marketplace.audit.bs.util.MessagingUtils;
import com.finconsgroup.itserr.marketplace.audit.bs.util.MockUtils;
import com.finconsgroup.itserr.marketplace.audit.bs.util.TestConstants;
import com.finconsgroup.itserr.marketplace.audit.dm.dto.InputCreateAuditLogDto;
import com.finconsgroup.itserr.messaging.dto.UntypedMessagingEventDto;
import com.finconsgroup.itserr.messaging.utils.CloudEventUtil;
import com.rabbitmq.stream.Environment;
import com.rabbitmq.stream.Message;
import com.rabbitmq.stream.Producer;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.Pair;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.stream.Stream;
import static com.finconsgroup.itserr.marketplace.audit.bs.util.TestConstants.MAX_WAIT_TIME_MESSAGE_HANDLED;
import static com.finconsgroup.itserr.marketplace.audit.bs.util.TestConstants.MAX_WAIT_TIME_MESSAGE_PRODUCED;
import static com.finconsgroup.itserr.marketplace.audit.bs.util.TestConstants.MESSAGE_RETRY_COUNT;
import static com.finconsgroup.itserr.marketplace.audit.bs.util.TestConstants.MESSAGING_STREAM_CONSUMER_DLQ_NAME_VALUE_FORMAT;
import static com.finconsgroup.itserr.marketplace.audit.bs.util.TestConstants.MESSAGING_STREAM_NAME_VALUE_FORMAT;
import static com.finconsgroup.itserr.marketplace.audit.bs.util.TestConstants.PRODUCER_NAME_ERROR_FORMAT;
import static com.finconsgroup.itserr.marketplace.audit.bs.util.TestConstants.PRODUCER_NAME_FORMAT;
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.containing;
import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson;
import static com.github.tomakehurst.wiremock.client.WireMock.post;
import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor;
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
/**
* Integration tests for {@link MessagingEventSubscriber}
* <p>
* The class uses Testcontainers to run integration tests against a real rabbitmq instance.
* <p>
*/
@Slf4j
public class MessagingEventSubscriberIntegrationTest extends AbstractIntegrationTest {
@Autowired
protected ObjectMapper objectMapper;
@Value("${audit_bs_messaging_host}")
private String auditBsMessagingHost;
@Value("${audit_bs_messaging_port}")
private String auditBsMessagingPort;
@Value("${audit_bs_messaging_vhost}")
private String auditBsMessagingVhost;
@Value("${audit_bs_messaging_auth_client_id}")
private String auditBsMessagingAuthClientId;
@Value("${audit_bs_messaging_auth_client_secret}")
private String auditBsMessagingAuthClientSecret;
@Captor
private ArgumentCaptor<Pair<String, UntypedMessagingEventDto>> eventMessageDlqCaptor;
@ParameterizedTest
@MethodSource("givenEventCreated_whenSendMessageToStream_thenMessageReceivedAndSentToDmService_source")
void givenEventCreated_whenSendMessageToStream_thenMessageReceivedAndSentToDmService(String stream) throws Exception {
// given
String createdEventType = "%s-event-created".formatted(stream);
String source = "%s-bs".formatted(stream);
UntypedMessagingEventDto messagePayload = MockUtils.generateUntypedMessagingEventDto();
configureCreateAuditLogOnAuditDmWireMock();
Producer producer = createProducer(stream, PRODUCER_NAME_FORMAT.formatted(stream, createdEventType));
Message message = MessagingUtils.createMessage(
producer, messagePayload.getId(), messagePayload, createdEventType, source);
InputCreateAuditLogDto expectedCreateAuditLogDto = MockUtils.generateInputCreateAuditLogDto(dto -> {
dto.setEventSource(source);
dto.setEventType(createdEventType);
});
// when
boolean messageSent = MessagingUtils.produceMessage(producer, message, MAX_WAIT_TIME_MESSAGE_PRODUCED);
// then
assertTrue(messageSent, "Cannot publish test message");
verifyCreateAuditLogRequestToAuditDm(expectedCreateAuditLogDto);
}
@ParameterizedTest
@MethodSource("givenInvalidMessage_whenSendMessageToStream_thenMessageReceivedAndSentToDlq_source")
void givenInvalidMessage_whenSendMessageToStream_thenMessageReceivedAndSentToDlq(String stream) throws Exception {
// given
String createdEventType = "%s-event-created".formatted(stream);
Object messagePayload = Map.of("testKey", "testValue");
configureCreateAuditLogOnAuditDmWireMockError();
Producer producer = createProducer(stream, PRODUCER_NAME_ERROR_FORMAT.formatted(stream, createdEventType));
Message message = MessagingUtils.createMessage(
producer, UUID.randomUUID().toString(), messagePayload, createdEventType, "%s-bs".formatted(stream));
Consumer<Pair<String, UntypedMessagingEventDto>> eventMessageDlqConsumer = createMockMessageConsumer();
TypeReference<UntypedMessagingEventDto> eventDtoTypeReference = new TypeReference<>() {
};
try (
com.rabbitmq.stream.Consumer eventMessageStreamConsumer = createEventMessageStreamDlqConsumer(stream,
"%s-created-event".formatted(stream), eventMessageDlqConsumer, eventDtoTypeReference)
) {
// when
boolean messageSent = MessagingUtils.produceMessage(producer, message, MAX_WAIT_TIME_MESSAGE_PRODUCED);
// then
assertTrue(messageSent, "Cannot publish test message");
await().atMost(MAX_WAIT_TIME_MESSAGE_HANDLED, TimeUnit.SECONDS).untilAsserted(() ->
wireMockServer().verify(MESSAGE_RETRY_COUNT, postRequestedFor(urlEqualTo("/api/v1/dm/audit/audit-logs")))
);
MessagingUtils.verifyMessageProduced(MAX_WAIT_TIME_MESSAGE_HANDLED, () -> {
verify(eventMessageDlqConsumer).accept(eventMessageDlqCaptor.capture());
assertThat(eventMessageDlqCaptor.getValue().getLeft()).isEqualTo(createdEventType);
});
}
}
// private
private void configureCreateAuditLogOnAuditDmWireMock() throws Exception {
wireMockServer()
.stubFor(post(urlEqualTo("/api/v1/dm/audit/audit-logs"))
.withHeader("Content-Type", containing("application/json"))
.willReturn(aResponse()
.withStatus(201)
.withHeader("Content-Type", "application/json")
.withBody(mapObjectToJson(MockUtils.generateOutputAuditLogDto()))));
}
private void configureCreateAuditLogOnAuditDmWireMockError() throws Exception {
wireMockServer()
.stubFor(post(urlEqualTo("/api/v1/dm/audit/audit-logs"))
.withHeader("Content-Type", containing("application/json"))
.willReturn(aResponse()
.withStatus(400)
.withHeader("Content-Type", "application/json")
.withBody(mapObjectToJson(Map.of("messages", List.of("id: cannot be null"))))));
}
private void verifyCreateAuditLogRequestToAuditDm(InputCreateAuditLogDto inputCreateAuditLogDto) throws JsonProcessingException {
// ignore eventCreationTime
inputCreateAuditLogDto.setEventCreationTime(null);
String expectedJson = CloudEventUtil.getObjectMapper()
.writeValueAsString(inputCreateAuditLogDto)
.replaceAll(",\"eventCreationTime\":null", "")
.replaceAll("\"eventCreationTime\":null,", "");
await().atMost(TestConstants.MAX_WAIT_TIME_MESSAGE_HANDLED, TimeUnit.SECONDS).untilAsserted(() ->
wireMockServer().verify(postRequestedFor(urlEqualTo("/api/v1/dm/audit/audit-logs"))
.withRequestBody(equalToJson(expectedJson, false, true)))
);
}
private Producer createProducer(String stream, String producerName) {
Environment environment = MessagingUtils.createEnvironment(
auditBsMessagingHost,
auditBsMessagingPort,
auditBsMessagingVhost,
auditBsMessagingAuthClientId,
auditBsMessagingAuthClientSecret
);
String streamName = MESSAGING_STREAM_NAME_VALUE_FORMAT.formatted(stream);
return MessagingUtils.createProducer(environment, producerName, streamName);
}
@SuppressWarnings("unchecked")
private static <T> Consumer<T> createMockMessageConsumer() {
return (Consumer<T>) mock(Consumer.class);
}
private <T> com.rabbitmq.stream.Consumer createEventMessageStreamDlqConsumer(String stream,
String consumerName,
Consumer<Pair<String, T>> messageConsumer,
TypeReference<T> typeReference) {
String streamName = MESSAGING_STREAM_CONSUMER_DLQ_NAME_VALUE_FORMAT.formatted(stream);
return createConsumer(consumerName, streamName, typeReference, messageConsumer);
}
private <T> com.rabbitmq.stream.Consumer createConsumer(String consumerName,
String streamName,
TypeReference<T> typeReference,
Consumer<Pair<String, T>> messageConsumer) {
Environment environment = MessagingUtils.createEnvironment(
auditBsMessagingHost,
auditBsMessagingPort,
auditBsMessagingVhost,
auditBsMessagingAuthClientId,
auditBsMessagingAuthClientSecret
);
return MessagingUtils.createConsumer(environment, consumerName, streamName, typeReference, messageConsumer);
}
/**
* Maps the object to its json string representation
*
* @param value the object to map
* @return json string representation of the object
* @throws Exception in case of any errors
*/
private String mapObjectToJson(Object value) throws Exception {
return objectMapper.writeValueAsString(value);
}
public static Stream<Arguments> givenEventCreated_whenSendMessageToStream_thenMessageReceivedAndSentToDmService_source() {
return supportedStreamNames_source();
}
public static Stream<Arguments> givenInvalidMessage_whenSendMessageToStream_thenMessageReceivedAndSentToDlq_source() {
return supportedStreamNames_source();
}
public static Stream<Arguments> supportedStreamNames_source() {
return TestConstants.SUPPORTED_STREAMS.stream().map(Arguments::of);
}
}

View File

@ -0,0 +1,59 @@
package com.finconsgroup.itserr.marketplace.audit.bs.service.impl;
import com.finconsgroup.itserr.marketplace.audit.bs.dto.InputCreateAuditLogDto;
import com.finconsgroup.itserr.marketplace.audit.bs.dto.OutputAuditLogDto;
import com.finconsgroup.itserr.marketplace.audit.bs.mapper.AuditLogMapper;
import com.finconsgroup.itserr.marketplace.audit.bs.util.MockUtils;
import com.finconsgroup.itserr.marketplace.audit.dm.client.AuditDmClient;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
/**
* Unit tests for {@link DefaultAuditLogServiceTest}.
*/
@ExtendWith(MockitoExtension.class)
public class DefaultAuditLogServiceTest {
private AuditDmClient auditDmClient;
private AuditLogMapper AuditLogMapper;
private DefaultAuditLogService service;
/**
* Set up mocks before each test.
*/
@BeforeEach
void setUp() {
auditDmClient = mock(AuditDmClient.class);
AuditLogMapper = mock(AuditLogMapper.class);
// And a service instance with mocked repository and mapper
service = new DefaultAuditLogService(auditDmClient, AuditLogMapper);
}
@Test
void givenNewAuditLog_whenCreateAuditLog_thenSaveAndReturnDto() {
// Given
InputCreateAuditLogDto inputDto = MockUtils.generateInputCreateAuditLogDto();
OutputAuditLogDto expectedDto = MockUtils.generateOutputAuditLogDto();
doReturn(expectedDto).when(auditDmClient).createAuditLog(inputDto);
doReturn(expectedDto).when(AuditLogMapper).auditLogDmDtoToBsDto(expectedDto);
// When
OutputAuditLogDto result = service.create(inputDto);
// Then
assertThat(result).isEqualTo(expectedDto);
verify(auditDmClient).createAuditLog(inputDto);
}
}

View File

@ -0,0 +1,140 @@
package com.finconsgroup.itserr.marketplace.audit.bs.util;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.finconsgroup.itserr.messaging.utils.CloudEventUtil;
import com.rabbitmq.stream.Address;
import com.rabbitmq.stream.Consumer;
import com.rabbitmq.stream.ConsumerBuilder;
import com.rabbitmq.stream.Environment;
import com.rabbitmq.stream.Message;
import com.rabbitmq.stream.MessageHandler;
import com.rabbitmq.stream.OffsetSpecification;
import com.rabbitmq.stream.Producer;
import io.cloudevents.CloudEvent;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.Pair;
import org.awaitility.core.ThrowingRunnable;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import static org.awaitility.Awaitility.await;
/**
* Utility class for handling RabbitMQ stream messaging operations used in integration tests.
* <p>
* Provides methods to:
* <ul>
* <li>Create and configure a RabbitMQ {@link Environment}</li>
* <li>Initialize a {@link Producer} with super stream and routing</li>
* <li>Create a CloudEvent-based {@link Message}</li>
* <li>Send a message with confirmation and timeout control</li>
* </ul>
*/
@Slf4j
public class MessagingUtils {
public static Environment createEnvironment(
String host,
String port,
String virtualHost,
String authClientId,
String authClientSecret
) {
Address entryPoint = new Address(host, Integer.parseInt(port));
return Environment.builder()
.uri(String.format("rabbitmq-stream://%s:%s", host, port))
.virtualHost(virtualHost)
.username(authClientId)
.password(authClientSecret)
.addressResolver(address -> entryPoint)
.build();
}
public static Producer createProducer(
Environment environment,
String producerName,
String superStreamName
) {
return environment.producerBuilder()
.name(producerName)
.superStream(superStreamName)
.routing(message -> message.getProperties().getMessageIdAsString())
.producerBuilder().build();
}
public static Message createMessage(
Producer producer,
String resourceId,
Object resourcePayload,
String eventType,
String source
) throws JsonProcessingException {
byte[] cloudEventBytes = CloudEventUtil.createCloudEventPayload(resourcePayload, eventType, source);
return producer.messageBuilder()
.properties()
.messageId(resourceId)
.messageBuilder()
.addData(cloudEventBytes)
.build();
}
public static boolean produceMessage(
Producer producer,
Message message,
long maxWaitTimeMessageProducedInSecond
) throws InterruptedException, ExecutionException, TimeoutException {
CompletableFuture<Boolean> result = new CompletableFuture<>();
producer.send(message, confirmationStatus -> {
if (confirmationStatus.isConfirmed()) {
result.complete(true);
} else {
result.complete(false);
}
});
return result.get(maxWaitTimeMessageProducedInSecond, TimeUnit.SECONDS);
}
public static <T> Consumer createConsumer(
Environment environment,
String consumerName,
String superStreamName,
TypeReference<T> typeReference,
java.util.function.Consumer<Pair<String, T>> messageConsumer
) {
MessageHandler messageHandler = (context, message) -> {
try {
// Unique message ID
String messageId = message.getProperties().getMessageId().toString();
String jsonMessage = new String(message.getBodyAsBinary(), StandardCharsets.UTF_8);
CloudEvent cloudEvent = CloudEventUtil.deserializeCloudEvent(jsonMessage);
context.storeOffset();
T data = CloudEventUtil.extractDataWithType(cloudEvent, typeReference);
log.info("Successfully processed and Acknowledged message [ID: {}], with data: {}", messageId, data);
messageConsumer.accept(Pair.of(cloudEvent.getType(), data));
} catch (Exception e) {
throw new RuntimeException(e);
}
};
ConsumerBuilder consumerBuilder = environment.consumerBuilder()
.name(consumerName)
.superStream(superStreamName)
.offset(OffsetSpecification.next())
.messageHandler(messageHandler);
consumerBuilder.autoTrackingStrategy();
return consumerBuilder.build();
}
public static void verifyMessageProduced(long maxWaitTimeInSeconds, ThrowingRunnable runnable) {
await().atMost(maxWaitTimeInSeconds, TimeUnit.SECONDS).untilAsserted(runnable);
}
}

View File

@ -0,0 +1,107 @@
package com.finconsgroup.itserr.marketplace.audit.bs.util;
import com.finconsgroup.itserr.marketplace.audit.bs.dto.InputCreateAuditLogDto;
import com.finconsgroup.itserr.marketplace.audit.bs.dto.OutputAuditLogDto;
import com.finconsgroup.itserr.marketplace.audit.dm.dto.InputAuditLogResourceDto;
import com.finconsgroup.itserr.marketplace.audit.dm.dto.InputAuditLogUserDto;
import com.finconsgroup.itserr.marketplace.audit.dm.dto.OutputAuditLogResourceDto;
import com.finconsgroup.itserr.marketplace.audit.dm.dto.OutputAuditLogUserDto;
import com.finconsgroup.itserr.messaging.dto.MessagingEventUserDto;
import com.finconsgroup.itserr.messaging.dto.UntypedMessagingEventDto;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.RandomStringUtils;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Map;
import java.util.UUID;
import java.util.function.Consumer;
/**
* Utility class for generating mock DTO instances used in unit tests.
* <p>
* Provides methods to create fully populated DTOs, including nested objects, to simplify test setup and ensure consistent test data across test cases.
* </p>
*/
@NoArgsConstructor
public final class MockUtils {
private static final Instant EVENT_ACTION_TIME = Instant.now().truncatedTo(ChronoUnit.MICROS);
private static final Instant EVENT_CREATION_TIME = EVENT_ACTION_TIME.plus(1, ChronoUnit.HOURS).truncatedTo(ChronoUnit.MICROS);
private static final Instant CREATION_TIME = EVENT_ACTION_TIME.plus(2, ChronoUnit.HOURS).truncatedTo(ChronoUnit.MICROS);
public static final UUID USER_ID = UUID.randomUUID();
public static final UUID AUDIT_LOG_ID = UUID.randomUUID();
public static final UUID RESOURCE_ID = UUID.randomUUID();
public static InputCreateAuditLogDto generateInputCreateAuditLogDto() {
return InputCreateAuditLogDto.builder()
.eventSource("catalog-bs")
.eventType("catalog-item-event-created")
.user(InputAuditLogUserDto.builder()
.id(USER_ID)
.username("john.doe1234")
.name("John Doe")
.build())
.resource(InputAuditLogResourceDto.builder()
.id(RESOURCE_ID.toString())
.name("Talmud")
.title("Test Title")
.category("dataset")
.status("approved")
.build())
.eventAdditionalData(Map.of("key1", "value1", "key2", "value2"))
.eventActionTime(EVENT_ACTION_TIME)
.eventCreationTime(EVENT_CREATION_TIME)
.build();
}
public static InputCreateAuditLogDto generateInputCreateAuditLogDto(Consumer<InputCreateAuditLogDto> postProcessor) {
InputCreateAuditLogDto inputCreateAuditLogDto = MockUtils.generateInputCreateAuditLogDto();
postProcessor.accept(inputCreateAuditLogDto);
return inputCreateAuditLogDto;
}
public static OutputAuditLogDto generateOutputAuditLogDto() {
return OutputAuditLogDto.builder()
.id(AUDIT_LOG_ID)
.eventSource("catalog-bs")
.eventType("catalog-item-event-created")
.user(OutputAuditLogUserDto.builder()
.id(USER_ID)
.username("john.doe1234")
.name("John Doe")
.build())
.resource(OutputAuditLogResourceDto.builder()
.id(RESOURCE_ID.toString())
.name("Talmud")
.title("Test Title")
.category("dataset")
.status("approved")
.build())
.eventAdditionalData(Map.of("key1", "value1", "key2", "value2"))
.eventActionTime(EVENT_ACTION_TIME)
.eventCreationTime(EVENT_CREATION_TIME)
.creationTime(CREATION_TIME)
.build();
}
public static UntypedMessagingEventDto generateUntypedMessagingEventDto() {
return UntypedMessagingEventDto.builder()
.id(RESOURCE_ID.toString())
.user(MessagingEventUserDto.builder()
.id(USER_ID)
.username("john.doe1234")
.name("John Doe")
.build())
.name("Talmud")
.title("Test Title")
.category("dataset")
.status("approved")
.additionalData(Map.of("key1", "value1", "key2", "value2"))
.timestamp(EVENT_ACTION_TIME)
.build();
}
}

View File

@ -0,0 +1,160 @@
package com.finconsgroup.itserr.marketplace.audit.bs.util;
import lombok.extern.slf4j.Slf4j;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.testcontainers.containers.RabbitMQContainer;
import org.testcontainers.utility.MountableFile;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import static com.finconsgroup.itserr.marketplace.audit.bs.util.TestConstants.MESSAGING_STREAM_CONSUMER_DLQ_NAME_VALUE_FORMAT;
import static com.finconsgroup.itserr.marketplace.audit.bs.util.TestConstants.MESSAGING_STREAM_NAME_VALUE_FORMAT;
import static com.finconsgroup.itserr.marketplace.audit.bs.util.TestConstants.SUPPORTED_STREAMS;
/**
* Utility class for managing the lifecycle and configuration
* of RabbitMq Testcontainers.
*/
@Slf4j
public class RabbitMqContainerHelper {
/**
* Docker container RabbitMq image name
*/
private static final String RABBITMQ_IMAGE_NAME = "rabbitmq:3.13.7-management";
/**
* RabbitMq configuration file
*/
private static final String RABBITMQ_MESSAGING_CONF = "rabbitmq/rabbitmq.conf";
/**
* RabbitMq Container configuration property values.
* <p>
* These values define messaging settings such as ports, credentials, and stream names,
* and are used to configure the RabbitMq container.
* </p>
*/
private static final int MESSAGING_STREAM_PORT_VALUE = 5552;
private static final int MESSAGING_UI_MANAGEMENT_PORT_VALUE = 15672;
private static final String MESSAGING_USERNAME_VALUE = "test_user";
private static final String MESSAGING_PASSWORD_VALUE = "test_password";
private static final String MESSAGING_VIRTUAL_HOST_VALUE = "itserr_vhost";
/**
* Messaging property keys.
* <p>
* These keys are used to dynamically inject container-generated messaging properties
* (such as port, virtual host, stream name) at runtime into the Spring context.
* Static configuration in {@code application-*.yml} will not work when using Testcontainers.
* </p>
*/
private static final String SPRING_MESSAGING_HOST_KEY = "audit_bs_messaging_host";
private static final String SPRING_MESSAGING_PORT_KEY = "audit_bs_messaging_port";
private static final String SPRING_MESSAGING_USERNAME_KEY = "audit_bs_messaging_auth_client_id";
private static final String SPRING_MESSAGING_PASSWORD_KEY = "audit_bs_messaging_auth_client_secret";
private static final String SPRING_MESSAGING_VIRTUAL_HOST_KEY = "audit_bs_messaging_vhost";
private static final String SPRING_MESSAGING_STREAM_NAME_KEY_FORMAT = "audit_bs_messaging_%s_bs_event_stream_name";
private static final String SPRING_MESSAGING_STREAM_CONSUMER_DLQ_NAME_KEY_FORMAT = "audit_bs_messaging_%s_bs_event_stream_consumer_dlq_name";
private static final String SPRING_MESSAGING_STREAM_CONSUMER_ENABLED_KEY_FORMAT = "audit_bs_messaging_%s_bs_event_stream_consumer_enabled";
/**
* Starts a new RabbitMqContainer instance
* using predefined configuration constants.
*
* @return a running instance of RabbitMqContainer
*/
public static RabbitMQContainer startRabbitMqContainer() throws IOException, InterruptedException {
RabbitMQContainer rabbitMqContainer = new RabbitMQContainer(RABBITMQ_IMAGE_NAME)
.withExposedPorts(MESSAGING_STREAM_PORT_VALUE, MESSAGING_UI_MANAGEMENT_PORT_VALUE)
.withAdminUser(MESSAGING_USERNAME_VALUE)
.withAdminPassword(MESSAGING_PASSWORD_VALUE)
.withRabbitMQConfig(MountableFile.forClasspathResource(RABBITMQ_MESSAGING_CONF))
.withReuse(true);
rabbitMqContainer.start();
configureRabbitMq(rabbitMqContainer);
return rabbitMqContainer;
}
/**
* Configure RabbitMqContainer instance
* Enable plugins, Create virtual host, Create streams
*/
private static void configureRabbitMq(RabbitMQContainer rabbitMQContainer) throws IOException, InterruptedException {
List<String[]> commands = new ArrayList<>();
// Enable plugins
commands.add(new String[]{"rabbitmq-plugins", "enable", "rabbitmq_management", "rabbitmq_stream"});
// Add vhost
commands.add(new String[]{"rabbitmqctl", "add_vhost", MESSAGING_VIRTUAL_HOST_VALUE});
// Set guest permissions on vhost
commands.add(new String[]{"rabbitmqctl", "set_permissions", "-p", MESSAGING_VIRTUAL_HOST_VALUE, MESSAGING_USERNAME_VALUE, ".*", ".*", ".*"});
for (String stream : SUPPORTED_STREAMS) {
// Create event super stream
commands.add(new String[]{
"rabbitmq-streams", "add_super_stream", MESSAGING_STREAM_NAME_VALUE_FORMAT.formatted(stream),
"--vhost", MESSAGING_VIRTUAL_HOST_VALUE, "--partitions", "3"
});
// Create event dlq super stream
commands.add(new String[]{
"rabbitmq-streams", "add_super_stream", MESSAGING_STREAM_CONSUMER_DLQ_NAME_VALUE_FORMAT.formatted(stream),
"--vhost", MESSAGING_VIRTUAL_HOST_VALUE, "--partitions", "3"
});
}
for (String[] command : commands) {
rabbitMQContainer.execInContainer(command);
}
}
/**
* Stops the provided RabbitMqContainer instance.
*
* @param rabbitMqContainer the container to stop
*/
public static void stopRabbitMqContainer(RabbitMQContainer rabbitMqContainer) {
if (rabbitMqContainer != null && rabbitMqContainer.isRunning()) {
rabbitMqContainer.stop();
}
}
/**
* Registers dynamic properties for the
* Spring test context using the given container.
* <p>
* These properties must be defined programmatically at runtime.
* Setting these properties statically in {@code application-*.yml}
* will not work, Spring will fail to connect to the container.
* </p>
*
* @param registry the dynamic property registry to populate
* @param rabbitMqContainer the RabbitMq container instance
*/
public static void setDynamicPropertyRegistry(DynamicPropertyRegistry registry, RabbitMQContainer rabbitMqContainer) {
String host = rabbitMqContainer.getHost();
int streamPort = rabbitMqContainer.getMappedPort(MESSAGING_STREAM_PORT_VALUE);
int uiManagementPort = rabbitMqContainer.getMappedPort(MESSAGING_UI_MANAGEMENT_PORT_VALUE);
String username = rabbitMqContainer.getAdminUsername();
String password = rabbitMqContainer.getAdminPassword();
registry.add(SPRING_MESSAGING_HOST_KEY, () -> host);
registry.add(SPRING_MESSAGING_PORT_KEY, () -> streamPort);
registry.add(SPRING_MESSAGING_USERNAME_KEY, () -> username);
registry.add(SPRING_MESSAGING_PASSWORD_KEY, () -> password);
registry.add(SPRING_MESSAGING_VIRTUAL_HOST_KEY, () -> MESSAGING_VIRTUAL_HOST_VALUE);
for (String stream : SUPPORTED_STREAMS) {
registry.add(SPRING_MESSAGING_STREAM_NAME_KEY_FORMAT.formatted(stream), () -> MESSAGING_STREAM_NAME_VALUE_FORMAT.formatted(stream));
registry.add(SPRING_MESSAGING_STREAM_CONSUMER_DLQ_NAME_KEY_FORMAT.formatted(stream), () -> MESSAGING_STREAM_CONSUMER_DLQ_NAME_VALUE_FORMAT.formatted(stream));
registry.add(SPRING_MESSAGING_STREAM_CONSUMER_ENABLED_KEY_FORMAT.formatted(stream), () -> true);
}
log.info("TestContainer RabbitMq started — " +
"host: {}, username: {}, password: {}, stream port: {}, ui management port: {}",
host, username, password, streamPort, uiManagementPort);
}
}

View File

@ -0,0 +1,15 @@
package com.finconsgroup.itserr.marketplace.audit.bs.util;
import java.util.Set;
public class TestConstants {
public static final Set<String> SUPPORTED_STREAMS = Set.of("catalog", "event", "workspace");
public static final String PRODUCER_NAME_FORMAT = "test-producer-%s-%s";
public static final String PRODUCER_NAME_ERROR_FORMAT = "test-producer-error-%s-%s";
public static final String MESSAGING_STREAM_NAME_VALUE_FORMAT = "itserr-stream-%s-event";
public static final String MESSAGING_STREAM_CONSUMER_DLQ_NAME_VALUE_FORMAT = "itserr-stream-%s-event-dlq";
public static final int MAX_WAIT_TIME_MESSAGE_PRODUCED = 3;
public static final int MAX_WAIT_TIME_MESSAGE_HANDLED = 7;
public static final int MESSAGE_RETRY_COUNT = 2;
}

View File

@ -0,0 +1,37 @@
audit_bs_server_port: 8080
audit_bs_zipkin_tracing_export_enabled: false
audit_bs_swagger_api_server_url: http://localhost:8080/api/v1/bs
audit_dm_client_url: http://localhost:8080/api/v1/dm
audit_bs_log_base_folder: logs
# reduce the number of retries and backoff ms for integration tests
audit_bs_messaging_default_event_stream_consumer_retry_attempts: 2
audit_bs_messaging_default_event_stream_consumer_retry_backoff_ms: 300
# Messaging
audit_bs_messaging_enabled: true
audit_bs_messaging_host: ignored
audit_bs_messaging_port: ignored
audit_bs_messaging_vhost: ignored
audit_bs_messaging_auth_keycloak_token_url:
audit_bs_messaging_auth_client_id: ignored
audit_bs_messaging_auth_client_secret: ignored
audit_bs_messaging_catalog_bs_event_stream_consumer_enabled: true
audit_bs_messaging_catalog_bs_event_stream_name: ignored
audit_bs_messaging_catalog_bs_event_stream_consumer_dlq_name: ignored
audit_bs_messaging_event_bs_event_stream_consumer_enabled: true
audit_bs_messaging_event_bs_event_stream_name: ignored
audit_bs_messaging_event_bs_event_stream_consumer_dlq_name: ignored
audit_bs_messaging_workspace_bs_event_stream_consumer_enabled: true
audit_bs_messaging_workspace_bs_event_stream_name: ignored
audit_bs_messaging_workspace_bs_event_stream_consumer_dlq_name: ignored
logging:
level:
com.finconsgroup.itserr.messaging.utils.CloudEventUtil: TRACE

View File

@ -0,0 +1,11 @@
audit_bs_server_port: 8080
audit_bs_zipkin_tracing_export_enabled: false
audit_bs_swagger_api_server_url: http://localhost:8080/api/v1/bs
audit_dm_client_url: http://localhost:8080/api/v1/dm
audit_bs_log_base_folder: logs
audit_bs_messaging_enabled: false

View File

@ -0,0 +1,6 @@
auth_backends.1 = rabbit_auth_backend_internal
stream.listeners.tcp.1 = 5552
log.file.level = debug
log.default.level = debug
log.console.level = debug