diff --git a/.aliases b/.aliases index ae9ceaf0..9477474d 100644 --- a/.aliases +++ b/.aliases @@ -44,7 +44,7 @@ alias podman-stop='systemctl --user disable --now podman.socket && systemctl --u alias podman-use='export DOCKER_HOST="unix:///run/user/$UID/podman/podman.sock"; export TESTCONTAINERS_RYUK_DISABLED=true' alias gw=gradleWrapper -alias pg-sql-run='docker run --name hsadmin-ng-postgres -e POSTGRES_PASSWORD=password -p 5432:5432 -d postgres:13.7-bullseye' +alias pg-sql-run='docker run --name hsadmin-ng-postgres -e POSTGRES_PASSWORD=password -p 5432:5432 -d postgres:15.5-bookworm' alias pg-sql-stop='docker stop hsadmin-ng-postgres' alias pg-sql-start='docker container start hsadmin-ng-postgres' alias pg-sql-remove='docker rm hsadmin-ng-postgres' diff --git a/README.md b/README.md index a3a1c6e5..54667c20 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ For architecture consider the files in the `doc` and `adr` folder. - [Directory and Package Structure](#directory-and-package-structure) - [General Directory Structure](#general-directory-structure) - [Source Code Package Structure](#source-code-package-structure) + - [Run Tests from Command Line](#run-tests-from-command-line) - [Spotless Code Formatting](#spotless-code-formatting) - [JaCoCo Test Code Coverage Check](#jacoco-test-code-coverage-check) - [PiTest Mutation Testing](#pitest-mutation-testing) @@ -39,6 +40,7 @@ For architecture consider the files in the `doc` and `adr` folder. - [How to Use a Persistent Database for Integration Tests?](#how-to-use-a-persistent-database-for-integration-tests?) - [How to Amend Liquibase SQL Changesets?](#how-to-amend-liquibase-sql-changesets?) - [How to Re-Generate Spring-Controller-Interfaces from OpenAPI specs?](#how-to-re-generate-spring-controller-interfaces-from-openapi-specs?) + - [How to Generate Database Table Diagrams?](#how-to-generate-database-table-diagrams?) - [Further Documentation](#further-documentation) <!-- generated TOC end. --> @@ -50,7 +52,7 @@ Everything is tested on _Ubuntu Linux 22.04_ and _MacOS Monterey (12.4)_. To be able to build and run the Java Spring Boot application, you need the following tools: - Docker 20.x (on MacOS you also need *Docker Desktop* or similar) -- PostgreSQL Server 13.7-bullseye +- PostgreSQL Server 15.5-bookworm (see instructions below to install and run in Docker) - Java JDK at least recent enough to run Gradle (JDK 17.x will be automatically installed by Gradle toolchain support) @@ -133,14 +135,14 @@ But the easiest way to run PostgreSQL is via Docker. Initially, pull an image compatible to current PostgreSQL version of Hostsharing: - docker pull postgres:13.7-bullseye + docker pull postgres:15.5-bookworm <big>**⚠**</big> If we switch the version, please also amend the documentation as well as the aliases file. Thanks! Create and run a container with the given PostgreSQL version: - docker run --name hsadmin-ng-postgres -e POSTGRES_PASSWORD=password -p 5432:5432 -d postgres:13.7-bullseye + docker run --name hsadmin-ng-postgres -e POSTGRES_PASSWORD=password -p 5432:5432 -d postgres:15.5-bookworm # or via alias: pg-sql-run @@ -199,7 +201,7 @@ To generate the TOC (Table of Contents), a little bash script from a Given this is in PATH as `md-toc`, use: ```shell -md-toc <README.md 2 4 | sed -e 's/^ //g' +md-toc <README.md 2 4 | cut -c5-' ``` To render the Markdown files, especially to watch embedded PlantUML diagrams, you can use one of the following methods: @@ -233,12 +235,19 @@ sudo apt install graphviz ##### Ubuntu Linux command line -```sh -sudo apt-get install pandoc texlive-latex-base texlive-fonts-recommended texlive-extra-utils texlive-latex-extra pandoc-plantuml-filter +1. Install Pandoc with some extra libraries: +```shell +sudo apt-get install pandoc texlive-latex-base texlive-fonts-recommended texlive-extra-utils texlive-latex-extra pandoc-plantuml-filter ``` -```sh -pandoc --filter pandoc-plantuml rbac.md -o rbac.pdf +2. Install mermaid-filter, e.g. this way: +```shell +npm install -g mermaid-filter +``` + +3. Run Pandoc to generate a PDF from a Markdown file with PlantUML and Mermaid diagrams: +```shell +pandoc --filter mermaid-filter --filter pandoc-plantuml rbac.md -o rbac.pdf ``` ##### for other IDEs / operating systems @@ -247,7 +256,7 @@ If you have figured out how it works, please add instructions above this section #### Render Markdown Embedded Mermaid Diagrams -The source of RBAC role diagrams are much easier to read with Mermaid than with PlantUML or GraphViz, that's the main reason Mermaid ist used too. +The source of RBAC role diagrams are much easier to read with Mermaid than with PlantUML or GraphViz, that's also the main reason Mermaid is used. Can you see the following diagram right in your IDE? I mean a real graphic diagram, not just some markup code. @@ -271,8 +280,11 @@ If not, you need to install some tooling. ##### for IntelliJ IDEA (or derived products) -You just need the bundled Markdown plugin enabled and install and activate the Mermaid plugin in its [settings](jetbrains://idea/settings?name=Languages+%26+Frameworks--Markdown). +1. Activate the bundled Jebrains Markdown PlantUML Extension via + [File | Settings | Languages & Frameworks | Markdown](jetbrains://idea/settings?name=Languages+%26+Frameworks--Markdown) +2. Install the Jetbrains Mermaid plugin: https://plugins.jetbrains.com/plugin/20146-mermaid, it also works embedded in Markdown files. +Now the above diagram should be rendered. ##### for other IDEs / command-line / operating systems @@ -282,13 +294,23 @@ If you have figured out how it works, please add instructions above this section #### IntelliJ IDEA +##### Build Settings + Go to [Gradle Settings}(jetbrains://idea/settings?name=Build%2C+Execution%2C+Deployment--Build+Tools--Gradle) and select "Build and run using" and "Run tests using" both to "gradle". Otherwise, settings from `build.gradle`, like compiler arguments, are not applied when compiling through *IntelliJ IDEA*. +##### Annotation Processor + Go to [Annotations Processors](jetbrains://idea/settings?name=Build%2C+Execution%2C+Deployment--Compiler--Annotation+Processors) and activate annotation processing. Otherwise, *IntelliJ IDEA* can't see *Lombok* generated classes and will show false errors (missing identifiers). + +##### Suggested Plugins + +- [Jetbrains Mermaid Integration](https://plugins.jetbrains.com/plugin/20146-mermaid) +- [Vojtěch Krása PlantUML Integration](https://plugins.jetbrains.com/plugin/7017-plantuml-integration) + ### Other Tools **jq**: a JSON formatter. diff --git a/build.gradle b/build.gradle index 1be9d95f..b43f22e1 100644 --- a/build.gradle +++ b/build.gradle @@ -1,15 +1,15 @@ plugins { id 'java' - id 'org.springframework.boot' version '3.0.0' - id 'io.spring.dependency-management' version '1.1.0' - id 'io.openapiprocessor.openapi-processor' version '2022.2' - id 'com.github.jk1.dependency-license-report' version '2.1' - id "org.owasp.dependencycheck" version "7.3.0" - id "com.diffplug.spotless" version "6.11.0" + id 'org.springframework.boot' version '3.1.7' + id 'io.spring.dependency-management' version '1.1.4' + id 'io.openapiprocessor.openapi-processor' version '2023.2' + id 'com.github.jk1.dependency-license-report' version '2.5' + id "org.owasp.dependencycheck" version "9.0.7" + id "com.diffplug.spotless" version "6.23.3" id 'jacoco' - id 'info.solidsoft.pitest' version '1.9.0' + id 'info.solidsoft.pitest' version '1.15.0' id 'se.patrikerdes.use-latest-versions' version '0.2.18' - id 'com.github.ben-manes.versions' version '0.43.0' + id 'com.github.ben-manes.versions' version '0.50.0' } group = 'net.hostsharing' @@ -17,7 +17,7 @@ version = '0.0.1-SNAPSHOT' wrapper { distributionType = Wrapper.DistributionType.BIN - gradleVersion = '7.5' + gradleVersion = '8.5' } configurations { @@ -42,7 +42,7 @@ repositories { java { toolchain { - languageVersion = JavaLanguageVersion.of(17) + languageVersion = JavaLanguageVersion.of(21) } } @@ -50,31 +50,41 @@ ext { set('testcontainersVersion', "1.17.3") } -// wrapper - dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-data-rest' implementation 'org.springframework.boot:spring-boot-starter-jdbc' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-validation' - implementation 'com.github.gavlyukovskiy:datasource-proxy-spring-boot-starter:1.8.1' - implementation 'org.springdoc:springdoc-openapi:2.0.0-M7' - implementation 'org.liquibase:liquibase-core' - implementation 'com.vladmihalcea:hibernate-types-60:2.20.0' - implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.4' - implementation 'org.openapitools:jackson-databind-nullable:0.2.4' - implementation 'org.apache.commons:commons-text:1.10.0' - implementation 'org.modelmapper:modelmapper:3.1.0' - implementation 'org.iban4j:iban4j:3.2.3-RELEASE' - implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0' + implementation 'com.github.gavlyukovskiy:datasource-proxy-spring-boot-starter:1.9.1' + implementation 'org.springdoc:springdoc-openapi:2.3.0' + implementation 'org.postgresql:postgresql:42.7.1' + implementation 'org.liquibase:liquibase-core:4.25.1' + implementation 'com.vladmihalcea:hibernate-types-60:2.21.1' + implementation 'io.hypersistence:hypersistence-utils-hibernate-62:3.7.0' + implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.16.1' + implementation 'org.openapitools:jackson-databind-nullable:0.2.6' + implementation 'org.apache.commons:commons-text:1.11.0' + implementation 'org.modelmapper:modelmapper:3.2.0' + implementation 'org.iban4j:iban4j:3.2.7-RELEASE' + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0' + + // fixes vulnerability CVE-2022-1471 + // The dependency usually comes from Spring Boot, just in the wrong version. + // TODO: Remove this explicit dependency once we are on SpringBoot 3.2.x + // as well as the related exclude in settings.gradle + // and the dependency suppression in owasp-dependency-check-suppression.xml. + implementation('org.yaml:snakeyaml') { + version { + strictly('2.2') + } + } compileOnly 'org.projectlombok:lombok' testCompileOnly 'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' - runtimeOnly 'org.postgresql:postgresql' annotationProcessor 'org.projectlombok:lombok' testAnnotationProcessor 'org.projectlombok:lombok' @@ -82,11 +92,12 @@ dependencies { testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.testcontainers:testcontainers' testImplementation 'org.testcontainers:junit-jupiter' + testImplementation 'org.junit.jupiter:junit-jupiter' testImplementation 'org.testcontainers:postgresql' - testImplementation 'com.tngtech.archunit:archunit-junit5:1.0.0' + testImplementation 'com.tngtech.archunit:archunit-junit5:1.2.1' testImplementation 'io.rest-assured:spring-mock-mvc' testImplementation 'org.hamcrest:hamcrest-core:2.2' - testImplementation 'org.pitest:pitest-junit5-plugin:1.1.0' + testImplementation 'org.pitest:pitest-junit5-plugin:1.2.1' } dependencyManagement { @@ -171,7 +182,7 @@ openApiGenerate.dependsOn processSpring // Spotless Code Formatting spotless { java { - // removeUnusedImports() TODO: reactivate once it can deal with multi-line-strings + removeUnusedImports() indentWithSpaces(4) endWithNewline() toggleOffOn() @@ -183,14 +194,24 @@ spotless { } } project.tasks.check.dependsOn(spotlessCheck) +// HACK: no idea why spotless uses the output of these tasks, but we get warnings without those +project.tasks.spotlessJava.dependsOn( + tasks.generateLicenseReport, + tasks.pitest, + tasks.jacocoTestReport, + tasks.processResources, + tasks.processTestResources) // OWASP Dependency Security Test dependencyCheck { - cveValidForHours=4 + nvd { + apiKey = project.property('OWASP_API_KEY') // set it in ~/.gradle/gradle.properties + delay = 16000 + } format = 'ALL' suppressionFile = 'etc/owasp-dependency-check-suppression.xml' failOnError = true - failBuildOnCVSS = 7 + failBuildOnCVSS = 5 } project.tasks.check.dependsOn(dependencyCheckAnalyze) project.tasks.dependencyCheckAnalyze.doFirst { // Why not doLast? See README.md! @@ -207,7 +228,7 @@ project.tasks.check.dependsOn(checkLicense) // JaCoCo Test Code Coverage jacoco { - toolVersion = "0.8.8" + toolVersion = "0.8.10" } test { finalizedBy jacocoTestReport // generate report after tests @@ -286,7 +307,7 @@ pitest { targetTests = ['net.hostsharing.hsadminng.**.*UnitTest', 'net.hostsharing.hsadminng.**.*RestTest'] excludedTestClasses = ['**AcceptanceTest*', '**IntegrationTest*'] - pitestVersion = '1.9.9' + pitestVersion = '1.15.3' junit5PluginVersion = '1.1.0' threads = 4 diff --git a/etc/allowed-licenses.json b/etc/allowed-licenses.json index 31bbfab3..f50ce4b9 100644 --- a/etc/allowed-licenses.json +++ b/etc/allowed-licenses.json @@ -8,6 +8,7 @@ { "moduleLicense": "BSD License" }, { "moduleLicense": "BSD-2-Clause" }, + { "moduleLicense": "BSD-3-Clause" }, { "moduleLicense": "The BSD License" }, { "moduleLicense": "CDDL 1.1" }, diff --git a/etc/owasp-dependency-check-suppression.xml b/etc/owasp-dependency-check-suppression.xml index 4c258544..39d77b47 100644 --- a/etc/owasp-dependency-check-suppression.xml +++ b/etc/owasp-dependency-check-suppression.xml @@ -14,4 +14,52 @@ <packageUrl regex="true">^pkg:maven/com\.fasterxml\.jackson\.core/jackson\-databind@.*$</packageUrl> <cve>CVE-2022-42003</cve> </suppress> + <suppress> + <notes><![CDATA[ + We don't parse external XML. + ]]></notes> + <packageUrl regex="true">^pkg:maven/org\.eclipse\.angus/angus\-activation@.*$</packageUrl> + <cpe>cpe:/a:eclipse:eclipse_ide</cpe> + </suppress> + <suppress> + <notes><![CDATA[ + We don't parse external XML. + ]]></notes> + <packageUrl regex="true">^pkg:maven/jakarta\.activation/jakarta\.activation\-api@.*$</packageUrl> + <cpe>cpe:/a:eclipse:eclipse_ide</cpe> + </suppress> + <suppress> + <notes><![CDATA[ + Cyclic references are not possible if file comes in JSON text format. + ]]></notes> + <packageUrl regex="true">^pkg:maven/com\.fasterxml\.jackson\.core/jackson\-databind@.*$</packageUrl> + <cpe>cpe:/a:fasterxml:jackson-databind</cpe> + </suppress> + <suppress> + <notes><![CDATA[ + As far as I see Criteria.parse(...) cannot be reached with external data. + ]]></notes> + <packageUrl regex="true">^pkg:maven/com\.jayway\.jsonpath/json\-path@.*$</packageUrl> + <vulnerabilityName>CVE-2023-51074</vulnerabilityName> + </suppress> + <suppress> + <notes><![CDATA[ + Internal tooling, not exposed to the Internet. + ]]></notes> + <packageUrl regex="true">^pkg:maven/org\.pitest/pitest\-command\-line@.*$</packageUrl> + <cpe>cpe:/a:line:line</cpe> + </suppress> + <suppress> + <notes><![CDATA[ + Spring Boot 3.1.x has a transient dependency to snakeyaml 1.3 + which contains this vulnerability. + + We've explicitly bumped to 2.2, but the vulnerability checker does not seem to notice that. + + TODO: Remove this suppression once we are on SpringBoot 3.2, + as well as the explicit version bump and the transient dependency exclude. + ]]></notes> + <packageUrl regex="true">^pkg:maven/org\.yaml/snakeyaml@.*$</packageUrl> + <cve>CVE-2022-1471</cve> + </suppress> </suppressions> diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 41d9927a..d64cd491 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 8049c684..1af9e093 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 1b6c7873..1aa94a42 100755 --- a/gradlew +++ b/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -80,13 +80,11 @@ do esac done -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" +# This is normally unused +# shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,22 +131,29 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -193,11 +198,15 @@ if "$cygwin" || "$msys" ; then done fi -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ @@ -205,6 +214,12 @@ set -- \ org.gradle.wrapper.GradleWrapperMain \ "$@" +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. diff --git a/gradlew.bat b/gradlew.bat index 107acd32..93e3f59f 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,8 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/settings.gradle b/settings.gradle index 8c454c71..2423c63e 100644 --- a/settings.gradle +++ b/settings.gradle @@ -7,4 +7,28 @@ pluginManagement { } } +dependencyResolutionManagement { + components { + all { + allVariants { + withDependencies { + removeAll { + // Spring Boot 3.1.x has a transient dependency to snakeyaml 1.3 + // which contains a severe vulnerability. + // Here we remove this transient dependency and in build.gradle + // we add an explicit dependency to snakeyaml 2.2, + // which does not have this vulnerability anymore. + // + // TODO: Check Once we are on SpringBoot 3.2.x, check if this exclude + // is still neccessary. If not: + // Remove it // as well as the related explicit dependency in build.gradle + // and the dependency suppression in owasp-dependency-check-suppression.xml. + it.module in [ 'snakeyaml' ] + } + } + } + } + } +} + rootProject.name = 'hsadmin-ng' diff --git a/src/main/java/net/hostsharing/hsadminng/config/PostgresCustomDialect.java b/src/main/java/net/hostsharing/hsadminng/config/PostgresCustomDialect.java index 9cd2ec70..3c66716d 100644 --- a/src/main/java/net/hostsharing/hsadminng/config/PostgresCustomDialect.java +++ b/src/main/java/net/hostsharing/hsadminng/config/PostgresCustomDialect.java @@ -8,7 +8,7 @@ import static org.hibernate.dialect.DatabaseVersion.make; public class PostgresCustomDialect extends PostgreSQLDialect { public PostgresCustomDialect() { - super(make(13, 7)); + super(make(15, 5)); } } diff --git a/src/main/java/net/hostsharing/hsadminng/context/Context.java b/src/main/java/net/hostsharing/hsadminng/context/Context.java index f7f6f827..2730147d 100644 --- a/src/main/java/net/hostsharing/hsadminng/context/Context.java +++ b/src/main/java/net/hostsharing/hsadminng/context/Context.java @@ -15,9 +15,11 @@ import java.util.Collections; import java.util.Optional; import java.util.Set; import java.util.UUID; +import java.util.function.Function; import java.util.stream.Collectors; import static java.util.function.Predicate.not; +import static net.hostsharing.hsadminng.mapper.PostgresArray.fromPostgresArray; import static org.springframework.transaction.annotation.Propagation.MANDATORY; @Service @@ -81,11 +83,14 @@ public class Context { } public String[] getAssumedRoles() { - return (String[]) em.createNativeQuery("select assumedRoles() as roles", String[].class).getSingleResult(); + final byte[] result = (byte[]) em.createNativeQuery("select assumedRoles() as roles", String[].class).getSingleResult(); + return fromPostgresArray(result, String.class, Function.identity()); } public UUID[] currentSubjectsUuids() { - return (UUID[]) em.createNativeQuery("select currentSubjectsUuids() as uuids", UUID[].class).getSingleResult(); + final byte[] result = (byte[]) em.createNativeQuery("select currentSubjectsUuids() as uuids", UUID[].class) + .getSingleResult(); + return fromPostgresArray(result, UUID.class, UUID::fromString); } public static String getCallerMethodNameFromStackFrame(final int skipFrames) { diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactRepository.java b/src/main/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactRepository.java index a39acbfa..309c3a57 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactRepository.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactRepository.java @@ -14,7 +14,7 @@ public interface HsOfficeContactRepository extends Repository<HsOfficeContactEnt @Query(""" SELECT c FROM HsOfficeContactEntity c WHERE :label is null - OR c.label like concat(:label, '%') + OR c.label like concat(cast(:label as text), '%') """) List<HsOfficeContactEntity> findContactByOptionalLabelLike(String label); diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionEntity.java b/src/main/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionEntity.java index 9955f6f1..e699fb5c 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionEntity.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionEntity.java @@ -1,13 +1,11 @@ package net.hostsharing.hsadminng.hs.office.coopassets; -import com.vladmihalcea.hibernate.type.basic.PostgreSQLEnumType; import lombok.*; import net.hostsharing.hsadminng.errors.DisplayName; import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipEntity; import net.hostsharing.hsadminng.stringify.Stringify; import net.hostsharing.hsadminng.stringify.Stringifyable; import org.hibernate.annotations.GenericGenerator; -import org.hibernate.annotations.Type; import jakarta.persistence.*; import java.math.BigDecimal; @@ -47,7 +45,6 @@ public class HsOfficeCoopAssetsTransactionEntity implements Stringifyable { @Column(name = "transactiontype") @Enumerated(EnumType.STRING) - @Type(PostgreSQLEnumType.class) private HsOfficeCoopAssetsTransactionType transactionType; @Column(name = "valuedate") diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionRepository.java b/src/main/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionRepository.java index 1a14abde..256933b9 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionRepository.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionRepository.java @@ -1,6 +1,5 @@ package net.hostsharing.hsadminng.hs.office.coopassets; -import net.hostsharing.hsadminng.hs.office.coopshares.HsOfficeCoopSharesTransactionEntity; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.Repository; diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionEntity.java b/src/main/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionEntity.java index 1b5d1cc5..b5d4979b 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionEntity.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionEntity.java @@ -1,12 +1,10 @@ package net.hostsharing.hsadminng.hs.office.coopshares; -import com.vladmihalcea.hibernate.type.basic.PostgreSQLEnumType; import lombok.*; import net.hostsharing.hsadminng.errors.DisplayName; import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipEntity; import net.hostsharing.hsadminng.stringify.Stringify; import net.hostsharing.hsadminng.stringify.Stringifyable; -import org.hibernate.annotations.Type; import jakarta.persistence.*; import java.time.LocalDate; @@ -43,7 +41,6 @@ public class HsOfficeCoopSharesTransactionEntity implements Stringifyable { @Column(name = "transactiontype") @Enumerated(EnumType.STRING) - @Type(PostgreSQLEnumType.class) private HsOfficeCoopSharesTransactionType transactionType; @Column(name = "valuedate") diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorRepository.java b/src/main/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorRepository.java index 27cb6f92..f0013ef9 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorRepository.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorRepository.java @@ -19,15 +19,15 @@ public interface HsOfficeDebitorRepository extends Repository<HsOfficeDebitorEnt @Query(""" SELECT debitor FROM HsOfficeDebitorEntity debitor - JOIN HsOfficePartnerEntity partner ON partner.uuid = debitor.partner - JOIN HsOfficePersonEntity person ON person.uuid = partner.person - JOIN HsOfficeContactEntity contact ON contact.uuid = debitor.billingContact + JOIN HsOfficePartnerEntity partner ON partner.uuid = debitor.partner.uuid + JOIN HsOfficePersonEntity person ON person.uuid = partner.person.uuid + JOIN HsOfficeContactEntity contact ON contact.uuid = debitor.billingContact.uuid WHERE :name is null - OR partner.details.birthName like concat(:name, '%') - OR person.tradeName like concat(:name, '%') - OR person.familyName like concat(:name, '%') - OR person.givenName like concat(:name, '%') - OR contact.label like concat(:name, '%') + OR partner.details.birthName like concat(cast(:name as text), '%') + OR person.tradeName like concat(cast(:name as text), '%') + OR person.familyName like concat(cast(:name as text), '%') + OR person.givenName like concat(cast(:name as text), '%') + OR contact.label like concat(cast(:name as text), '%') """) List<HsOfficeDebitorEntity> findDebitorByOptionalNameLike(String name); diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipEntity.java b/src/main/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipEntity.java index 7a3e1a20..671ae7f7 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipEntity.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipEntity.java @@ -1,6 +1,5 @@ package net.hostsharing.hsadminng.hs.office.membership; -import com.vladmihalcea.hibernate.type.basic.PostgreSQLEnumType; import com.vladmihalcea.hibernate.type.range.PostgreSQLRangeType; import com.vladmihalcea.hibernate.type.range.Range; import lombok.*; @@ -61,7 +60,6 @@ public class HsOfficeMembershipEntity implements Stringifyable { @Column(name = "reasonfortermination") @Enumerated(EnumType.STRING) - @Type(PostgreSQLEnumType.class) private HsOfficeReasonForTermination reasonForTermination; public void setValidFrom(final LocalDate validFrom) { diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepository.java b/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepository.java index 222dcaed..6c7a158c 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepository.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepository.java @@ -13,14 +13,14 @@ public interface HsOfficePartnerRepository extends Repository<HsOfficePartnerEnt @Query(""" SELECT partner FROM HsOfficePartnerEntity partner - JOIN HsOfficeContactEntity contact ON contact.uuid = partner.contact - JOIN HsOfficePersonEntity person ON person.uuid = partner.person + JOIN HsOfficeContactEntity contact ON contact.uuid = partner.contact.uuid + JOIN HsOfficePersonEntity person ON person.uuid = partner.person.uuid WHERE :name is null - OR partner.details.birthName like concat(:name, '%') - OR contact.label like concat(:name, '%') - OR person.tradeName like concat(:name, '%') - OR person.givenName like concat(:name, '%') - OR person.familyName like concat(:name, '%') + OR partner.details.birthName like concat(cast(:name as text), '%') + OR contact.label like concat(cast(:name as text), '%') + OR person.tradeName like concat(cast(:name as text), '%') + OR person.givenName like concat(cast(:name as text), '%') + OR person.familyName like concat(cast(:name as text), '%') """) List<HsOfficePartnerEntity> findPartnerByOptionalNameLike(String name); diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonEntity.java b/src/main/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonEntity.java index cdc695f0..a76d4130 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonEntity.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonEntity.java @@ -1,13 +1,11 @@ package net.hostsharing.hsadminng.hs.office.person; -import com.vladmihalcea.hibernate.type.basic.PostgreSQLEnumType; import lombok.*; import lombok.experimental.FieldNameConstants; import net.hostsharing.hsadminng.errors.DisplayName; import net.hostsharing.hsadminng.stringify.Stringify; import net.hostsharing.hsadminng.stringify.Stringifyable; import org.apache.commons.lang3.StringUtils; -import org.hibernate.annotations.Type; import jakarta.persistence.*; import java.util.UUID; @@ -37,7 +35,6 @@ public class HsOfficePersonEntity implements Stringifyable { @Column(name = "persontype") @Enumerated(EnumType.STRING) - @Type(PostgreSQLEnumType.class) private HsOfficePersonType personType; @Column(name = "tradename") diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRepository.java b/src/main/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRepository.java index 538ffaf1..f7481339 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRepository.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRepository.java @@ -14,9 +14,9 @@ public interface HsOfficePersonRepository extends Repository<HsOfficePersonEntit @Query(""" SELECT p FROM HsOfficePersonEntity p WHERE :name is null - OR p.tradeName like concat(:name, '%') - OR p.givenName like concat(:name, '%') - OR p.familyName like concat(:name, '%') + OR p.tradeName like concat(cast(:name as text), '%') + OR p.givenName like concat(cast(:name as text), '%') + OR p.familyName like concat(cast(:name as text), '%') """) List<HsOfficePersonEntity> findPersonByOptionalNameLike(String name); diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipEntity.java b/src/main/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipEntity.java index 9e7fb5d9..383c6853 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipEntity.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipEntity.java @@ -1,12 +1,10 @@ package net.hostsharing.hsadminng.hs.office.relationship; -import com.vladmihalcea.hibernate.type.basic.PostgreSQLEnumType; import lombok.*; import lombok.experimental.FieldNameConstants; import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity; import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity; import net.hostsharing.hsadminng.stringify.Stringify; -import org.hibernate.annotations.Type; import jakarta.persistence.*; import java.util.UUID; @@ -47,7 +45,6 @@ public class HsOfficeRelationshipEntity { @Column(name = "reltype") @Enumerated(EnumType.STRING) - @Type(PostgreSQLEnumType.class) private HsOfficeRelationshipType relType; @Override diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateEntity.java b/src/main/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateEntity.java index db31adcb..84264bd6 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateEntity.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateEntity.java @@ -54,6 +54,7 @@ public class HsOfficeSepaMandateEntity implements Stringifyable { @Column(name = "validity", columnDefinition = "daterange") @Type(PostgreSQLRangeType.class) + @Builder.Default private Range<LocalDate> validity = Range.infinite(LocalDate.class); public void setValidFrom(final LocalDate validFrom) { diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateRepository.java b/src/main/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateRepository.java index d243a716..aab53bae 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateRepository.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateRepository.java @@ -14,7 +14,7 @@ public interface HsOfficeSepaMandateRepository extends Repository<HsOfficeSepaMa @Query(""" SELECT mandate FROM HsOfficeSepaMandateEntity mandate WHERE :iban is null - OR mandate.bankAccount.iban like concat(:iban, '%') + OR mandate.bankAccount.iban like concat(cast(:iban as text), '%') ORDER BY mandate.bankAccount.iban """) List<HsOfficeSepaMandateEntity> findSepaMandateByOptionalIban(String iban); diff --git a/src/main/java/net/hostsharing/hsadminng/mapper/PostgresArray.java b/src/main/java/net/hostsharing/hsadminng/mapper/PostgresArray.java new file mode 100644 index 00000000..e1e1d056 --- /dev/null +++ b/src/main/java/net/hostsharing/hsadminng/mapper/PostgresArray.java @@ -0,0 +1,58 @@ +package net.hostsharing.hsadminng.mapper; + +import lombok.experimental.UtilityClass; +import org.postgresql.util.PGtokenizer; + +import java.lang.reflect.Array; +import java.nio.charset.StandardCharsets; +import java.util.function.Function; + +@UtilityClass +public class PostgresArray { + + /** + * Converts a byte[], as returned for a Postgres-array by native queries, to a Java array. + * + * <p>This example code worked with Hibernate 5 (Spring Boot 3.0.x): + * <pre><code> + * return (UUID[]) em.createNativeQuery("select currentSubjectsUuids() as uuids", UUID[].class).getSingleResult(); + * </code></pre> + * </p> + * + * <p>With Hibernate 6 (Spring Boot 3.1.x), this utility method can be used like such: + * <pre><code> + * final byte[] result = (byte[]) em.createNativeQuery("select * from currentSubjectsUuids() as uuids", UUID[].class) + * .getSingleResult(); + * return fromPostgresArray(result, UUID.class, UUID::fromString); + * </code></pre> + * </p> + * + * @param pgArray the byte[] returned by a native query containing as rendered for a Postgres array + * @param elementClass the class of a single element of the Java array to be returned + * @param itemParser converts a string element to the specified elementClass + * @return a Java array containing the data from pgArray + * @param <T> type of a single element of the Java array + */ + public static <T> T[] fromPostgresArray(final byte[] pgArray, final Class<T> elementClass, final Function<String, T> itemParser) { + final var pgArrayLiteral = new String(pgArray, StandardCharsets.UTF_8); + if (pgArrayLiteral.length() == 2) { + return newGenericArray(elementClass, 0); + } + final PGtokenizer tokenizer = new PGtokenizer(pgArrayLiteral.substring(1, pgArrayLiteral.length()-1), ','); + tokenizer.remove("\"", "\""); + final T[] array = newGenericArray(elementClass, tokenizer.getSize()); // Create a new array of the specified type and length + for ( int n = 0; n < tokenizer.getSize(); ++n ) { + final String token = tokenizer.getToken(n); + if ( !"NULL".equals(token) ) { + array[n] = itemParser.apply(token.trim().replace("\\\"", "\"")); + } + } + return array; + } + + @SuppressWarnings("unchecked") + private static <T> T[] newGenericArray(final Class<T> elementClass, final int length) { + return (T[]) Array.newInstance(elementClass, length); + } + +} diff --git a/src/main/java/net/hostsharing/hsadminng/rbac/rbacuser/RbacUserRepository.java b/src/main/java/net/hostsharing/hsadminng/rbac/rbacuser/RbacUserRepository.java index bfe11a19..0c1a168b 100644 --- a/src/main/java/net/hostsharing/hsadminng/rbac/rbacuser/RbacUserRepository.java +++ b/src/main/java/net/hostsharing/hsadminng/rbac/rbacuser/RbacUserRepository.java @@ -11,7 +11,7 @@ public interface RbacUserRepository extends Repository<RbacUserEntity, UUID> { @Query(""" select u from RbacUserEntity u - where :userName is null or u.name like concat(:userName, '%') + where :userName is null or u.name like concat(cast(:userName as text), '%') order by u.name """) List<RbacUserEntity> findByOptionalNameLike(String userName); diff --git a/src/main/java/net/hostsharing/hsadminng/test/cust/TestCustomerController.java b/src/main/java/net/hostsharing/hsadminng/test/cust/TestCustomerController.java index 530a7006..1bd000ba 100644 --- a/src/main/java/net/hostsharing/hsadminng/test/cust/TestCustomerController.java +++ b/src/main/java/net/hostsharing/hsadminng/test/cust/TestCustomerController.java @@ -11,7 +11,6 @@ import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder; import java.util.List; -import java.util.UUID; @RestController public class TestCustomerController implements TestCustomersApi { diff --git a/src/main/java/net/hostsharing/hsadminng/test/cust/TestCustomerRepository.java b/src/main/java/net/hostsharing/hsadminng/test/cust/TestCustomerRepository.java index a882b304..2dc298ea 100644 --- a/src/main/java/net/hostsharing/hsadminng/test/cust/TestCustomerRepository.java +++ b/src/main/java/net/hostsharing/hsadminng/test/cust/TestCustomerRepository.java @@ -12,7 +12,7 @@ public interface TestCustomerRepository extends Repository<TestCustomerEntity, U Optional<TestCustomerEntity> findByUuid(UUID id); - @Query("SELECT c FROM TestCustomerEntity c WHERE :prefix is null or c.prefix like concat(:prefix, '%')") + @Query("SELECT c FROM TestCustomerEntity c WHERE :prefix is null or c.prefix like concat(cast(:prefix as text), '%')") List<TestCustomerEntity> findCustomerByOptionalPrefixLike(String prefix); TestCustomerEntity save(final TestCustomerEntity entity); diff --git a/src/main/java/net/hostsharing/hsadminng/test/pac/TestPackageRepository.java b/src/main/java/net/hostsharing/hsadminng/test/pac/TestPackageRepository.java index 610d8fdc..f8538465 100644 --- a/src/main/java/net/hostsharing/hsadminng/test/pac/TestPackageRepository.java +++ b/src/main/java/net/hostsharing/hsadminng/test/pac/TestPackageRepository.java @@ -8,7 +8,7 @@ import java.util.UUID; public interface TestPackageRepository extends Repository<TestPackageEntity, UUID> { - @Query("SELECT p FROM TestPackageEntity p WHERE :name is null or p.name like concat(:name, '%')") + @Query("SELECT p FROM TestPackageEntity p WHERE :name is null or p.name like concat(cast(:name as text), '%')") List<TestPackageEntity> findAllByOptionalNameLike(final String name); TestPackageEntity findByUuid(UUID packageUuid); diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/bankaccount/HsOfficeBankAccountControllerRestTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/bankaccount/HsOfficeBankAccountControllerRestTest.java index a54ca5c6..d870ca1a 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/bankaccount/HsOfficeBankAccountControllerRestTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/bankaccount/HsOfficeBankAccountControllerRestTest.java @@ -83,7 +83,7 @@ class HsOfficeBankAccountControllerRestTest { enum InvalidBicTestCase { TOO_SHORT("BEVODEB", "Bic length must be 8 or 11"), TOO_LONG("BEVODEBBX", "Bic length must be 8 or 11"), - INVALID_CHARACTER("BEV-ODEB", "Bank code must contain only letters."); + INVALID_CHARACTER("BEV-ODEB", "Bank code must contain only alphanumeric."); private final String givenBic; private final String expectedErrorMessage; diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/bankaccount/TestHsOfficeBankAccount.java b/src/test/java/net/hostsharing/hsadminng/hs/office/bankaccount/TestHsOfficeBankAccount.java index 7bb7de7e..7b7505f4 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/bankaccount/TestHsOfficeBankAccount.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/bankaccount/TestHsOfficeBankAccount.java @@ -1,6 +1,5 @@ package net.hostsharing.hsadminng.hs.office.bankaccount; -import java.util.UUID; public class TestHsOfficeBankAccount { diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactRepositoryIntegrationTest.java index a58aa824..0308c31d 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactRepositoryIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactRepositoryIntegrationTest.java @@ -28,7 +28,6 @@ import static net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantEntity.grantD import static net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleEntity.roleNamesOf; import static net.hostsharing.test.JpaAttempt.attempt; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assumptions.assumeThat; @DataJpaTest @Import( { Context.class, JpaAttempt.class }) @@ -237,10 +236,6 @@ class HsOfficeContactRepositoryIntegrationTest extends ContextBasedTest { final var initialRoleNames = roleNamesOf(rawRoleRepo.findAll()); final var initialGrantNames = grantDisplaysOf(rawGrantRepo.findAll()); final var givenContact = givenSomeTemporaryContact("selfregistered-user-drew@hostsharing.org"); - assumeThat(rawRoleRepo.findAll().size()).as("unexpected number of roles created") - .isEqualTo(initialRoleNames.size() + 3); - assumeThat(rawGrantRepo.findAll().size()).as("unexpected number of grants created") - .isEqualTo(initialGrantNames.size() + 7); // when final var result = jpaAttempt.transacted(() -> { diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/contact/TestHsOfficeContact.java b/src/test/java/net/hostsharing/hsadminng/hs/office/contact/TestHsOfficeContact.java index 58284258..b42ef8e5 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/contact/TestHsOfficeContact.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/contact/TestHsOfficeContact.java @@ -1,6 +1,5 @@ package net.hostsharing.hsadminng.hs.office.contact; -import java.util.UUID; public class TestHsOfficeContact { diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorControllerAcceptanceTest.java index 22001cb2..76d6758f 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorControllerAcceptanceTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorControllerAcceptanceTest.java @@ -26,7 +26,6 @@ import java.util.UUID; import static net.hostsharing.test.IsValidUuidMatcher.isUuidValid; import static net.hostsharing.test.JsonMatcher.lenientlyEquals; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assumptions.assumeThat; import static org.hamcrest.Matchers.*; @SpringBootTest( @@ -481,7 +480,7 @@ class HsOfficeDebitorControllerAcceptanceTest { void contactAdminUser_canNotDeleteRelatedDebitor() { context.define("superuser-alex@hostsharing.net"); final var givenDebitor = givenSomeTemporaryDebitor(); - assumeThat(givenDebitor.getBillingContact().getLabel()).isEqualTo("forth contact"); + assertThat(givenDebitor.getBillingContact().getLabel()).isEqualTo("forth contact"); RestAssured // @formatter:off .given() @@ -501,7 +500,7 @@ class HsOfficeDebitorControllerAcceptanceTest { void normalUser_canNotDeleteUnrelatedDebitor() { context.define("superuser-alex@hostsharing.net"); final var givenDebitor = givenSomeTemporaryDebitor(); - assumeThat(givenDebitor.getBillingContact().getLabel()).isEqualTo("forth contact"); + assertThat(givenDebitor.getBillingContact().getLabel()).isEqualTo("forth contact"); RestAssured // @formatter:off .given() diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/TestHsOfficeDebitor.java b/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/TestHsOfficeDebitor.java index 9d2c6b7f..d9d482ba 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/TestHsOfficeDebitor.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/TestHsOfficeDebitor.java @@ -2,7 +2,6 @@ package net.hostsharing.hsadminng.hs.office.debitor; import lombok.experimental.UtilityClass; -import java.util.UUID; import static net.hostsharing.hsadminng.hs.office.contact.TestHsOfficeContact.TEST_CONTACT; import static net.hostsharing.hsadminng.hs.office.partner.TestHsOfficePartner.TEST_PARTNER; diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipRepositoryIntegrationTest.java index 42f61495..c85a9b13 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipRepositoryIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipRepositoryIntegrationTest.java @@ -32,7 +32,6 @@ import static net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantEntity.grantD import static net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleEntity.roleNamesOf; import static net.hostsharing.test.JpaAttempt.attempt; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assumptions.assumeThat; @DataJpaTest @Import( { Context.class, JpaAttempt.class }) @@ -327,7 +326,7 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTest { // when final var result = jpaAttempt.transacted(() -> { context("superuser-alex@hostsharing.net", "hs_office_debitor#10003ThirdOHG-thirdcontact.admin"); - assumeThat(membershipRepo.findByUuid(givenMembership.getUuid())).isPresent(); + assertThat(membershipRepo.findByUuid(givenMembership.getUuid())).isPresent(); membershipRepo.deleteByUuid(givenMembership.getUuid()); }); diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/membership/TestHsMembership.java b/src/test/java/net/hostsharing/hsadminng/hs/office/membership/TestHsMembership.java index 1b40a4ce..d9245fc8 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/membership/TestHsMembership.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/membership/TestHsMembership.java @@ -3,7 +3,6 @@ package net.hostsharing.hsadminng.hs.office.membership; import com.vladmihalcea.hibernate.type.range.Range; import java.time.LocalDate; -import java.util.UUID; import static net.hostsharing.hsadminng.hs.office.partner.TestHsOfficePartner.TEST_PARTNER; diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerControllerAcceptanceTest.java index 899b151d..053b03e1 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerControllerAcceptanceTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerControllerAcceptanceTest.java @@ -24,7 +24,6 @@ import java.util.UUID; import static net.hostsharing.test.IsValidUuidMatcher.isUuidValid; import static net.hostsharing.test.JsonMatcher.lenientlyEquals; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assumptions.assumeThat; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.startsWith; @@ -408,7 +407,7 @@ class HsOfficePartnerControllerAcceptanceTest { void contactAdminUser_canNotDeleteRelatedPartner() { context.define("superuser-alex@hostsharing.net"); final var givenPartner = givenSomeTemporaryPartnerBessler(); - assumeThat(givenPartner.getContact().getLabel()).isEqualTo("forth contact"); + assertThat(givenPartner.getContact().getLabel()).isEqualTo("forth contact"); RestAssured // @formatter:off .given() @@ -428,7 +427,7 @@ class HsOfficePartnerControllerAcceptanceTest { void normalUser_canNotDeleteUnrelatedPartner() { context.define("superuser-alex@hostsharing.net"); final var givenPartner = givenSomeTemporaryPartnerBessler(); - assumeThat(givenPartner.getContact().getLabel()).isEqualTo("forth contact"); + assertThat(givenPartner.getContact().getLabel()).isEqualTo("forth contact"); RestAssured // @formatter:off .given() diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepositoryIntegrationTest.java index 6b035f5b..e03d8cbe 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepositoryIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepositoryIntegrationTest.java @@ -29,7 +29,6 @@ import static net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantEntity.grantD import static net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleEntity.roleNamesOf; import static net.hostsharing.test.JpaAttempt.attempt; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assumptions.assumeThat; @DataJpaTest @Import( { Context.class, JpaAttempt.class }) @@ -330,7 +329,7 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTest { // when final var result = jpaAttempt.transacted(() -> { context("person-ErbenBesslerMelBessler@example.com"); - assumeThat(partnerRepo.findByUuid(givenPartner.getUuid())).isPresent(); + assertThat(partnerRepo.findByUuid(givenPartner.getUuid())).isPresent(); partnerRepo.deleteByUuid(givenPartner.getUuid()); }); @@ -352,10 +351,6 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTest { final var initialRoleNames = Array.from(roleNamesOf(rawRoleRepo.findAll())); final var initialGrantNames = Array.from(grantDisplaysOf(rawGrantRepo.findAll())); final var givenPartner = givenSomeTemporaryPartnerBessler("twelfth"); - assumeThat(rawRoleRepo.findAll().size()).as("unexpected number of roles created") - .isEqualTo(initialRoleNames.length + 3); - assumeThat(rawGrantRepo.findAll().size()).as("unexpected number of grants created") - .isEqualTo(initialGrantNames.length + 10); // when final var result = jpaAttempt.transacted(() -> { diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/TestHsOfficePartner.java b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/TestHsOfficePartner.java index 21756b6d..19235167 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/TestHsOfficePartner.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/TestHsOfficePartner.java @@ -3,7 +3,6 @@ package net.hostsharing.hsadminng.hs.office.partner; import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity; import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity; -import java.util.UUID; import static net.hostsharing.hsadminng.hs.office.person.HsOfficePersonType.LEGAL; diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRepositoryIntegrationTest.java index 6c75434e..2405b237 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRepositoryIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRepositoryIntegrationTest.java @@ -27,7 +27,6 @@ import static net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantEntity.grantD import static net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleEntity.roleNamesOf; import static net.hostsharing.test.JpaAttempt.attempt; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assumptions.assumeThat; @DataJpaTest @Import( { Context.class, JpaAttempt.class }) @@ -244,10 +243,6 @@ class HsOfficePersonRepositoryIntegrationTest extends ContextBasedTest { final var initialRoleNames = roleNamesOf(rawRoleRepo.findAll()); final var initialGrantNames = grantDisplaysOf(rawGrantRepo.findAll()); final var givenPerson = givenSomeTemporaryPerson("selfregistered-user-drew@hostsharing.org"); - assumeThat(rawRoleRepo.findAll().size()).as("unexpected number of roles created") - .isEqualTo(initialRoleNames.size() + 3); - assumeThat(rawGrantRepo.findAll().size()).as("unexpected number of grants created") - .isEqualTo(initialGrantNames.size() + 7); // when final var result = jpaAttempt.transacted(() -> { diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/person/TestHsOfficePerson.java b/src/test/java/net/hostsharing/hsadminng/hs/office/person/TestHsOfficePerson.java index f4d10fda..d394ee56 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/person/TestHsOfficePerson.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/person/TestHsOfficePerson.java @@ -1,6 +1,5 @@ package net.hostsharing.hsadminng.hs.office.person; -import java.util.UUID; public class TestHsOfficePerson { diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipControllerAcceptanceTest.java index 6288bb4c..f090295b 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipControllerAcceptanceTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipControllerAcceptanceTest.java @@ -25,7 +25,6 @@ import java.util.UUID; import static net.hostsharing.test.IsValidUuidMatcher.isUuidValid; import static net.hostsharing.test.JsonMatcher.lenientlyEquals; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assumptions.assumeThat; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.startsWith; diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateEntityUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateEntityUnitTest.java index 7ba77e0e..5d8fa5b5 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateEntityUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateEntityUnitTest.java @@ -1,6 +1,5 @@ package net.hostsharing.hsadminng.hs.office.sepamandate; -import com.vladmihalcea.hibernate.type.range.Range; import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountEntity; import org.junit.jupiter.api.Test; diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateRepositoryIntegrationTest.java index cbc8bfbc..8e5f5c79 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateRepositoryIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateRepositoryIntegrationTest.java @@ -31,7 +31,6 @@ import static net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantEntity.grantD import static net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleEntity.roleNamesOf; import static net.hostsharing.test.JpaAttempt.attempt; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assumptions.assumeThat; @DataJpaTest @Import({ Context.class, JpaAttempt.class }) @@ -346,7 +345,7 @@ class HsOfficeSepaMandateRepositoryIntegrationTest extends ContextBasedTest { // when final var result = jpaAttempt.transacted(() -> { context("bankaccount-admin@ThirdOHG.example.com"); - assumeThat(sepaMandateRepo.findByUuid(givenSepaMandate.getUuid())).isPresent(); + assertThat(sepaMandateRepo.findByUuid(givenSepaMandate.getUuid())).isPresent(); sepaMandateRepo.deleteByUuid(givenSepaMandate.getUuid()); }); diff --git a/src/test/java/net/hostsharing/hsadminng/mapper/PostgresArrayIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/mapper/PostgresArrayIntegrationTest.java new file mode 100644 index 00000000..c76141b1 --- /dev/null +++ b/src/test/java/net/hostsharing/hsadminng/mapper/PostgresArrayIntegrationTest.java @@ -0,0 +1,88 @@ +package net.hostsharing.hsadminng.mapper; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; + +import jakarta.persistence.EntityManager; + +import java.util.UUID; +import java.util.function.Function; + +import static org.assertj.core.api.Assertions.assertThat; + +@DataJpaTest +class PostgresArrayIntegrationTest { + + @Autowired + EntityManager em; + + @Test + void shouldCreateEmptyArray() { + em.createNativeQuery(""" + create or replace function returnEmptyArray() + returns text[] + stable leakproof + language plpgsql as $$ + declare + emptyArray text[] = '{}'; + begin + return emptyArray; + end; $$; + """).executeUpdate(); + final byte[] pgArray = (byte[]) em.createNativeQuery("SELECT returnEmptyArray()", String[].class).getSingleResult(); + + final String[] result = PostgresArray.fromPostgresArray(pgArray, String.class, Function.identity()); + + assertThat(result).isEmpty(); + } + + @Test + void shouldCreateStringArray() { + em.createNativeQuery(""" + create or replace function returnStringArray() + returns varchar(63)[] + stable leakproof + language plpgsql as $$ + declare + text1 text = 'one'; + text2 text = 'two, three'; + text3 text = 'four; five'; + text4 text = 'say "Hello" to me'; + begin + return array[text1, text2, text3, null, text4]; + end; $$; + """).executeUpdate(); + final byte[] pgArray = (byte[]) em.createNativeQuery("SELECT returnStringArray()", String[].class).getSingleResult(); + + final String[] result = PostgresArray.fromPostgresArray(pgArray, String.class, Function.identity()); + + assertThat(result).containsExactly("one", "two, three", "four; five", null, "say \"Hello\" to me"); + } + + @Test + void shouldCreateUUidArray() { + em.createNativeQuery(""" + create or replace function returnUuidArray() + returns uuid[] + stable leakproof + language plpgsql as $$ + declare + uuid1 UUID = 'f47ac10b-58cc-4372-a567-0e02b2c3d479'; + uuid2 UUID = '6ba7b810-9dad-11d1-80b4-00c04fd430c8'; + uuid3 UUID = '01234567-89ab-cdef-0123-456789abcdef'; + begin + return ARRAY[uuid1, uuid2, null, uuid3]; + end; $$; + """).executeUpdate(); + final byte[] pgArray = (byte[]) em.createNativeQuery("SELECT returnUuidArray()", UUID[].class).getSingleResult(); + + final UUID[] result = PostgresArray.fromPostgresArray(pgArray, UUID.class, UUID::fromString); + + assertThat(result).containsExactly( + UUID.fromString("f47ac10b-58cc-4372-a567-0e02b2c3d479"), + UUID.fromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8"), + null, + UUID.fromString("01234567-89ab-cdef-0123-456789abcdef")); + } +} diff --git a/src/test/java/net/hostsharing/hsadminng/rbac/rbacgrant/RbacGrantControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/rbac/rbacgrant/RbacGrantControllerAcceptanceTest.java index 0402dbfe..6f0abc93 100644 --- a/src/test/java/net/hostsharing/hsadminng/rbac/rbacgrant/RbacGrantControllerAcceptanceTest.java +++ b/src/test/java/net/hostsharing/hsadminng/rbac/rbacgrant/RbacGrantControllerAcceptanceTest.java @@ -26,7 +26,6 @@ import java.util.List; import java.util.UUID; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assumptions.assumeThat; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.Matchers.*; @@ -343,7 +342,7 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest { } private void assumeCreated(final ValidatableResponse response) { - assumeThat(response.extract().response().statusCode()).isEqualTo(201); + assertThat(response.extract().response().statusCode()).isEqualTo(201); } class Subject { @@ -479,7 +478,7 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest { } private void assumeGrantExists(final Subject grantingSubject, final String expectedGrant) { - assumeThat(findAllGrantsOf(grantingSubject)) + assertThat(findAllGrantsOf(grantingSubject)) .extracting(RbacGrantEntity::toDisplay) .contains(expectedGrant); } diff --git a/src/test/java/net/hostsharing/hsadminng/rbac/rbacgrant/RbacGrantRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/rbac/rbacgrant/RbacGrantRepositoryIntegrationTest.java index 3ff9eda0..3b09e861 100644 --- a/src/test/java/net/hostsharing/hsadminng/rbac/rbacgrant/RbacGrantRepositoryIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/rbac/rbacgrant/RbacGrantRepositoryIntegrationTest.java @@ -25,7 +25,6 @@ import java.util.UUID; import static net.hostsharing.test.JpaAttempt.attempt; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assumptions.assumeThat; @DataJpaTest @Import( { Context.class, JpaAttempt.class }) @@ -186,9 +185,8 @@ class RbacGrantRepositoryIntegrationTest extends ContextBasedTest { // when context("customer-admin@xxx.example.com", "test_customer#xxx.admin"); - final var revokeAttempt = attempt(em, () -> { - rbacGrantRepository.deleteByRbacGrantId(grant.getRbacGrantId()); - }); + final var revokeAttempt = attempt(em, () -> + rbacGrantRepository.deleteByRbacGrantId(grant.getRbacGrantId())); // then context("customer-admin@xxx.example.com", "test_customer#xxx.admin"); @@ -208,9 +206,8 @@ class RbacGrantRepositoryIntegrationTest extends ContextBasedTest { // when context("pac-admin-xxx00@xxx.example.com", "test_package#xxx00.admin"); - final var revokeAttempt = attempt(em, () -> { - rbacGrantRepository.deleteByRbacGrantId(grant.getRbacGrantId()); - }); + final var revokeAttempt = attempt(em, () -> + rbacGrantRepository.deleteByRbacGrantId(grant.getRbacGrantId())); // then assertThat(revokeAttempt.caughtExceptionsRootCause()).isNull(); @@ -230,9 +227,8 @@ class RbacGrantRepositoryIntegrationTest extends ContextBasedTest { // when context("pac-admin-xxx00@xxx.example.com", "test_package#xxx00.admin"); - final var revokeAttempt = attempt(em, () -> { - rbacGrantRepository.deleteByRbacGrantId(grant.getRbacGrantId()); - }); + final var revokeAttempt = attempt(em, () -> + rbacGrantRepository.deleteByRbacGrantId(grant.getRbacGrantId())); // then revokeAttempt.assertExceptionWithRootCauseMessage( @@ -255,10 +251,10 @@ class RbacGrantRepositoryIntegrationTest extends ContextBasedTest { rbacGrantRepository.save(grant) ); - assumeThat(grantAttempt.caughtException()).isNull(); - assumeThat(rawRbacGrantRepository.findAll()) + assertThat(grantAttempt.caughtException()).isNull(); + assertThat(rawRbacGrantRepository.findAll()) .extracting(RawRbacGrantEntity::toDisplay) - .contains("{ grant role %s to user %s by role %s and assume }".formatted( + .contains("{ grant role %s to user %s by %s and assume }".formatted( with.grantedRole, with.granteeUserName, with.assumedRole )); diff --git a/src/test/java/net/hostsharing/hsadminng/rbac/rbacuser/RbacUserRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/rbac/rbacuser/RbacUserRepositoryIntegrationTest.java index bd2257ef..ea0a3109 100644 --- a/src/test/java/net/hostsharing/hsadminng/rbac/rbacuser/RbacUserRepositoryIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/rbac/rbacuser/RbacUserRepositoryIntegrationTest.java @@ -61,11 +61,6 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest { assertThat(result.returnedValue()).isNotNull() .extracting(RbacUserEntity::getUuid).isEqualTo(givenUuid); assertThat(rbacUserRepository.findByName(result.returnedValue().getName())).isNotNull(); - // jpaAttempt.transacted(() -> { - // context(givenUser.getName()); - // assertThat(em.find(RbacUserEntity.class, givenUser.getUuid())) - // .isNotNull().extracting(RbacUserEntity::getName).isEqualTo(givenUser.getName()); - // }).assertSuccessful(); } } @@ -87,9 +82,6 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest { // then the user is deleted result.assertSuccessful(); assertThat(rbacUserRepository.findByName(givenUser.getName())).isNull(); - // jpaAttempt.transacted(() -> { - // assertThat(rbacUserRepository.findByName(givenUser.getName())).isNull(); - // }).assertSuccessful(); } } diff --git a/src/test/java/net/hostsharing/hsadminng/test/cust/TestCustomer.java b/src/test/java/net/hostsharing/hsadminng/test/cust/TestCustomer.java index 7d5b0b43..bb00975f 100644 --- a/src/test/java/net/hostsharing/hsadminng/test/cust/TestCustomer.java +++ b/src/test/java/net/hostsharing/hsadminng/test/cust/TestCustomer.java @@ -1,6 +1,5 @@ package net.hostsharing.hsadminng.test.cust; -import static java.util.UUID.randomUUID; public class TestCustomer { diff --git a/src/test/java/net/hostsharing/hsadminng/test/pac/TestPackageControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/test/pac/TestPackageControllerAcceptanceTest.java index e8cfc5bb..fd51ebf8 100644 --- a/src/test/java/net/hostsharing/hsadminng/test/pac/TestPackageControllerAcceptanceTest.java +++ b/src/test/java/net/hostsharing/hsadminng/test/pac/TestPackageControllerAcceptanceTest.java @@ -16,7 +16,7 @@ import org.springframework.transaction.annotation.Transactional; import java.util.UUID; import static java.lang.String.format; -import static org.assertj.core.api.Assumptions.assumeThat; +import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; @@ -85,7 +85,8 @@ class TestPackageControllerAcceptanceTest { @Test void withDescriptionUpdatesDescription() { - assumeThat(getDescriptionOfPackage("xxx00")) + assertThat(getDescriptionOfPackage("xxx00")) + .as("precondition failed") .isEqualTo("Here you can add your own description of package xxx00."); final var randomDescription = RandomStringUtils.randomAlphanumeric(80); @@ -117,7 +118,8 @@ class TestPackageControllerAcceptanceTest { @Test void withNullDescriptionUpdatesDescriptionToNull() { - assumeThat(getDescriptionOfPackage("xxx01")) + assertThat(getDescriptionOfPackage("xxx01")) + .as("precondition failed") .isEqualTo("Here you can add your own description of package xxx01."); // @formatter:off @@ -146,7 +148,8 @@ class TestPackageControllerAcceptanceTest { @Test void withoutDescriptionDoesNothing() { - assumeThat(getDescriptionOfPackage("xxx02")) + assertThat(getDescriptionOfPackage("xxx02")) + .as("precondition failed") .isEqualTo("Here you can add your own description of package xxx02."); // @formatter:off diff --git a/src/test/java/net/hostsharing/test/JpaAttempt.java b/src/test/java/net/hostsharing/test/JpaAttempt.java index a7244e37..589049bb 100644 --- a/src/test/java/net/hostsharing/test/JpaAttempt.java +++ b/src/test/java/net/hostsharing/test/JpaAttempt.java @@ -12,7 +12,6 @@ import java.util.Optional; import java.util.function.Supplier; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assumptions.assumeThat; /** * Wraps the 'when' part of a DataJpaTest to improve readability of tests. @@ -138,7 +137,7 @@ public class JpaAttempt { } public JpaResult<T> assumeSuccessful() { - assumeThat(exception).as(firstRootCauseMessageLineOf(exception)).isNull(); + assertThat(exception).as(firstRootCauseMessageLineOf(exception)).isNull(); return this; }