From f71631ab097d0c6b7a2f2883efc8e784c622cf87 Mon Sep 17 00:00:00 2001 From: Nikan Radan Date: Fri, 7 Nov 2025 22:32:20 -0800 Subject: [PATCH 1/3] Gradle Migration 1. Migrated from Maven to Gradle. 2. Migrated workflows from Maven to Gradle. 3. Added Gradle related files to the .gitignore. 4. Added a Gradle plugin to handle license headers automatically (both `ConnectConfigTest.java` files and `DatabaseLifecycleTest.java` were missing headers, this makes sure that never happens again and keeps all headers consistent). See `HEADER`. 5. Suppressed all PMD and normal false positive warnings to make Gradle happy while fixing accurate warnings. 6. Used non deprecated alternatives to anything that was deprecated to make Gradle happy. 7. Added quoting to `detect_linux_distribution.sh` to prevent word splitting which would break the script. 8. Added `.gitattributes` to normalize line endings and protect the `gradle-wrapper.jar`. --- .PVS-Studio/ide-warnings.json | 144 +++++++ .PVS-Studio/settings.json | 46 +++ .gitattributes | 5 + .github/dependabot.yml | 2 +- .github/workflows/release.yml | 62 ++- .github/workflows/test.yml | 26 +- .gitignore | 4 + HEADER | 13 + build.gradle.kts | 181 +++++++++ gradle.properties | 54 +++ gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 45457 bytes gradle/wrapper/gradle-wrapper.properties | 7 + gradlew | 248 +++++++++++ gradlew.bat | 93 +++++ pom.xml | 384 ------------------ settings.gradle.kts | 19 + .../db/postgres/embedded/ConnectionInfo.java | 6 +- .../embedded/DatabaseConnectionPreparer.java | 8 +- .../postgres/embedded/DatabasePreparer.java | 10 +- .../DefaultPostgresBinaryResolver.java | 19 +- .../postgres/embedded/EmbeddedPostgres.java | 230 +++++------ .../db/postgres/embedded/FlywayPreparer.java | 15 +- .../postgres/embedded/LiquibasePreparer.java | 19 +- .../postgres/embedded/PgBinaryResolver.java | 6 +- .../postgres/embedded/PreparedDbProvider.java | 78 ++-- .../embedded/ProcessOutputLogger.java | 10 +- .../postgres/junit/EmbeddedPostgresRules.java | 11 +- .../db/postgres/junit/PreparedDbRule.java | 23 +- .../junit/SingleInstancePostgresRule.java | 26 +- .../junit5/EmbeddedPostgresExtension.java | 8 +- .../postgres/junit5/PreparedDbExtension.java | 7 +- .../SingleInstancePostgresExtension.java | 11 +- .../test/db/postgres/util/ArchUtils.java | 30 +- .../test/db/postgres/util/LinuxUtils.java | 10 +- .../resources/sh/detect_linux_distribution.sh | 2 +- .../embedded/EmbeddedPostgresTest.java | 38 +- .../db/postgres/junit/ConnectConfigTest.java | 19 +- .../db/postgres/junit/FlywayPreparerTest.java | 18 +- .../test/db/postgres/junit/IsolationTest.java | 29 +- ...LiquibasePreparerClasspathContextTest.java | 10 +- .../junit/LiquibasePreparerClasspathTest.java | 10 +- .../LiquibasePreparerFileContextTest.java | 10 +- .../junit/LiquibasePreparerFileTest.java | 10 +- .../junit/PreparedDbCustomizerTest.java | 5 +- .../db/postgres/junit/PreparedDbTest.java | 36 +- .../junit/SingleInstanceRuleTest.java | 23 +- .../db/postgres/junit5/ConnectConfigTest.java | 25 +- .../junit5/DatabaseLifecycleTest.java | 46 ++- .../postgres/junit5/FlywayPreparerTest.java | 25 +- .../db/postgres/junit5/IsolationTest.java | 33 +- ...LiquibasePreparerClasspathContextTest.java | 17 +- .../LiquibasePreparerClasspathTest.java | 17 +- .../LiquibasePreparerFileContextTest.java | 17 +- .../junit5/LiquibasePreparerFileTest.java | 15 +- .../junit5/PreparedDbCustomizerTest.java | 24 +- .../db/postgres/junit5/PreparedDbTest.java | 53 +-- .../junit5/SingleInstanceRuleTest.java | 27 +- src/test/resources/liqui/master-test.xml | 3 +- src/test/resources/liqui/master.xml | 4 +- src/test/resources/simplelogger.properties | 2 +- 60 files changed, 1440 insertions(+), 893 deletions(-) create mode 100644 .PVS-Studio/ide-warnings.json create mode 100644 .PVS-Studio/settings.json create mode 100644 .gitattributes create mode 100644 HEADER create mode 100644 build.gradle.kts create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat delete mode 100644 pom.xml create mode 100644 settings.gradle.kts diff --git a/.PVS-Studio/ide-warnings.json b/.PVS-Studio/ide-warnings.json new file mode 100644 index 00000000..2f171482 --- /dev/null +++ b/.PVS-Studio/ide-warnings.json @@ -0,0 +1,144 @@ +{ + "languages": { + "JAVA": { + "groups": { + "OWASP": "DISABLED", + "GA": "SHOW_ALL" + } + } + }, + "warnings": { + "V6027": true, + "V6026": true, + "V6029": true, + "V6028": true, + "V6023": true, + "V6022": true, + "V6025": true, + "V6024": true, + "V6021": true, + "V6020": true, + "V6038": true, + "V6037": true, + "V6039": true, + "V6034": true, + "V6033": true, + "V6036": true, + "V6035": true, + "V6030": true, + "V6032": true, + "V6031": true, + "V6126": true, + "V6005": true, + "V6125": true, + "V6004": true, + "V6007": true, + "V6128": true, + "V6006": true, + "V6127": true, + "V6001": true, + "V6089": true, + "V6122": true, + "V6088": true, + "V6121": true, + "V6124": true, + "V6003": true, + "V6002": true, + "V6123": true, + "V6009": true, + "V6008": true, + "V6129": true, + "V6085": true, + "V6084": true, + "V6087": true, + "V6120": true, + "V6086": true, + "V6081": true, + "V6080": true, + "V6083": true, + "V6082": true, + "V6016": true, + "V6015": true, + "V6018": true, + "V6017": true, + "V6012": true, + "V6011": true, + "V6099": true, + "V6132": true, + "V6014": true, + "V6013": true, + "V6019": true, + "V6090": true, + "V6096": true, + "V6095": true, + "V6010": true, + "V6131": true, + "V6098": true, + "V6097": true, + "V6130": true, + "V6092": true, + "V6091": true, + "V6094": true, + "V6093": true, + "V6104": true, + "V6103": true, + "V6106": true, + "V6105": true, + "V6100": true, + "V6067": true, + "V6066": true, + "V6069": true, + "V6102": true, + "V6068": true, + "V6101": true, + "V6108": true, + "V6107": true, + "V6109": true, + "V6063": true, + "V6062": true, + "V6065": true, + "V6064": true, + "V6061": true, + "V6060": true, + "V6115": true, + "V6114": true, + "V6117": true, + "V6116": true, + "V6078": true, + "V6111": true, + "V6077": true, + "V6110": true, + "V6113": true, + "V6079": true, + "V6112": true, + "V6119": true, + "V6118": true, + "V6074": true, + "V6073": true, + "V6076": true, + "V6075": true, + "V6070": true, + "V6072": true, + "V6071": true, + "V6049": true, + "V6048": true, + "V6045": true, + "V6044": true, + "V6047": true, + "V6046": true, + "V6041": true, + "V6040": true, + "V6043": true, + "V6042": true, + "V6059": true, + "V6056": true, + "V6055": true, + "V6058": true, + "V6057": true, + "V6052": true, + "V6051": true, + "V6054": true, + "V6053": true, + "V6050": true + } +} \ No newline at end of file diff --git a/.PVS-Studio/settings.json b/.PVS-Studio/settings.json new file mode 100644 index 00000000..12631c48 --- /dev/null +++ b/.PVS-Studio/settings.json @@ -0,0 +1,46 @@ +{ + "src": [], + "ext": [], + "threads": 15, + "output-type": "json", + "securityRelatedIssues": false, + "annotation-file": [], + "incremental": false, + "force-rebuild": false, + "disable-cache": false, + "exclude": [], + "analyze-only": [], + "fail-on-warnings": false, + "analysis-mode": [ + "GA" + ], + "disabled-warnings": [], + "enabled-warnings": [], + "additional-warnings": [], + "suppress-base": ".PVS-Studio/suppress_base.json", + "timeout": 10, + "compatibility": false, + "exclude-packages": [], + "activate-license": false, + "version": false, + "is-java-core-subprocess-with-add-opens-for-native-libs-field-reflective-access": false, + "write-to-stdout": false, + "verbose": false, + "useOfflineDocumentation": false, + "skip-modules": [], + "include-generated": false, + "launch-mode": "IDEA", + "enable-all-warnings": false, + "benchmark": false, + "java": "java", + "jvm-arguments": [ + "-Xss64m" + ], + "traceLogFileName": "pvs.log", + "traceSpoonLogFileName": "spoon.log", + "check-license": false, + "logging": "OFF", + "project": "C:/Users/organ/Documents/GitHub/embedded-postgres", + "type": "sources", + "disableDiag": false +} \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..eaeceeea --- /dev/null +++ b/.gitattributes @@ -0,0 +1,5 @@ +* text=auto eol=lf +gradlew text eol=lf +*.bat text eol=crlf +*.cmd text eol=crlf +gradle-wrapper.jar -text -diff -merge -filter \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml index c9b2105b..519d9124 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,7 +4,7 @@ updates: directory: "/" schedule: interval: "weekly" - - package-ecosystem: "maven" + - package-ecosystem: "gradle" directory: "/" schedule: interval: "weekly" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 98352d0f..6be0656b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,53 +3,49 @@ on: milestone: types: [closed] jobs: - build: + release: name: Release ${{ github.event.milestone.title }} runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: ref: master fetch-depth: 0 + - name: Validate Gradle Wrapper + uses: gradle/actions/wrapper-validation@v5 - name: Set up Git run: | git config user.name "Zonky Bot" git config user.email "bot@zonky.com" - - name: Set up JDK - uses: actions/setup-java@v4 + - name: Set up JDK 8 + uses: actions/setup-java@v5 with: distribution: 'zulu' - java-version: 8 - server-id: ossrh - server-username: MAVEN_USER - server-password: MAVEN_PASS - gpg-private-key: ${{ secrets.SIGNING_CERT }} - gpg-passphrase: SIGNING_PASS - - name: Release with Maven + java-version: '8' + cache: 'gradle' + - name: Make Gradle wrapper executable + run: chmod +x gradlew + - name: Publish to Maven Central via Gradle env: RELEASE_VERSION: ${{ github.event.milestone.title }} - MAVEN_USER: ${{ secrets.MAVEN_USER }} - MAVEN_PASS: ${{ secrets.MAVEN_PASS }} - SIGNING_PASS: ${{ secrets.SIGNING_PASS }} - run: mvn -B release:prepare release:perform -DreleaseVersion=$RELEASE_VERSION - - name: Upload staged artifacts to Central Sonatype + # Gradle signing plugin (build.gradle.kts) + MAVEN_SIGNING_KEY: ${{ secrets.SIGNING_CERT }} + MAVEN_SIGNING_PASSPHRASE: ${{ secrets.SIGNING_PASS }} + # nmcp credentials (build.gradle.kts) + USERNAME_TOKEN: ${{ secrets.MAVEN_USER }} + PASSWORD_TOKEN: ${{ secrets.MAVEN_PASS }} + # Use the milestone title as the build's version without touching gradle.properties + run: | + ./gradlew \ + -Pversion=$RELEASE_VERSION \ + clean check publishAllPublicationsToCentralPortal \ + --stacktrace + # Reproduces Maven Release Plugin’s v@{project.version} tag + - name: Tag release + if: success() env: - SONATYPE_USERNAME: ${{ secrets.MAVEN_USER }} - SONATYPE_PASSWORD: ${{ secrets.MAVEN_PASS }} + RELEASE_VERSION: ${{ github.event.milestone.title }} run: | - SONATYPE_TOKEN=$(printf "$SONATYPE_USERNAME:$SONATYPE_PASSWORD" | base64) - PUBLISH_NAMESPACE="io.zonky" - echo "Uploading artifacts from OSSRH-Staging to Central Sonatype..." - RESPONSE=$(curl -s -w "%{http_code}" -o response_body.txt -X POST \ - -H "Authorization: Bearer $SONATYPE_TOKEN" \ - "https://ossrh-staging-api.central.sonatype.com/manual/upload/defaultRepository/$PUBLISH_NAMESPACE?publishing_type=user_managed") - if [ "$RESPONSE" -ne 200 ]; then - echo "Failed to upload artifacts to Central Sonatype. Response code: $RESPONSE. Response body: " - cat response_body.txt - echo "Visit https://central.sonatype.com/publishing/deployments for more information." - exit 1 - else - echo "Artifacts were uploaded successfully to Central Sonatype." - echo "Visit https://central.sonatype.com/publishing/deployments to view your artifacts." - fi + git tag "v$RELEASE_VERSION" + git push origin "v$RELEASE_VERSION" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 84b53f3a..f573b40b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,15 +6,19 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - java: [8, 11, 17, 21, 22] # LTS and newer versions + java: [8, 11, 17, 21, 25] # LTS and newer versions steps: - - name: Checkout project - uses: actions/checkout@v4 - - name: Set up JDK - uses: actions/setup-java@v4 - with: - distribution: 'zulu' - java-version: ${{ matrix.java }} - cache: 'maven' - - name: Build with Maven - run: mvn -B test + - name: Checkout project + uses: actions/checkout@v5 + - name: Validate Gradle Wrapper + uses: gradle/actions/wrapper-validation@v5 + - name: Set up JDK + uses: actions/setup-java@v5 + with: + distribution: 'zulu' + java-version: ${{ matrix.java }} + cache: 'gradle' + - name: Make Gradle wrapper executable + run: chmod +x gradlew + - name: Build with Gradle + run: ./gradlew check diff --git a/.gitignore b/.gitignore index 481a27f1..a1c2952f 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,7 @@ target/ .project .settings dist/ +.gradle/ +build/ +out/ +classes/ \ No newline at end of file diff --git a/HEADER b/HEADER new file mode 100644 index 00000000..17f32874 --- /dev/null +++ b/HEADER @@ -0,0 +1,13 @@ +Copyright ${CREATION_YEAR} Tomas Vanek + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 00000000..df6a23c3 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,181 @@ +import enforcer.rules.DependencyConvergence +import org.apache.tools.ant.taskdefs.condition.Os + +plugins { + `java-library` + `maven-publish` + signing + pmd + id("dev.yumi.gradle.licenser") + id("com.gradleup.nmcp") + id("de.aaschmid.cpd") + id("org.kordamp.gradle.project-enforcer") +} + +val projectName = providers.gradleProperty("name") +val projectGroup = providers.gradleProperty("group") +val projectVersion = providers.gradleProperty("version") + +val javaVersion = providers.gradleProperty("java_version") + +val embeddedPostgresBinariesVersion = providers.gradleProperty("embedded_postgres_binaries_version") +val commonsCodecVersion = providers.gradleProperty("commons_codec_version") +val commonsCompressVersion = providers.gradleProperty("commons_compress_version") +val commonsIoVersion = providers.gradleProperty("commons_io_version") +val commonsLang3Version = providers.gradleProperty("commons_lang3_version") +val flywayVersion = providers.gradleProperty("flyway_version") +val junit4Version = providers.gradleProperty("junit4_version") +val junit5Version = providers.gradleProperty("junit5_version") +val liquibaseVersion = providers.gradleProperty("liquibase_version") +val mockitoVersion = providers.gradleProperty("mockito_version") +val pmdVersion = providers.gradleProperty("pmd_version") +val postgresqlVersion = providers.gradleProperty("postgresql_version") +val slf4jVersion = providers.gradleProperty("slf4j_version") +val xzVersion = providers.gradleProperty("xz_version") + +description = "Embedded PostgreSQL Server" +base.archivesName = projectName.get() +group = projectGroup.get() +version = projectVersion.get() + +repositories { mavenCentral() } + +dependencies { + runtimeOnly("io.zonky.test.postgres:embedded-postgres-binaries-windows-amd64:${embeddedPostgresBinariesVersion.get()}") + runtimeOnly("io.zonky.test.postgres:embedded-postgres-binaries-darwin-amd64:${embeddedPostgresBinariesVersion.get()}") + runtimeOnly("io.zonky.test.postgres:embedded-postgres-binaries-linux-amd64:${embeddedPostgresBinariesVersion.get()}") + runtimeOnly("io.zonky.test.postgres:embedded-postgres-binaries-linux-amd64-alpine:${embeddedPostgresBinariesVersion.get()}") + + implementation("org.slf4j:slf4j-api:${slf4jVersion.get()}") + implementation("org.apache.commons:commons-lang3:${commonsLang3Version.get()}") + implementation("org.apache.commons:commons-compress:${commonsCompressVersion.get()}") + implementation("org.tukaani:xz:${xzVersion.get()}") + implementation("commons-io:commons-io:${commonsIoVersion.get()}") + implementation("commons-codec:commons-codec:${commonsCodecVersion.get()}") + implementation("org.postgresql:postgresql:${postgresqlVersion.get()}") + + compileOnly("org.flywaydb:flyway-core:${flywayVersion.get()}") + compileOnly("org.liquibase:liquibase-core:${liquibaseVersion.get()}") + compileOnly("junit:junit:${junit4Version.get()}") + compileOnly("org.junit.jupiter:junit-jupiter-api:${junit5Version.get()}") + + testImplementation("org.flywaydb:flyway-core:${flywayVersion.get()}") + testImplementation("org.liquibase:liquibase-core:${liquibaseVersion.get()}") + testImplementation(platform("org.junit:junit-bom:${junit5Version.get()}")) + testImplementation("org.junit.jupiter:junit-jupiter") + testImplementation("junit:junit:${junit4Version.get()}") + testImplementation("org.mockito:mockito-core:${mockitoVersion.get()}") + + testRuntimeOnly("org.junit.vintage:junit-vintage-engine") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") + testRuntimeOnly("org.slf4j:slf4j-simple:${slf4jVersion.get()}") +} + +java { + toolchain.languageVersion = JavaLanguageVersion.of(javaVersion.get()) + sourceCompatibility = JavaVersion.toVersion(javaVersion.get().toInt()) + targetCompatibility = JavaVersion.toVersion(javaVersion.get().toInt()) + withSourcesJar() + withJavadocJar() +} +tasks { + withType().configureEach { + options.encoding = "UTF-8" + options.compilerArgs.add("-Xlint:deprecation") + sourceCompatibility = javaVersion.get() + targetCompatibility = javaVersion.get() + if (javaVersion.get().toInt() > 8) options.release = javaVersion.get().toInt() + } + withType().configureEach { + options.encoding = "UTF-8" + val standardOptions = options as StandardJavadocDocletOptions + standardOptions.addStringOption("Xdoclint:none", "-quiet") + } + withType().configureEach { defaultCharacterEncoding = "UTF-8" } + withType().configureEach { + defaultCharacterEncoding = "UTF-8" + useJUnitPlatform() + if (!Os.isFamily(Os.FAMILY_WINDOWS)) environment("LC_ALL", System.getenv("LC_ALL") ?: "en_US.UTF-8") + } + named("check") { dependsOn("cpdCheck") } +} +pmd { + toolVersion = pmdVersion.get() + isConsoleOutput = true + isIgnoreFailures = false + rulesMinimumPriority = 4 +} +cpd { + toolVersion = pmdVersion.get() + isIgnoreFailures = true + minimumTokenCount = 100 + encoding = "UTF-8" +} +enforce { + rule(DependencyConvergence::class.java) { + failOnDynamicVersions = true + failOnChangingVersions = true + failOnNonReproducibleResolution = true + } +} +license { + rule(file("./HEADER")) + include("**/*.java") + exclude("**/*.properties") +} +publishing { + publications { + create("maven") { + from(components["java"]) + groupId = project.group.toString() + artifactId = base.archivesName.get() + version = project.version.toString() + pom { + name = projectName + description = project.description + url = "https://github.com/zonkyio/embedded-postgres" + + licenses { + license { + name = "The Apache License, Version 2.0" + url = "https://www.apache.org/licenses/LICENSE-2.0.txt" + distribution = "repo" + } + } + developers { + developer { + name = "Tomas Vanek" + email = "tomix26@gmail.com" + } + developer { + name = "Zonky Developers" + email = "developers@zonky.cz" + } + } + scm { + url = "https://github.com/zonkyio/embedded-postgres" + connection = "scm:git:https://github.com/zonkyio/embedded-postgres.git" + developerConnection = "scm:git:https://github.com/zonkyio/embedded-postgres.git" + tag = "HEAD" + } + } + } + } +} +signing { + val signingKey = System.getenv("MAVEN_SIGNING_KEY") + val signingPassphrase = System.getenv("MAVEN_SIGNING_PASSPHRASE") + if (!signingKey.isNullOrBlank()) { + isRequired = true + useInMemoryPgpKeys(signingKey, signingPassphrase) + sign(publishing.publications) + } else { + isRequired = false + } +} +nmcp { + publishAllPublicationsToCentralPortal { + username = System.getenv("USERNAME_TOKEN") ?: "" + password = System.getenv("PASSWORD_TOKEN") ?: "" + } +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 00000000..eb27cf96 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,54 @@ +########################################################################## +# Standard Properties +org.gradle.jvmargs = -Xmx1G -Dfile.encoding=UTF-8 +org.gradle.warning.mode = all +org.gradle.configuration-cache = false +########################################################################## +# Maven Properties +group = io.zonky.test +name = embedded-postgres +version = 2.1.2-SNAPSHOT +########################################################################## +# Java Version +java_version = 8 +########################################################################## +# Dependency Versions +# Check this on https://central.sonatype.com/artifact/io.zonky.test.postgres/embedded-postgres-binaries-bom/ +embedded_postgres_binaries_version = 14.19.0 +# Check this on https://central.sonatype.com/artifact/commons-codec/commons-codec/ +commons_codec_version = 1.19.0 +# Check this on https://central.sonatype.com/artifact/org.apache.commons/commons-compress/ +commons_compress_version = 1.28.0 +# Check this on https://central.sonatype.com/artifact/commons-io/commons-io/ +commons_io_version = 2.21.0 +# Check this on https://central.sonatype.com/artifact/org.apache.commons/commons-lang3/ +commons_lang3_version = 3.19.0 +# Check this on https://central.sonatype.com/artifact/org.flywaydb/flyway-core/ +flyway_version = 9.22.3 +# Check this on https://central.sonatype.com/artifact/org.junit.jupiter/junit-jupiter-api/ +junit5_version = 5.14.1 +# Check this on https://central.sonatype.com/artifact/junit/junit/ +junit4_version = 4.13.2 +# Check this on https://central.sonatype.com/artifact/org.liquibase/liquibase-core/ +liquibase_version = 4.33.0 +# Check this on https://central.sonatype.com/artifact/org.mockito/mockito-core/ +mockito_version = 4.11.0 +# Check this on https://central.sonatype.com/artifact/net.sourceforge.pmd/pmd/ +pmd_version = 7.18.0 +# Check this on https://central.sonatype.com/artifact/org.postgresql/postgresql/ +postgresql_version = 42.7.8 +# Check this on https://central.sonatype.com/artifact/org.slf4j/slf4j-api/ +slf4j_version = 1.7.36 +# Check this on https://central.sonatype.com/artifact/org.tukaani/xz/ +xz_version = 1.10 +########################################################################## +# Plugin Versions +# Check this on https://plugins.gradle.org/plugin/dev.yumi.gradle.licenser/ +yumi_gradle_licenser_version = 2.2.1 +# Check this on https://github.com/GradleUp/nmcp/releases/latest/ +nmcp_version = 1.2.0 +# Check this on https://github.com/aaschmid/gradle-cpd-plugin/releases/latest/ +cpd_version = 3.5 +# Check this on https://github.com/kordamp/enforcer-gradle-plugin/releases/latest/ +enforcer_gradle_version = 0.14.0 +########################################################################## diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..8bdaf60c75ab801e22807dde59e12a8735a34077 GIT binary patch literal 45457 zcma&NW0YlEwk;ePwr$(aux;D69T}N{9ky*d!_2U4+qUuIRNZ#Jck8}7U+vcB{`IjNZqX3eq5;s6ddAkU&5{L|^Ow`ym2B0m+K02+~Q)i807X3X94qi>j)C0e$=H zm31v`=T&y}ACuKx7G~yWSYncG=NFB>O2);i9EmJ(9jSamq?Crj$g~1l3m-4M7;BWn zau2S&sSA0b0Rhg>6YlVLQa;D#)1yw+eGs~36Q$}5?avIRne3TQZXb<^e}?T69w<9~ zUmx1cG0uZ?Kd;Brd$$>r>&MrY*3$t^PWF1+J+G_xmpHW=>mly$<>~wHH+Bt3mzN7W zhR)g{_veH6>*KxLJ~~s{9HZm!UeC86d_>42NRqd$ev8zSMq4kt)q*>8kJ8p|^wuKx zq2Is_HJPoQ_apSoT?zJj7vXBp!xejBc^7F|zU0rhy%Ub*Dy#jJs!>1?CmJ-gulPVX zKit>RVmjL=G?>jytf^U@mfnC*1-7EVag@%ROu*#kA+)Rxq?MGK0v-dp^kM?nyMngb z_poL>GLThB7xAO*I7&?4^Nj`<@O@>&0M-QxIi zD@n}s%CYI4Be19C$lAb9Bbm6!R{&A;=yh=#fnFyb`s7S5W3?arZf?$khCwkGN!+GY~GT8-`!6pFr zbFBVEF`kAgtecfjJ`flN2Z!$$8}6hV>Tu;+rN%$X^t8fI>tXQnRn^$UhXO8Gu zt$~QON8`doV&{h}=2!}+xJKrNPcIQid?WuHUC-i%P^F(^z#XB`&&`xTK&L+i8a3a@ zkV-Jy;AnyQ`N=&KONV_^-0WJA{b|c#_l=v!19U@hS~M-*ix16$r01GN3#naZ|DxY2 z76nbjbOnFcx4bKbEoH~^=EikiZ)_*kOb>nW6>_vjf-UCf0uUy~QBb7~WfVO6qN@ns zz=XEG0s5Yp`mlmUad)8!(QDgIzY=OK%_hhPStbyYYd|~zDIc3J4 zy9y%wZOW>}eG4&&;Z>vj&Mjg+>4gL! z(@oCTFf-I^54t=*4AhKRoE-0Ky=qg3XK2Mu!Bmw@z>y(|a#(6PcfbVTw-dUqyx4x4 z3O#+hW1ANwSv-U+9otHE#U9T>(nWx>^7RO_aI>${jvfZQ{mUwiaxHau!H z0Nc}ucJu+bKux?l!dQ2QA(r@(5KZl(Or=U!=2K*8?D=ZT-IAcAX!5OI3w@`sF@$($ zbDk0p&3X0P%B0aKdijO|s})70K&mk1DC|P##b=k@fcJ|lo@JNWRUc>KL?6dJpvtSUK zxR|w8Bo6K&y~Bd}gvuz*3z z@sPJr{(!?mi@okhudaM{t3gp9TJ!|@j4eO1C&=@h#|QLCUKLaKVL z!lls$%N&ZG7yO#jK?U>bJ+^F@K#A4d&Jz4boGmptagnK!Qu{Ob>%+60xRYK>iffd_ z>6%0K)p!VwP$^@Apm%NrS6TpKJwj_Q=k~?4=_*NIe~eh_QtRaqX4t-rJAGYdB{pGq zSXX)-dR8mQ)X|;8@_=J6Dk7MfMp;x)^aZeCtScHs12t3vL+p-6!qhPkOM1OYQ z8YXW5tWp)Th(+$m7SnV_hNGKAP`JF4URkkNc@YV9}FK$9k zR&qgi$Cj#4bC1VK%#U)f%(+oQJ+EqvV{uAq1YG0riLvGxW@)m;*ayU-BSW61COFy0 z(-l>GJqYl;*x1PnRZ(p3Lm}* zlkpWyCoYtg9pAZ5RU^%w=vN{3Y<6WImxj(*SCcJsFj?o6CZ~>cWW^foliM#qN#We{ zwsL!u1$rzC1#4~bILZm*a!T{^kCci$XOJADm)P;y^%x5)#G#_!2uNp^S;cE`*ASCn;}H7pP^RRA z6lfXK(r4dy<_}R|(7%Lyo>QFP#s31E8zsYA${gSUykUV@?lyDNF=KhTeF^*lu7C*{ zBCIjy;bIE;9inJ$IT8_jL%)Q{7itmncYlkf2`lHl(gTwD%LmEPo^gskydVxMd~Do` zO8EzF!yn!r|BEgPjhW#>g(unY#n}=#4J;3FD2ThN5LpO0tI2~pqICaFAGT%%;3Xx$ z>~Ng(64xH-RV^Rj4=A_q1Ee8kcF}8HN{5kjYX0ADh}jq{q18x(pV!23pVsK5S}{M#p8|+LvfKx|_3;9{+6cu7%5o-+R@z>TlTft#kcJ`s2-j zUe4dgpInZU!<}aTGuwgdWJZ#8TPiV9QW<-o!ibBn&)?!ZDomECehvT7GSCRyF#VN2&5GShch9*}4p;8TX~cW*<#( zv-HmU7&+YUWO__NN3UbTFJ&^#3vxW4U9q5=&ORa+2M$4rskA4xV$rFSEYBGy55b{z z!)$_fYXiY?-GWDhGZXgTw}#ilrw=BiN(DGO*W7Vw(} zjUexksYLt_Nq?pl_nVa@c1W#edQKbT>VSN1NK?DulHkFpI-LXl7{;dl@z0#v?x%U& z8k8M1X6%TwR4BQ_eEWJASvMTy?@fQubBU__A_US567I-~;_VcX^NJ-E(ZPR^NASj1 zVP!LIf8QKtcdeH#w6ak50At)e={eF_Ns6J2Iko6dn8Qwa6!NQHZMGsD zhzWeSFK<{hJV*!cIHxjgR+e#lkUHCss-j)$g zF}DyS531TUXKPPIoePo{yH%qEr-dLMOhv^sC&@9YI~uvl?rBp^A-57{aH_wLg0&a|UxKLlYZQ24fpb24Qjil`4OCyt0<1eu>5i1Acv zaZtQRF)Q;?Aw3idg;8Yg9Cb#)03?pQ@O*bCloG zC^|TnJl`GXN*8iI;Ql&_QIY0ik}rqB;cNZ-qagp=qmci9eScHsRXG$zRNdf4SleJ} z7||<#PCW~0>3u8PP=-DjNhD(^(B0AFF+(oKOiQyO5#v4nI|v_D5@c2;zE`}DK!%;H zUn|IZ6P;rl*5`E(srr6@-hpae!jW=-G zC<*R?RLwL;#+hxN4fJ!oP4fX`vC3&)o!#l4y@MrmbmL{t;VP%7tMA-&vju_L zhtHbOL4`O;h*5^e3F{b9(mDwY6JwL8w`oi28xOyj`pVo!75hngQDNg7^D$h4t&1p2 ziWD_!ap3GM(S)?@UwWk=Szym^eDxSx3NaR}+l1~(@0car6tfP#sZRTb~w!WAS{+|SgUN3Tv`J4OMf z9ta_f>-`!`I@KA=CXj_J>CE7T`yGmej0}61sE(%nZa1WC_tV6odiysHA5gzfWN-`uXF46mhJGLpvNTBmx$!i zF67bAz~E|P{L6t1B+K|Cutp&h$fDjyq9JFy$7c_tB(Q$sR)#iMQH3{Og1AyD^lyQwX6#B|*ecl{-_;*B>~WSFInaRE_q6 zpK#uCprrCb`MU^AGddA#SS{P7-OS9h%+1`~9v-s^{s8faWNpt*Pmk_ECjt(wrpr{C_xdAqR(@!ERTSs@F%^DkE@No}wqol~pS^e7>ksF_NhL0?6R4g`P- zk8lMrVir~b(KY+hk5LQngwm`ZQT5t1^7AzHB2My6o)_ejR0{VxU<*r-Gld`l6tfA` zKoj%x9=>Ce|1R|1*aC}|F0R32^KMLAHN}MA<8NNaZ^j?HKxSwxz`N2hK8lEb{jE0& zg4G_6F@#NyDN?=i@=)eidKhlg!nQoA{`PgaH{;t|M#5z}a`u?^gy{5L~I2smLR z*4RmNxHqf9>D>sXSemHK!h4uPwMRb+W`6F>Q6j@isZ>-F=)B2*sTCD9A^jjUy)hjAw71B&$u}R(^R; zY9H3k8$|ounk>)EOi_;JAKV8U8ICSD@NrqB!&=)Ah_5hzp?L9Sw@c>>#f_kUhhm=p z1jRz8X7)~|VwO(MF3PS(|CL++1n|KT3*dhGjg!t_vR|8Yg($ z+$S$K=J`K6eG#^(J54=4&X#+7Car=_aeAuC>dHE+%v9HFu>r%ry|rwkrO-XPhR_#K zS{2Unv!_CvS7}Mb6IIT$D4Gq5v$Pvi5nbYB+1Yc&RY;3;XDihlvhhIG6AhAHsBYsm zK@MgSzs~y|+f|j-lsXKT0(%E2SkEb)p+|EkV5w8=F^!r1&0#0^tGhf9yPZ)iLJ^ zIXOg)HW_Vt{|r0W(`NmMLF$?3ZQpq+^OtjR-DaVLHpz%1+GZ7QGFA?(BIqBlVQ;)k zu)oO|KG&++gD9oL7aK4Zwjwi~5jqk6+w%{T$1`2>3Znh=OFg|kZ z>1cn>CZ>P|iQO%-Pic8wE9c*e%=3qNYKJ+z1{2=QHHFe=u3rqCWNhV_N*qzneN8A5 zj`1Ir7-5`33rjDmyIGvTx4K3qsks(I(;Kgmn%p#p3K zn8r9H8kQu+n@D$<#RZtmp$*T4B&QvT{K&qx(?>t@mX%3Lh}sr?gI#vNi=vV5d(D<=Cp5-y!a{~&y|Uz*PU{qe zI7g}mt!txT)U(q<+Xg_sSY%1wVHy;Dv3uze zJ>BIdSB2a|aK+?o63lR8QZhhP)KyQvV`J3)5q^j1-G}fq=E4&){*&hiam>ssYm!ya z#PsY0F}vT#twY1mXkGYmdd%_Uh12x0*6lN-HS-&5XWbJ^%su)-vffvKZ%rvLHVA<; zJP=h13;x?$v30`T)M)htph`=if#r#O5iC^ZHeXc6J8gewn zL!49!)>3I-q6XOZRG0=zjyQc`tl|RFCR}f-sNtc)I^~?Vv2t7tZZHvgU2Mfc9$LqG z!(iz&xb=q#4otDBO4p)KtEq}8NaIVcL3&pbvm@0Kk-~C@y3I{K61VDF_=}c`VN)3P z+{nBy^;=1N`A=xH$01dPesY_na*zrcnssA}Ix60C=sWg9EY=2>-yH&iqhhm28qq9Z z;}znS4ktr40Lf~G@6D5QxW&?q^R|=1+h!1%G4LhQs54c2Wo~4% zCA||d==lv2bP=9%hd0Dw_a$cz9kk)(Vo}NpSPx!vnV*0Bh9$CYP~ia#lEoLRJ8D#5 zSJS?}ABn1LX>8(Mfg&eefX*c0I5bf4<`gCy6VC{e>$&BbwFSJ0CgVa;0-U7=F81R+ zUmzz&c;H|%G&mSQ0K16Vosh?sjJW(Gp+1Yw+Yf4qOi|BFVbMrdO6~-U8Hr|L@LHeZ z0ALmXHsVm137&xnt#yYF$H%&AU!lf{W436Wq87nC16b%)p?r z70Wua59%7Quak50G7m3lOjtvcS>5}YL_~?Pti_pfAfQ!OxkX$arHRg|VrNx>R_Xyi z`N|Y7KV`z3(ZB2wT9{Dl8mtl zg^UOBv~k>Z(E)O>Z;~Z)W&4FhzwiPjUHE9&T#nlM)@hvAZL>cha-< zQ8_RL#P1?&2Qhk#c9fK9+xM#AneqzE-g(>chLp_Q2Xh$=MAsW z2ScEKr+YOD*R~mzy{bOJjs;X2y1}DVFZi7d_df^~((5a2%p%^4cf>vM_4Sn@@ssVJ z9ChGhs zbanJ+h74)3tWOviXI|v!=HU2mE%3Th$Mpx&lEeGFEBWRy8ogJY`BCXj@7s~bjrOY! z4nIU5S>_NrpN}|waZBC)$6ST8x91U2n?FGV8lS{&LFhHbuHU?SVU{p7yFSP_f#Eyh zJhI@o9lAeEwbZYC=~<(FZ$sJx^6j@gtl{yTOAz`Gj!Ab^y})eG&`Qt2cXdog2^~oOH^K@oHcE(L;wu2QiMv zJuGdhNd+H{t#Tjd<$PknMSfbI>L1YIdZ+uFf*Z=BEM)UPG3oDFe@8roB0h(*XAqRc zoxw`wQD@^nxGFxQXN9@GpkLqd?9@(_ZRS@EFRCO8J5{iuNAQO=!Lo5cCsPtt4=1qZN8z`EA2{ge@SjTyhiJE%ttk{~`SEl%5>s=9E~dUW0uws>&~3PwXJ!f>ShhP~U9dLvE8ElNt3g(6-d zdgtD;rgd^>1URef?*=8BkE&+HmzXD-4w61(p6o~Oxm`XexcHmnR*B~5a|u-Qz$2lf zXc$p91T~E4psJxhf^rdR!b_XmNv*?}!PK9@-asDTaen;p{Rxsa=1E}4kZ*}yQPoT0 zvM}t!CpJvk<`m~^$^1C^o1yM(BzY-Wz2q7C^+wfg-?}1bF?5Hk?S{^#U%wX4&lv0j zkNb)byI+nql(&65xV?_L<0tj!KMHX8Hmh2(udEG>@OPQ}KPtdwEuEb$?acp~yT1&r z|7YU<(v!0as6Xff5^XbKQIR&MpjSE)pmub+ECMZzn7c!|hnm_Rl&H_oXWU2!h7hhf zo&-@cLkZr#eNgUN9>b=QLE1V^b`($EX3RQIyg#45A^=G!jMY`qJ z8qjZ$*-V|?y0=zIM>!2q!Gi*t4J5Otr^OT3XzQ_GjATc(*eM zqllux#QtHhc>YtnswBNiS^t(dTDn|RYSI%i%-|sv1wh&|9jfeyx|IHowW)6uZWR<%n8I}6NidBm zJ>P7#5m`gnXLu;?7jQZ!PwA80d|AS*+mtrU6z+lzms6^vc4)6Zf+$l+Lk3AsEK7`_ zQ9LsS!2o#-pK+V`g#3hC$6*Z~PD%cwtOT8;7K3O=gHdC=WLK-i_DjPO#WN__#YLX|Akw3LnqUJUw8&7pUR;K zqJ98?rKMXE(tnmT`#080w%l1bGno7wXHQbl?QFU=GoK@d!Ov=IgsdHd-iIs4ahcgSj(L@F96=LKZ zeb5cJOVlcKBudawbz~AYk@!^p+E=dT^UhPE`96Q5J~cT-8^tp`J43nLbFD*Nf!w;6 zs>V!5#;?bwYflf0HtFvX_6_jh4GEpa0_s8UUe02@%$w^ym&%wI5_APD?9S4r9O@4m zq^Z5Br8#K)y@z*fo08@XCs;wKBydn+60ks4Z>_+PFD+PVTGNPFPg-V-|``!0l|XrTyUYA@mY?#bJYvD>jX&$o9VAbo?>?#Z^c+Y4Dl zXU9k`s74Sb$OYh7^B|SAVVz*jEW&GWG^cP<_!hW+#Qp|4791Od=HJcesFo?$#0eWD z8!Ib_>H1WQE}shsQiUNk!uWOyAzX>r(-N7;+(O333_ES7*^6z4{`p&O*q8xk{0xy@ zB&9LkW_B}_Y&?pXP-OYNJfqEWUVAPBk)pTP^;f+75Wa(W>^UO_*J05f1k{ zd-}j!4m@q#CaC6mLsQHD1&7{tJ*}LtE{g9LB>sIT7)l^ucm8&+L0=g1E_6#KHfS>A_Z?;pFP96*nX=1&ejZ+XvZ=ML`@oVu>s^WIjn^SY}n zboeP%`O9|dhzvnw%?wAsCw*lvVcv%bmO5M4cas>b%FHd;A6Z%Ej%;jgPuvL$nk=VQ=$-OTwslYg zJQtDS)|qkIs%)K$+r*_NTke8%Rv&w^v;|Ajh5QXaVh}ugccP}3E^(oGC5VO*4`&Q0 z&)z$6i_aKI*CqVBglCxo#9>eOkDD!voCJRFkNolvA2N&SAp^4<8{Y;#Kr5740 za|G`dYGE!9NGU3Ge6C)YByb6Wy#}EN`Ao#R!$LQ&SM#hifEvZp>1PAX{CSLqD4IuO z4#N4AjMj5t2|!yTMrl5r)`_{V6DlqVeTwo|tq4MHLZdZc5;=v9*ibc;IGYh+G|~PB zx2}BAv6p$}?7YpvhqHu7L;~)~Oe^Y)O(G(PJQB<&2AhwMw!(2#AHhjSsBYUd8MDeM z+UXXyV@@cQ`w}mJ2PGs>=jHE{%i44QsPPh(=yorg>jHic+K+S*q3{th6Ik^j=@%xo zXfa9L_<|xTL@UZ?4H`$vt9MOF`|*z&)!mECiuenMW`Eo2VE#|2>2ET7th6+VAmU(o zq$Fz^TUB*@a<}kr6I>r;6`l%8NWtVtkE?}Q<<$BIm*6Z(1EhDtA29O%5d1$0q#C&f zFhFrrss{hOsISjYGDOP*)j&zZUf9`xvR8G)gwxE$HtmKsezo`{Ta~V5u+J&Tg+{bh zhLlNbdzJNF6m$wZNblWNbP6>dTWhngsu=J{);9D|PPJ96aqM4Lc?&6H-J1W15uIpQ ziO{&pEc2}-cqw+)w$`p(k(_yRpmbp-Xcd`*;Y$X=o(v2K+ISW)B1(ZnkV`g4rHQ=s z+J?F9&(||&86pi}snC07Lxi1ja>6kvnut;|Ql3fD)%k+ASe^S|lN69+Ek3UwsSx=2EH)t}K>~ z`Mz-SSVH29@DWyl`ChuGAkG>J;>8ZmLhm>uEmUvLqar~vK3lS;4s<{+ehMsFXM(l- zRt=HT>h9G)JS*&(dbXrM&z;)66C=o{=+^}ciyt8|@e$Y}IREAyd_!2|CqTg=eu}yG z@sI9T;Tjix*%v)c{4G84|0j@8wX^Iig_JsPU|T%(J&KtJ>V zsAR+dcmyT5k&&G{!)VXN`oRS{n;3qd`BgAE9r?%AHy_Gf8>$&X$=>YD7M911?<{qX zkJ;IOfY$nHdy@kKk_+X%g3`T(v|jS;>`pz`?>fqMZ>Fvbx1W=8nvtuve&y`JBfvU~ zr+5pF!`$`TUVsx3^<)48&+XT92U0DS|^X6FwSa-8yviRkZ*@Wu|c*lX!m?8&$0~4T!DB0@)n}ey+ew}T1U>|fH3=W5I!=nfoNs~OkzTY7^x^G&h>M7ewZqmZ=EL0}3#ikWg+(wuoA{7hm|7eJz zNz78l-K81tP16rai+fvXtspOhN-%*RY3IzMX6~8k9oFlXWgICx9dp;`)?Toz`fxV@&m8< z{lzWJG_Y(N1nOox>yG^uDr}kDX_f`lMbtxfP`VD@l$HR*B(sDeE(+T831V-3d3$+% zDKzKnK_W(gLwAK{Saa2}zaV?1QmcuhDu$)#;*4gU(l&rgNXB^WcMuuTki*rt>|M)D zoI;l$FTWIUp}euuZjDidpVw6AS-3dal2TJJaVMGj#CROWr|;^?q>PAo2k^u-27t~v zCv10IL~E)o*|QgdM!GJTaT&|A?oW)m9qk2{=y*7qb@BIAlYgDIe)k(qVH@)#xx6%7 z@)l%aJwz5Joc84Q2jRp71d;=a@NkjSdMyN%L6OevML^(L0_msbef>ewImS=+DgrTk z4ON%Y$mYgcZ^44O*;ctP>_7=}=pslsu>~<-bw=C(jeQ-X`kUo^BS&JDHy%#L32Cj_ zXRzDCfCXKXxGSW9yOGMMOYqPKnU zTF6gDj47!7PoL%z?*{1eyc2IVF*RXX?mj1RS}++hZg_%b@6&PdO)VzvmkXxJ*O7H} z6I7XmJqwX3<>z%M@W|GD%(X|VOZ7A+=@~MxMt8zhDw`yz?V>H%C0&VY+ZZ>9AoDVZeO1c~z$r~!H zA`N_9p`X?z>jm!-leBjW1R13_i2(0&aEY2$l_+-n#powuRO;n2Fr#%jp{+3@`h$c< zcFMr;18Z`UN#spXv+3Ks_V_tSZ1!FY7H(tdAk!v}SkoL9RPYSD3O5w>A3%>7J+C-R zZfDmu=9<1w1CV8rCMEm{qyErCUaA3Q zRYYw_z!W7UDEK)8DF}la9`}8z*?N32-6c-Bwx^Jf#Muwc67sVW24 zJ4nab%>_EM8wPhL=MAN)xx1tozAl zmhXN;*-X%)s>(L=Q@vm$qmuScku>PV(W_x-6E?SFRjSk)A1xVqnml_92fbj0m};UC zcV}lRW-r*wY106|sshV`n#RN{)D9=!>XVH0vMh>od=9!1(U+sWF%#B|eeaKI9RpaW z8Ol_wAJX%j0h5fkvF)WMZ1}?#R(n-OT0CtwsL)|qk;*(!a)5a5ku2nCR9=E*iOZ`9 zy4>LHKt-BgHL@R9CBSG!v4wK zvjF8DORRva)@>nshE~VM@i2c$PKw?3nz(6-iVde;-S~~7R<5r2t$0U8k2_<5C0!$j zQg#lsRYtI#Q1YRs(-%(;F-K7oY~!m&zhuU4LL}>jbLC>B`tk8onRRcmIm{{0cpkD|o@Ixu#x9Wm5J)3oFkbfi62BX8IX1}VTe#{C(d@H|#gy5#Sa#t>sH@8v1h8XFgNGs?)tyF_S^ueJX_-1%+LR`1X@C zS3Oc)o)!8Z9!u9d!35YD^!aXtH;IMNzPp`NS|EcdaQw~<;z`lmkg zE|tQRF7!S!UCsbag%XlQZXmzAOSs= zIUjgY2jcN9`xA6mzG{m|Zw=3kZC4@XY=Bj%k8%D&iadvne$pYNfZI$^2BAB|-MnZW zU4U?*qE3`ZDx-bH})>wz~)a z_SWM!E=-BS#wdrfh;EfPNOS*9!;*+wp-zDthj<>P0a2n?$xfe;YmX~5a;(mNV5nKx zYR86%WtAPsOMIg&*o9uUfD!v&4(mpS6P`bFohPP<&^fZzfA|SvVzPQgbtwwM>IO>Z z75ejU$1_SB1tn!Y-9tajZ~F=Fa~{cnj%Y|$;%z6fJV1XC0080f)Pj|87j142q6`i>#)BCIi+x&jAH9|H#iMvS~?w;&E`y zoarJ)+5HWmZ{&OqlzbdQU=SE3GKmnQq zI{h6f$C@}Mbqf#JDsJyi&7M0O2ORXtEB`#cZ;#AcB zkao0`&|iH8XKvZ_RH|VaK@tAGKMq9x{sdd%p-o`!cJzmd&hb86N!KKxp($2G?#(#BJn5%hF0(^`= z2qRg5?82({w-HyjbffI>eqUXavp&|D8(I6zMOfM}0;h%*D_Dr@+%TaWpIEQX3*$vQ z8_)wkNMDi{rW`L+`yN^J*Gt(l7PExu3_hrntgbW0s}7m~1K=(mFymoU87#{|t*fJ?w8&>Uh zcS$Ny$HNRbT!UCFldTSp2*;%EoW+yhJD8<3FUt8@XSBeJM2dSEz+5}BWmBvdYK(OA zlm`nDDsjKED{$v*jl(&)H7-+*#jWI)W|_X)!em1qpjS_CBbAiyMt;tx*+0P%*m&v< zxV9rlslu8#cS!of#^1O$(ds8aviMFiT`6W+FzMHW{YS+SieJ^?TQb%NT&pasw^kbc znd`=%(bebvrNx3#7vq@vAX-G`4|>cY0svIXopH02{v;GZ{wJM#psz4!m8(IZu<)9D zqR~U7@cz-6H{724_*}-DWwE8Sk+dYBb*O-=c z+wdchFcm6$$^Z0_qGnv0P`)h1=D$_eg8!2-|7Y;o*c)4ax!Me0*EVcioh{wI#!qcb z1&xhOotXMrlo7P6{+C8m;E#4*=8(2y!r0d<6 zKi$d2X;O*zS(&Xiz_?|`ympxITf|&M%^WHp=694g6W@k+BL_T1JtSYX0OZ}o%?Pzu zJ{%P8A$uq?4F!NWGtq>_GLK3*c6dIcGH)??L`9Av&0k$A*14ED9!e9z_SZd3OH6ER zg%5^)3^gw;4DFw(RC;~r`bPJOR}H}?2n60=g4ESUTud$bkBLPyI#4#Ye{5x3@Yw<* z;P5Up>Yn(QdP#momCf=kOzZYzg9E330=67WOPbCMm2-T1%8{=or9L8+HGL{%83lri zODB;Y|LS`@mn#Wmez7t6-x`a2{}U9hE|xY7|BVcFCqoAZQzsEi=dYHB z(bqG3J5?teVSBqTj{aiqe<9}}CEc$HdsJSMp#I;4(EXRy_k|Y8X#5hwkqAaIGKARF zX?$|UO{>3-FU;IlFi80O^t+WMNw4So2nsg}^T1`-Ox&C%Gn_AZ-49Nir=2oYX6 z`uVke@L5PVh)YsvAgFMZfKi{DuSgWnlAaag{RN6t6oLm6{4)H~4xg#Xfcq-e@ALk& z@UP4;uCe(Yjg4jaJZ4pu*+*?4#+XCi%sTrqaT*jNY7|WQ!oR;S8nt)cI27W$Sz!94 z01zoTW`C*P3E?1@6thPe(QpIue$A54gp#C7pmfwRj}GxIw$!!qQetn`nvuwIvMBQ; zfF8K-D~O4aJKmLbNRN1?AZsWY&rp?iy`LP^3KT0UcGNy=Z@7qVM(#5u#Du#w>a&Bs z@f#zU{wk&5n!YF%D11S9*CyaI8%^oX=vq$Ei9cL1&kvv9|8vZD;Mhs1&slm`$A%ED zvz6SQ8aty~`IYp2Xd~G$z%Jf4zwVPKkCtqObrnc2gHKj^jg&-NH|xdNK_;+2d4ZXw zN9j)`jcp7y65&6P@}LsD_OLSi(#GW#hC*qF5KpmeXuQDNS%ZYpuW<;JI<>P6ln!p@ z>KPAM>8^cX|2!n@tV=P)f2Euv?!}UM`^RJ~nTT@W>KC2{{}xXS{}WH{|3najkiEUj z7l;fUWDPCtzQ$?(f)6RvzW~Tqan$bXibe%dv}**BqY!d4J?`1iX`-iy8nPo$s4^mQ z5+@=3xuZAl#KoDF*%>bJ4UrEB2EE8m7sQn!r7Z-ggig`?yy`p~3;&NFukc$`_>?}a z?LMo2LV^n>m!fv^HKKRrDn|2|zk?~S6i|xOHt%K(*TGWkq3{~|9+(G3M-L=;U-YRa zp{kIXZ8P!koE;BN2A;nBx!={yg4v=-xGOMC#~MA07zfR)yZtSF_2W^pDLcXg->*WD zY7Sz5%<_k+lbS^`y)=vX|KaN!gEMQob|(`%nP6huwr$%^?%0^vwr$(CZQD*Jc5?E( zb-q9E`OfoWSJ$rUs$ILfSFg3Mb*-!Ozgaz^%7ZkX@=3km0G;?+e?FQT_l5A9vKr<> z_CoemDo@6YIyl57l*gnJ^7+8xLW5oEGzjLv2P8vj*Q%O1^KOfrsC6eHvk{+$BMLGu z%goP8UY?J7Lj=@jcI$4{m2Sw?1E%_0C7M$lj}w{E#hM4%3QX|;tH6>RJf-TI_1A0w z@KcTEFx(@uitbo?UMMqUaSgt=n`Bu*;$4@cbg9JIS})3#2T;B7S

Z?HZkSa`=MM?n)?|XcM)@e1qmzJ$_4K^?-``~Oi&38`2}sjmP?kK z$yT)K(UU3fJID@~3R;)fU%k%9*4f>oq`y>#t90$(y*sZTzWcW$H=Xv|%^u^?2*n)Csx;35O0v7Nab-REgxDZNf5`cI69k$` zx(&pP6zVxlK5Apn5hAhui}b)(IwZD}D?&)_{_yTL7QgTxL|_X!o@A`)P#!%t9al+# zLD(Rr+?HHJEOl545~m1)cwawqY>cf~9hu-L`crI^5p~-9Mgp9{U5V&dJSwolnl_CM zwAMM1Tl$D@>v?LN2PLe0IZrQL1M zcA%i@Lc)URretFJhtw7IaZXYC6#8slg|*HfUF2Z5{3R_tw)YQ94=dprT`SFAvHB+7 z)-Hd1yE8LB1S+4H7iy$5XruPxq6pc_V)+VO{seA8^`o5{T5s<8bJ`>I3&m%R4cm1S z`hoNk%_=KU2;+#$Y!x7L%|;!Nxbu~TKw?zSP(?H0_b8Qqj4EPrb@~IE`~^#~C%D9k zvJ=ERh`xLgUwvusQbo6S=I5T+?lITYsVyeCCwT9R>DwQa&$e(PxF<}RpLD9Vm2vV# zI#M%ksVNFG1U?;QR{Kx2sf>@y$7sop6SOnBC4sv8S0-`gEt0eHJ{`QSW(_06Uwg*~ zIw}1dZ9c=K$a$N?;j`s3>)AqC$`ld?bOs^^stmYmsWA$XEVhUtGlx&OyziN1~2 z)s5fD(d@gq7htIGX!GCxKT=8aAOHW&DAP=$MpZ)SpeEZhk83}K) z0(Uv)+&pE?|4)D2PX4r6gOGHDY}$8FSg$3eDb*nEVmkFQ#lFpcH~IPeatiH3nPTkP z*xDN7l}r2GM9jwSsl=*!547nRPCS0pb;uE#myTqV+=se>bU=#e)f2}wCp%f-cIrh`FHA$2`monVy?qvJ~o2B6I7IE28bCY4=c#^){*essLG zXUH50W&SWmi{RIG9G^p;PohSPtC}djjXSoC)kyA8`o+L}SjE{i?%;Vh=h;QC{s`T7 zLmmHCr8F}#^O8_~lR)^clv$mMe`e*{MW#Sxd`rDckCnFBo9sC*vw2)dA9Q3lUi*Fy zgDsLt`xt|7G=O6+ms=`_FpD4}37uvelFLc^?snyNUNxbdSj2+Mpv<67NR{(mdtSDNJ3gSD@>gX_7S5 zCD)JP5Hnv!llc-9fwG=4@?=%qu~(4j>YXtgz%gZ#+A9i^H!_R!MxWlFsH(ClP3dU} za&`m(cM0xebj&S170&KLU%39I+XVWOJ_1XpF^ip}3|y()Fn5P@$pP5rvtiEK6w&+w z7uqIxZUj$#qN|<_LFhE@@SAdBy8)xTu>>`xC>VYU@d}E)^sb9k0}YKr=B8-5M?3}d z7&LqQWQ`a&=ihhANxe3^YT>yj&72x#X4NXRTc#+sk;K z=VUp#I(YIRO`g7#;5))p=y=MQ54JWeS(A^$qt>Y#unGRT$0BG=rI(tr>YqSxNm+-x z6n;-y8B>#FnhZX#mhVOT30baJ{47E^j-I6EOp;am;FvTlYRR2_?CjCWY+ypoUD-2S zqnFH6FS+q$H$^7>>(nd^WE+?Zn#@HU3#t|&=JnEDgIU+;CgS+krs+Y8vMo6U zHVkPoReZ-Di3z!xdBu#aW1f{8sC)etjN90`2|Y@{2=Os`(XLL9+ z1$_PE$GgTQrVx`^sx=Y(_y-SvquMF5<`9C=vM52+e+-r=g?D z+E|97MyoaK5M^n1(mnWeBpgtMs8fXOu4Q$89C5q4@YY0H{N47VANA1}M2e zspor6LdndC=kEvxs3YrPGbc;`q}|zeg`f;t3-8na)dGdZ9&d(n{|%mNaHaKJOA~@8 zgP?nkzV-=ULb)L3r`p)vj4<702a5h~Y%byo4)lh?rtu1YXYOY+qyTwzs!59I zL}XLe=q$e<+Wm7tvB$n88#a9LzBkgHhfT<&i#%e*y|}@I z!N~_)vodngB7%CI2pJT*{GX|cI5y>ZBN)}mezK~fFv@$*L`84rb0)V=PvQ2KN}3lTpT@$>a=CP?kcC0S_^PZ#Vd9#CF4 zP&`6{Y!hd^qmL!zr#F~FB0yag-V;qrmW9Jnq~-l>Sg$b%%TpO}{Q+*Pd-@n2suVh_ zSYP->P@# z&gQ^f{?}m(u5B9xqo63pUvDsJDQJi5B~ak+J{tX8$oL!_{Dh zL@=XFzWb+83H3wPbTic+osVp&~UoW3SqK0#P6+BKbOzK65tz)-@AW#g}Ew+pE3@ zVbdJkJ}EM@-Ghxp_4a)|asEk* z5)mMI&EK~BI^aaTMRl)oPJRH^Ld{;1FC&#pS`gh;l3Y;DF*`pR%OSz8U@B@zJxPNX zwyP_&8GsQ7^eYyUO3FEE|9~I~X8;{WTN=DJW0$2OH=3-!KZG=X6TH?>URr(A0l@+d zj^B9G-ACel;yYGZc}G`w9sR$Mo{tzE7&%XKuW$|u7DM<6_z}L>I{o`(=!*1 z{5?1p3F^aBONr6Ws!6@G?XRxJxXt_6b}2%Bp=0Iv5ngnpU^P+?(?O0hKwAK z*|wAisG&8&Td1XY+6qI~-5&+4DE2p|Dj8@do;!40o)F)QuoeUY;*I&QZ0*4?u)$s`VTkNl1WG`}g@J_i zjjmv4L%g&>@U9_|l>8^CN}`@4<D2aMN&?XXD-HNnsVM`irjv$ z^YVNUx3r1{-o6waQfDp=OG^P+vd;qEvd{UUYc;gF0UwaeacXkw32He^qyoYHjZeFS zo(#C9#&NEdFRcFrj7Q{CJgbmDejNS!H%aF6?;|KJQn_*Ps3pkq9yE~G{0wIS*mo0XIEYH zzIiJ>rbmD;sGXt#jlx7AXSGGcjty)5z5lTGp|M#5DCl0q0|~pNQ%1dP!-1>_7^BA~ zwu+uumJmTCcd)r|Hc)uWm7S!+Dw4;E|5+bwPb4i17Ued>NklnnsG+A{T-&}0=sLM- zY;sA9v@YH>b9#c$Vg{j@+>UULBX=jtu~N^%Y#BB5)pB|$?0Mf7msMD<7eACoP1(XY zPO^h5Brvhn$%(0JSo3KFwEPV&dz8(P41o=mo7G~A*P6wLJ@-#|_A z7>k~4&lbqyP1!la!qmhFBfIfT?nIHQ0j2WlohXk^sZ`?8-vwEwV0~uu{RDE^0yfl$ znua{^`VTZ)-h#ch_6^e2{VPaE@o&55|3dx$z_b6gbqduXJ(Lz(zq&ZbJ6qA4Ac4RT zhJO4KBLN!t;h(eW(?cZJw^swf8lP@tWMZ8GD)zg)siA3!2EJYI(j>WI$=pK!mo!Ry z?q&YkTIbTTr<>=}+N8C_EAR0XQL2&O{nNAXb?33iwo8{M``rUHJgnk z8KgZzZLFf|(O6oeugsm<;5m~4N$2Jm5#dph*@TgXC2_k&d%TG0LPY=Fw)=gf(hy9QmY*D6jCAiq44 zo-k2C+?3*+Wu7xm1w*LEAl`Vsq(sYPUMw|MiXrW)92>rVOAse5Pmx^OSi{y%EwPAE zx|csvE{U3c{vA>@;>xcjdCW15pE31F3aoIBsz@OQRvi%_MMfgar2j3Ob`9e@gLQk# zlzznEHgr|Ols%f*a+B-0klD`czi@RWGPPpR1tE@GB|nwe`td1OwG#OjGlTH zfT#^r?%3Ocp^U0F8Kekck6-Vg2gWs|sD_DTJ%2TR<5H3a$}B4ZYpP=p)oAoHxr8I! z1SYJ~v-iP&mNm{ra7!KP^KVpkER>-HFvq*>eG4J#kz1|eu;=~u2|>}TE_5nv2=d!0 z3P~?@blSo^uumuEt{lBsGcx{_IXPO8s01+7DP^yt&>k;<5(NRrF|To2h7hTWBFQ_A z+;?Q$o5L|LlIB>PH(4j)j3`JIb1xA_C@HRFnPnlg{zGO|-RO7Xn}!*2U=Z2V?{5Al z9+iL+n^_T~6Uu{law`R&fFadSVi}da8G>|>D<{(#vi{OU;}1ZnfXy8=etC7)Ae<2S zAlI`&=HkNiHhT0|tQztSLNsRR6v8bmf&$6CI|7b8V4kyJ{=pG#h{1sVeC28&Ho%Fh zwo_FIS}ST-2OF6jNQ$(pjrq)P)@sie#tigN1zSclxJLb-O9V|trp^G8<1rpsj8@+$ z2y27iiM>H8kfd%AMlK|9C>Lkvfs9iSk>k2}tCFlqF~Z_>-uWVQDd$5{3sM%2$du9; z*ukNSo}~@w@DPF)_vS^VaZ)7Mk&8ijX2hNhKom$#PM%bzSA-s$ z0O!broj`!Nuk)Qcp3(>dL|5om#XMx2RUSDMDY9#1|+~fxwP}1I4iYy4j$CGx3jD&eKhf%z`Jn z7mD!y6`nVq%&Q#5yqG`|+e~1$Zkgu!O(~~pWSDTw2^va3u!DOMVRQ8ycq)sk&H%vb z;$a`3gp74~I@swI!ILOkzVK3G&SdTcVe~RzN<+z`u(BY=yuwez{#T3a_83)8>2!X?`^02zVjqx-fN+tW`zCqH^XG>#Ies$qxa!n4*FF0m zxgJlPPYl*q4ylX;DVu3G*I6T&JyWvs`A(*u0+62=+ylt2!u)6LJ=Qe1rA$OWcNCmH zLu7PwMDY#rYQA1!!ONNcz~I^uMvi6N&Lo4dD&HF?1Su5}COTZ-jwR)-zLq=6@bN}X zSP(-MY`TOJ@1O`bLPphMMSWm+YL{Ger>cA$KT~)DuTl+H)!2Lf`c+lZ0ipxd>KfKn zIv;;eEmz(_(nwW24a+>v{K}$)A?=tp+?>zAmfL{}@0r|1>iFQfJ5C*6dKdijK=j16 zQpl4gl93ttF5@d<9e2LoZ~cqkH)aFMgt(el_)#OG4R4Hnqm(@D*Uj>2ZuUCy)o-yy z_J|&S-@o5#2IMcL(}qWF3EL<4n(`cygenA)G%Ssi7k4w)LafelpV5FvS9uJES+(Ml z?rzZ={vYrB#mB-Hd#ID{KS5dKl-|Wh_~v+Lvq3|<@w^MD-RA{q!$gkUUNIvAaex5y z)jIGW{#U=#UWyku7FIAB=TES8>L%Y9*h2N`#Gghie+a?>$CRNth?ORq)!Tde24f5K zKh>cz5oLC;ry*tHIEQEL>8L=zsjG7+(~LUN5K1pT`_Z-4Z}k^m%&H%g3*^e(FDCC{ zBh~eqx%bY?qqu_2qa+9A+oS&yFw^3nLRsN#?FcZvt?*dZhRC_a%Jd{qou(p5AG_Q6 ziOJMu8D~kJ7xEkG(69$Dl3t1J592=Olom%;13uZvYDda08YwzqFlND-;YodmA!SL) z!AOSI=(uCnG#Yo&BgrH(muUemmhQW7?}IHfxI~T`44wuLGFOMdKreQO!a=Z-LkH{T z@h;`A_l2Pp>Xg#`Vo@-?WJn-0((RR4uKM6P2*^-qprHgQhMzSd32@ho>%fFMbp9Y$ zx-#!r8gEu;VZN(fDbP7he+Nu7^o3<+pT!<<>m;m z=FC$N)wx)asxb_KLs}Z^;x*hQM}wQGr((&=%+=#jW^j|Gjn$(qqXwt-o-|>kL!?=T zh0*?m<^>S*F}kPiq@)Cp+^fnKi2)%<-Tw4K3oHwmI-}h}Kc^+%1P!D8aWp!hB@-ZT zybHrRdeYlYulEj>Bk zEIi|PU0eGg&~kWQ{q)gw%~bFT0`Q%k5S|tt!JIZXVXX=>er!7R^w>zeQ%M-(C|eOQG>5i|}i3}X#?aqAg~b1t{-fqwKd(&CyA zmyy)et*E}+q_lEqgbClewiJ=u@bFX}LKe)5o26K9fS;R`!er~a?lUCKf60`4Zq7{2q$L?k?IrAdcDu+ z4A0QJBUiGx&$TBASI2ASM_Wj{?fjv=CORO3GZz;1X*AYY`anM zI`M6C%8OUFSc$tKjiFJ|V74Yj-lK&Epi7F^Gp*rLeDTokfW#o6sl33W^~4V|edbS1 zhx%1PTdnI!C96iYqSA=qu6;p&Dd%)Skjjw0fyl>3k@O?I@x5|>2_7G#_Yc2*1>=^# z|H43bJDx$SS2!vkaMG!;VRGMbY{eJhT%FR{(a+RXDbd4OT?DRoE(`NhiVI6MsUCsT z1gc^~Nv>i;cIm2~_SYOfFpkUvV)(iINXEep;i4>&8@N#|h+_;DgzLqh3I#lzhn>cN zjm;m6U{+JXR2Mi)=~WxM&t9~WShlyA$Pnu+VIW2#;0)4J*C!{1W|y1TP{Q;!tldR< zI7aoH&cMm*apW}~BabBT;`fQ1-9q|!?6nTzmhiIo6fGQlcP{pu)kJh- zUK&Ei9lArSO6ep_SN$Lt_01|Y#@Ksznl@f<+%ku1F|k#Gcwa`(^M<2%M3FAZVb99?Ez4d9O)rqM< zCbYsdZlSo{X#nKqiRA$}XG}1Tw@)D|jGKo1ITqmvE4;ovYH{NAk{h8*Ysh@=nZFiF zmDF`@4do#UDKKM*@wDbwoO@tPx4aExhPF_dvlR&dB5>)W=wG6Pil zq{eBzw%Ov!?D+%8&(uK`m7JV7pqNp-krMd>ECQypq&?p#_3wy){eW{(2q}ij{6bfmyE+-ZO z)G4OtI;ga9;EVyKF6v3kO1RdQV+!*>tV-ditH-=;`n|2T zu(vYR*BJSBsjzFl1Oy#DpL=|pfEY4NM;y5Yly__T*Eg^3Mb_()pHwn)mAsh!7Yz-Z zY`hBLDXS4F^{>x=oOphq|LMo;G!C(b2hS9A6lJqb+e$2af}7C>zW2p{m18@Bdd>iL zoEE$nFUnaz_6p${cMO|;(c1f9nm5G5R;p)m4dcC1?1YD=2Mi&20=4{nu>AV#R^d%A zsmm_RlT#`;g~an9mo#O1dYV)2{mgUWEqb*a@^Ok;ckj;uqy{%*YB^({d{^V)P9VvP zC^qbK&lq~}TWm^RF8d4zbo~bJuw zFV!!}b^4BlJ0>5S3Q>;u*BLC&G6Fa5V|~w&bRZ*-YU>df6%qAvK?%Qf+#=M-+JqLw&w*l4{v7XTstY4j z26z69U#SVzSbY9HBXyD;%P$#vVU7G*Yb-*fy)Qpx?;ed;-P24>-L6U+OAC9Jj63kg zlY`G2+5tg1szc#*9ga3%f9H9~!(^QjECetX-PlacTR+^g8L<#VRovPGvsT)ln3lr= zm5WO@!NDuw+d4MY;K4WJg3B|Sp|WdumpFJO>I2tz$72s4^uXljWseYSAd+vGfjutO z-x~Qlct+BnlI+Iun)fOklxPH?30i&j9R$6g5^f&(x7bIom|FLKq9CUE);w2G>}vye zxWvEaXhx8|~2j)({Rq>0J9}lzdE`yhQ(l$z! z;x%d%_u?^4vlES_>JaIjJBN|N8z5}@l1#PG_@{mh`oWXQOI41_kPG}R_pV+jd^PU) zEor^SHo`VMul*80-K$0mSk|FiI+tHdWt-hzt~S>6!2-!R&rdL_^gGGUzkPe zEZkUKU=EY(5Ex)zeTA4-{Bkbn!Gm?nuaI4jLE%X;zMZ7bwn4FXz(?az;9(Uv;38U6 zi)}rA3xAcD2&6BY<~Pj9Q1~4Dyjs&!$)hyHiiTI@%qXd~+>> zW}$_puSSJ^uWv$jtWakn}}@eX6_LGz|7M#$!3yjY ztS{>HmQ%-8u0@|ig{kzD&CNK~-dIK5e{;@uWOs8$r>J7^c2P~Pwx%QVX0e8~oXK0J zM4HCNK?%t6?v~#;eP#t@tM$@SXRt;(b&kU7uDzlzUuu;+LQ5g%=FqpJPGrX8HJ8CS zITK|(fjhs3@CR}H4@)EjL@J zV_HPexOQ!@k&kvsQG)n;7lZaUh>{87l4NS_=Y-O9Ul3CaKG8iy+xD=QXZSr57a-hb z7jz3Ts-NVsMI783OPEdlE|e&a2;l^h@e>oYMh5@=Lte-9A+20|?!9>Djl~{XkAo>0p9`n&nfWGdGAfT-mSYW z1cvG>GT9dRJdcm7M_AG9JX5AqTCdJ6MRqR3p?+FvMxp(oB-6MZ`lRzSAj%N(1#8@_ zDnIIo9Rtv12(Eo}k_#FILhaZQ`yRD^Vn5tm+IK@hZO>s=t5`@p1#k?Umz2y*R64CF zGM-v&*k}zZ%Xm<_?1=g~<*&3KAy;_^QfccIp~CS7NW24Tn|mSDxb%pvvi}S}(~`2# z3I|kD@||l@lAW06K2%*gHd4x9YKeXWpwU%!ozYcJ+KJeX!s6b94j!Qyy7>S!wb?{qaMa`rpbU1phn0EpF}L zsBdZc|Im#iRiQmJjZwb5#n;`_O{$Zu$I zMXqbfu0yVmt!!Y`Fzl}QV7HUSOPib#da4i@vM$0u2FEYytsvrbR#ui9lrMkZ(AVVJ zMVl^Wi_fSRsEXLA_#rdaG%r(@UCw#o7*yBN)%22b)VSNyng6Lxk|2;XK3Qb=C_<`F zN##8MLHz-s%&O6JE~@P1=iHpj8go@4sC7*AWe99tuf$f7?2~wC&RA^UjB*2`K!%$y zSDzMd7}!vvN|#wDuP%%nuGk8&>N)7eRxtqdMXHD1W%hP7tYW{W>^DJp`3WS>3}i+$ z_li?4AlEj`r=!SPiIc+NNUZ9NCrMv&G0BdQHBO&S7d48aB)LfGi@D%5CC1%)1hVcJ zB~=yNC}LBn(K?cHkPmAX$5^M7JSnNkcc!X!0kD&^F$cJmRP(SJ`9b7}b)o$rj=BZ- zC;BX3IG94%Qz&(V$)7O~v|!=jd-yU1(6wd1u;*$z4DDe6+BFLhz>+8?59?d2Ngxck zm92yR!jk@MP@>>9FtAY2L+Z|MaSp{MnL-;fm}W3~fg!9TRr3;S@ysLf@#<)keHDRO zsJI1tP`g3PNL`2(8hK3!4;r|E-ZQbU0e-9u{(@du`4wjGj|A!QB&9w~?OI1r}M? zw)6tvsknfPfmNijZ;3VZX&HM6=|&W zy6GIe3a?_(pRxdUc==do9?C&v7+6cgIoL4)Ka^bOG9`l;S|QmVzjv%)3^PDi@=-cp z=!R0bU<@_;#*D}e1m@0!%k=VPtyRAkWYW(VFl|eu0LteWH7eDB%P|uF7BQ-|D4`n; z)UpuY1)*s32UwW756>!OoAq#5GAtfrjo*^7YUv^(eiySE?!TQzKxzqXE@jM_bq3Zq zg#1orE*Zd5ZWEpDXW9$=NzuadNSO*NW)ZJ@IDuU`w}j_FRE4-QS*rD4mPVQPH(jGg z+-Ye?3%G%=DT5U1b+TnNHHv(nz-S?3!M4hXtEB@J4WK%%p zkv=Bb`1DHmgUdYo>3kwB(T>Ba#DKv%cLp2h4r8v}p=Np}wL!&PB5J-w4V4REM{kMD z${oSuAw9?*yo3?tNp~X5WF@B^P<6L0HtIW0H7^`R8~9zAXgREH`6H{ntGu$aQ;oNq zig;pB^@KMHNoJcEb0f1fz+!M6sy?hQjof-QoxJgBM`!k^T~cykcmi^s_@1B9 z)t1)Y-ZsV9iA&FDrVoF=L7U#4&inXk{3+Xm9A|R<=ErgxPW~Fq zqu-~x0dIBlR+5_}`IK^*5l3f5$&K@l?J{)_d_*459pvsF*e*#+2guls(cid4!N%DG zl3(2`az#5!^@HNRe3O4(_5nc+){q?ENQG2|uKW0U0$aJ5SQ6hg>G4OyN6os76y%u8qNNHi;}XnRNwpsfn^!6Qt(-4tE`uxaDZ`hQp#aFX373|F?vjEiSEkV>K)cTBG+UL#wDj0_ zM9$H&-86zP=9=5_Q7d3onkqKNr4PAlF<>U^^yYAAEso|Ak~p$3NNZ$~4&kE9Nj^As zQPoo!m*uZ;z1~;#g(?zFECJ$O2@EBy<;F)fnQxOKvH`MojG5T?7thbe%F@JyN^k1K zn3H*%Ymoim)ePf)xhl2%$T)vq3P=4ty%NK)@}po&7Q^~o3l))Zm4<75Y!fFihsXJc z9?vecovF^nYfJVg#W~R3T1*PK{+^YFgb*7}Up2U#)oNyzkfJ#$)PkFxrq_{Ai?0zk zWnjq_ixF~Hs7YS9Y6H&8&k0#2cAj~!Vv4{wCM zi2f1FjQf+F@=BOB)pD|T41a4AEz+8hnH<#_PT#H|Vwm7iQ0-Tw()WMN za0eI-{B2G{sZ7+L+^k@BA)G;mOFWE$O+2nS|DzPSGZ)ede(9%+8kqu4W^wTn!yZPN z7u!Qu0u}K5(0euRZ$7=kn9DZ+llruq5A_l) zOK~wof7_^8Yeh@Qd*=P!gM)lh`Z@7^M?k8Z?t$$vMAuBG>4p56Dt!R$p{)y>QG}it zGG;Ei```7ewXrbGo6Z=!AJNQ!GP8l13m7|FIQTFZTpIg#kpZkl1wj)s1eySXjAAWy zfl;;@{QQ;Qnb$@LY8_Z&7 z6+d98F?z2Zo)sS)z$YoL(zzF>Ey8u#S_%n7)XUX1Pu(>e8gEUU1S;J=EH(#`cWi1+ zoL$5TN+?#NM8=4E7HOk)bf5MXvEo%he5QcB%_5YQ$cu_j)Pd^@5hi}d%nG}x9xXtD-JMQxr;KkC=r_dS-t`lf zF&CS?Lk~>U^!)Y0LZqNVJq+*_#F7W~!UkvZfQhzvW`q;^X&iv~ zEDDGIQ&(S;#Hb(Ej4j+#D#sDS_uHehlY0kZsQpktc?;O z22W1b%wNcdfNza<1M2{*mAkM<{}@(w`VuQ<^lG|iYSuWBD#lYK9+jsdA+&#;Y@=zXLVr840Nq_t5))#7}2s9pK* zg42zd{EY|#sIVMDhg9>t6_Y#O>JoG<{GO&OzTa;iA9&&^6=5MT21f6$7o@nS=w;R) znkgu*7Y{UNPu7B9&B&~q+N@@+%&cO0N`TZ-qQ|@f@e0g2BI+9xO$}NzMOzEbSSJ@v z1uNp(S z-dioXc$5YyA6-My@gW~1GH($Q?;GCHfk{ej-{Q^{iTFs1^Sa67RNd5y{cjX1tG+$& zbGrUte{U1{^Z_qpzW$-V!pJz$dQZrL5i(1MKU`%^= z^)i;xua4w)evDBrFVm)Id5SbXMx2u7M5Df<2L4B`wy4-Y+Wec#b^QJO|J9xF{x#M8 zuLUer`%ZL^m3gy?U&dI+`kgNZ+?bl3H%8)&k84*-=aMfADh&@$xr&IS|4{3$v&K3q zZTn&f{N(#L6<-BZYNs4 zB*Kl*@_IhGXI^_8zfXT^XNmjJ@5E~H*wFf<&er?p7suz85)$-Hqz@C zGMFg1NKs;otNViu)r-u{SOLcqwqc7$poPvm(-^ag1m71}HL#cj5t4Hw(W?*fi4GSH z9962NZ>p^ECPqVc$N}phy>N8rQsWWm%%rc5B4XLATFEtffX&TM2%|8S2Lh_q; zCytXua84HBnSybW-}(j z3Zwv4CaK)jC!{oUvdsFRXK&Sx@t)yGm(h65$!WZ!-jL52no}NX6=E<=H!aZ74h_&> zZ+~c@k!@}Cs84l{u+)%kg4fq~pOeTK3S4)gX~FKJw4t9ba!Ai{_gkKQYQvafZIyKq zX|r4xgC(l%JgmW!tvR&yNt$6uME({M`uNIi7HFiPEQo_UMRkl~12&4c& z^se;dbZWKu7>dLMg`IZq%@b@ME?|@{&xEIZEU(omKNUY? z`JszxNghuO-VA;MrZKEC0|Gi0tz3c#M?aO?WGLy64LkG4T%|PBIt_?bl{C=L@9e;A zia!35TZI7<`R8hr06xF62*rNH5T3N0v^acg+;ENvrLYo|B4!c^eILcn#+lxDZR!%l zjL6!6h9zo)<5GrSPth7+R(rLAW?HF4uu$glo?w1U-y}CR@%v+wSAlsgIXn>e%bc{FE;j@R0AoNIWf#*@BSngZ)HmNqkB z)cs3yN%_PT4f*K+Y1wFl)be=1iq+bb1G-}b|72|gJ|lMt`tf~0Jk}zMbS0+M-Mq}R z>Bv}-W6J%}j#dIz`Z0}zD(DGKn`R;E8A`)$a6qDfr(c@iHKZcCVY_nJEDpcUddGH* z*ct2$&)RelhmV}@jGXY>3Y~vp;b*l9M+hO}&x`e~q*heO8GVkvvJTwyxFetJC8VnhjR`5*+qHEDUNp16g`~$TbdliLLd}AFf}U+Oda1JXwwseRFbj?DN96;VSX~z?JxJSuA^BF}262%Z0)nv<6teKK`F zfm9^HsblS~?Xrb1_~^=5=PD!QH$Y1hD_&qe1HTQnese8N#&C(|Q)CvtAu6{{0Q%ut8ESVdn&& z4y%nsCs!$(#9d{iVjXDR##3UyoMNeY@_W^%qyuZ^K3Oa4(^!tDXOUS?b2P)yRtJ8j zSX}@qGBj+gKf;|6Kb&rq`!}S*cSu-3&S>=pM$eEB{K>PP~I}N|uGE|`3U#{Q6v^kO4nIsaq zfPld}c|4tVPI4!=!ETCNW+LjcbmEoxm0RZ%ieV0`(nVlWKClZW5^>f&h79-~CF(%+ zv|KL(^xQ7$#a}&BSGr9zf{xJ(cCfq>UR*>^-Ou_pmknCt6Y--~!duL{k2D{yLMl__ z!KeMRRg&EsD2s|cmy?xgK&XcGIKeos`&UEVhBTw;mqy|8DlP1M7PYS2z{YmTJ;n!h znPe(Qu?c7+xZz!Tm1AnE8|;&tf7fW$2dArX7ck1Jd(S1+91YB8bjISRZ`UL*?vb{b zMp*!Xq7VaLc0Ogqj5qmop8NREQ{9_iC$;tviZlubGLy1jLlIFBxAymMr@SDLAcx+) z5YRkl$bW**X)W0JzWNcLx9>fTqJj00ipY6Ua?mUlsgQrVVgpmaheE;RgA5U_+WsPh z9+X|PU4zFyNxZ2?Q+V`Mo{xH~(m}OMRZa<&$nCl7o4x`^^|V4?aPz8#KwFm=8T6_} z8=P_4$_rD2a%7}}HT6VQ>ZGKW=QF7zI-2=6oBNZR$HVn|gq`>l$HZ`48lkM7%R$>MS& zghR`WZ9Xrd_6FaDedH6_aKVJhYev*2)UQ>!CRH3PQ_d9nXlO;c z9PeqiKD@aGz^|mvD-tV<{BjfA;)B+76!*+`$CZOJ=#)}>{?!9fAg(Xngbh||n=q*C zU0mGP`NxHn$uY#@)gN<0xr)%Ue80U{-`^FX1~Q@^>WbLraiB|c#4v$5HX)0z!oA#jOXPyWg! z8EC}SBmG7j3T&zCenPLYA{kN(3l62pu}91KOWZl? zg~>T4gQ%1y3AYa^J|>ba$7F5KlVx}_&*~me*q-SYLBCXZFU=U8mHQD4K!?;B61NoX z?VS41SS&jHyhmB~+bC=w0a06V``ZXCkC~}oM9pM{$hU~-s_elYPmT1L!%B`?*<+?( zFQ@TP%y+QL`_&Y0A3679pe5~iL=z)$b)k!oSbJRyw+K};SGAvvE=|<~*aiwJc?uE@2?7a1i9|3=^N%*9smt3ZIhjY>gIsr{Q2rX(NovZ7I1n^V{ z#~(1ze-%`C>fM`^hCV**9BA-04lNuu&3=reevNOMwmX(A{yh`^c8%0mjAKMj{Th05 zXrM(zILwyL-Pcdw^(=gj(ZLVMA95zlzmLa^skb8tQq%8SV&4vp?S>L3+P4^tp`$xA zr38jBw0ItR`VbO5vB1`<3d})}aorkIU1z3*ifYN&Lpp)}|}QJS60th_v-EEkAM zyOREuj!Ou|pVeZEWg;$Hf!x;xAmFu7gB^UR$=L0BuZ~thLC@#moJ(@@wejR|`t_K@ zuQ{XmpAWz%o&~2dk!SIGR$EmpZY)@+r^gvX26%)y>1u2bt~JUPTQzQu&_tB)|{19)&n$m5Fhw0A-8S1^%XpAD%`#a z_ModVxsM|x!m3N1vRt_XEL`O-+J3cMsM1l*dbjT&S0c@}Xxl3I&AeMNT97G3c6%3C zbrZS?2EAKcEq@@Pw?r%eh0YM6z0>&Qe#n+e9hEHK?fzig3v5S#O2IxVLu;a>~c~ZfHVbgLox%_tg)bsC8Rl35P=Jhl+Y=w6zb$ z;*uO%i^U z^mp_QggBILLF$AyjPD41Z0SFdbDj&z&xjq~X|OoM7bCuBfma1CEd!4RKGqPR)K)e}+7^JfFUI_fy63cMyq#&)Z*#w18{S zhC@f9U5k#2S2`d$-)cEoH-eAz{2Qh>YF1Xa)E$rWd52N-@{#lrw3lRqr)z?BGThgO z-Mn>X=RPHQ)#9h{3ciF)<>s{uf_&XdKb&kC!a373l2OCu&y8&n#P%$7YwAVJ_lD-G zX7tgMEV8}dY^mz`R6_0tQ5Eu@CdSOyaI63Vb*mR+rCzxgsjCXLSHOmzt0tA zGoA0Cp&l>rtO@^uQayrkoe#d2@}|?SlQl9W{fmcxY(0*y zHTZ6>FL;$8FEzbb;M(o%mBe-X?o<0+1dH?ZVjcf8)Kyqb07*a zLfP1blbt)=W)TN}4M#dUnt8Gdr4p$QRA<0W)JhWLK3-g82Q~2Drmx4J z;6m4re%igus136VL}MDI-V;WmSfs4guF_(7ifNl#M~Yx5HB!UF)>*-KDQl0U?u4UXV2I*qMhEfsxb%87fi+W;mW5{h?o8!52}VUs*Fpo#aSuXk(Ug z>r>xC#&2<9Uwmao@iJQ|{Vr__?eRT2NB$OcoXQ-jZ{t|?Uy{7q$nU-i|&-R6fHPWJDgHZ69iVbK#Ab@2@y zPD*Gj=hib?PWr8NGf;g$o5I!*n>94Z!IfqRm zLvM>Gx$Y*rEL3Z-+lS42=cnEfXR)h1z`h8a+I%E_ss%qXsrgIV%qv9d|KT>fV5=3e zw>P#ju>2naGc{=6!)9TeHq$S9Pk|>$UCEl}H}lE@;0(jbNT9TXUXyss>al>S4DuGi zVCy;Qt=a2`iu2;TvrIkh2NTvNV}0)qun~9y1yEQMdOf#V#3(e(C?+--8bCsJu={Q1z5qNJIk&yW>ZnVm;A=fL~29lvXQ*4j(SLau?P zi8LC7&**O!6B6=vfY%M;!p2L2tQ+w3Y!am{b?14E`h4kN$1L0XqT5=y=DW8GI_yi% zlIWsjmf0{l#|ei>)>&IM4>jXH)?>!fK?pfWIQn9gT9N(z&w3SvjlD|u*6T@oNQRF6 zU5Uo~SA}ml5f8mvxzX>BGL}c2#AT^6Lo-TM5XluWoqBRin$tiyRQK0wJ!Ro+7S!-K z=S95p-(#IDKOZsRd{l65N(Xae`wOa4Dg9?g|Jx97N-7OfHG(rN#k=yNGW0K$Tia5J zMMX1+!ulc1%8e*FNRV8jL|OSL-_9Nv6O=CH>Ty(W@sm`j=NFa1F3tT$?wM1}GZekB z6F_VLMCSd7(b9T%IqUMo$w9sM5wOA7l8xW<(1w0T=S}MB+9X5UT|+nemtm_;!|bxX z_bnOKN+F30ehJ$459k@=69yTz^_)-hNE4XMv$~_%vlH_y^`P1pLxYF6#_IZyteO`9wpuS> z#%Vyg5mMDt?}j!0}MoBX|9PS0#B zSVo6xLVjujMN57}IVc#A{VB*_yx;#mgM4~yT6wO;Qtm8MV6DX?u(JS~JFA~PvEl%9 z2XI}c>OzPoPn_IoyXa2v}BA(M+sWq=_~L0rZ_yR17I5c^m4;?2&KdCc)3lCs!M|0OzH@(PbG8T6w%N zKzR>%SLxL_C6~r3=xm9VG8<9yLHV6rJOjFHPaNdQHHflp><44l>&;)&7s)4lX%-er znWCv8eJJe1KAi_t1p%c4`bgxD2(1v)jm(gvQLp2K-=04oaIJu{F7SIu8&)gyw7x>+ zbzYF7KXg;T71w!-=C0DjcnF^JP$^o_N>*BAjtH!^HD6t1o?(O7IrmcodeQVDD<*+j zN)JdgB6v^iiJ1q`bZ(^WvN{v@sDqG$M9L`-UV!3q&sWZUnQ{&tAkpX(nZ_L#rMs}>p7l0fU5I5IzArncQi6TWjP#1B=QZ|Uqm-3{)YPn=XFqHW-~Fb z^!0CvIdelQbgcac9;By79%T`uvNhg9tS><pLzXePP=JZzcO@?5GRAdF4)sY*)YGP* zyioMa3=HRQz(v}+cqXc0%2*Q%CQi%e2~$a9r+X*u3J8w^Shg#%4I&?!$})y@ zzg8tQ6_-`|TBa_2v$D;Q(pFutj7@yos0W$&__9$|Yn3DFe*)k{g^|JIV4bqI@2%-4kpb_p? zQ4}qQcA>R6ihbxnVa{c;f7Y)VPV&mRY-*^qm~u3HB>8lf3P&&#GhQk8uIYYgwrugY zei>mp`YdC*R^Cxuv@d0V?$~d*=m-X?1Fqd9@*IM^wQ_^-nQEuc0!OqMr#TeT=8W`JbjjXc-Dh3NhnTj8e82yP;V_B<7LIejij+B{W1ViaJ_)+q?$BaLJpxt_4@&(?rWC3NC-_Z9Sg4JJWc( zX!Y34j67vCMHKB=JcJ1|#UI^D^mn(i=A5rf-iV7y4bR5HhC=I`rFPZv4F>q+h?l34 z4(?KYwZYHwkPG%kK7$A&M#=lpIn3Qo<>s6UFy|J$Zca-s(oM7??dkuKh?f5b2`m57 zJhs4BTcVVmwsswlX?#70uQb*k1Fi3q4+9`V+ikSk{L3K=-5HgN0JekQ=J~549Nd*+H%5+fi6aJuR=K zyD3xW{X$PL7&iR)=wumlTq2gY{LdrngAaPC;Qw_xLfVE0c0Z>y918TQpL!q@?`8{L!el18Qxiki3WZONF=eK$N3)p>36EW)I@Y z7QxbWW_9_7a*`VS&5~4-9!~&g8M+*U9{I2Bz`@TJ@E(YL$l+%<=?FyR#&e&v?Y@@G zqFF`J*v;l$&(A=s`na2>4ExKnxr`|OD+Xd-b4?6xl4mQ94xuk!-$l8*%+1zQU{)!= zTooUhjC0SNBh!&Ne}Q=1%`_r=Vu1c8RuE!|(g4BQGcd5AbpLbvKv_Z~Y`l!mr!sCc zDBupoc{W@U(6KWqW@xV_`;J0~+WDx|t^WeMri#=q0U5ZN7@@FAv<1!hP6!IYX z>UjbhaEv2Fk<6C0M^@J`lH#LgKJ(`?6z5=uH+ImggSQaZtvh52WTK+EBN~-op#EQKYW`$yBmq z4wgLTJPn3;mtbs0m0RO&+EG>?rb*ZECE0#eeSOFL!2YQ$w}cae>sun`<=}m!=go!v zO2jn<0tNh4E-4)ZA(ixh5nIUuXF-qYl>0I_1)K%EAw`D7~la$=gc@6g{iWF=>i_76?Mc zh#l9h7))<|EY=sK!E|54;c!b;Zp}HLd5*-w^6^whxB98v`*P>cj!Nfu1R%@bcp{cb zUZ24(fUXn3d&oc{6H%u(@4&_O?#HO(qd^YH=V`WJ=u*u6Zie8mE^r_Oz zDw`DaXeq4G#m@EK5+p40Xe!Lr!-jTQLCV3?R1|3#`%45h8#WSA!XoLDMS7=t!SluZ4H56;G z6C9D(B6>k^ur_DGfJ@Y-=3$5HkrI zO+3P>R@$6QZ#ATUI3$)xRBEL#5IKs}yhf&fK;ANA#Qj~G zdE|k|`puh$%dyE4R0$7dZd)M*#e7s%*PKPyrS;d%&S(d{_Ktq^!Hpi&bxZx`?9pEw z%sPjo&adHm95F7Z1{RdY#*a!&LcBZVRe{qhn8d{pOUJ{fOu`_kFg7ZVeRYZ(!ezNktT5{Ab z4BZI$vS0$vm3t9q`ECjDK;pmS{8ZTKs`Js~PYv2|=VkDv{Dtt)cLU@9%K6_KqtqfM zaE*e$f$Xm=;IAURNUXw8g%=?jzG2}10ZA5qXzAaJ@eh)yv5B=ETyVwC-a*CD;GgRJ z4J1~zMUey?4iVlS0zW|F-~0nenLiN3S0)l!T2}D%;<}Z9DzeVgcB+MSj;f$KY;uP%UR#f`0u*@6U@tk@jO3N?Fjq< z{cUUhjrr$rmo>qE?52zKe+>6iP5P_tcUfxsLSy{9*)shB(w`UUveNH`a`kr$VEF@} zKh&|lTD;4;m_H6C&)9#D`kRh;S(NTa=Ve^~xe_0~x$6h8Q@B_qu#ee=(lkI9@F6$0m=z@H=4&h%Q{htM>uHs(Sr@2ry`fgLA zKj8lVXdGPyy)2J%A${}Rm_a{){wHnlM?yGPQ7#KO{8*(_l0QZHuV};nO?c%h?qwSL z3wem|w*2tdxW5&PxC(Wd0QG_w|GPbw|0UFK`u$~U%!`QKcME;=Q@?*erh4_>FP~1n zAldwG9h$$u_$RFK6Uxo20GHqJzc}Rl-EwVz3h4n z;3~%DwD84i>)-8#&#y3k)3BG5cNaP3?t4q}F%yfv?*yEiC>sSo}$f>nh0QNZXH1N)-Q7kbk=2uL9OrF)nXrE@F1y%_8Yn c82=K%QXLKFx%@O{wJjEi6Y56o#$)Bpeg literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..6954be87 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.0-all.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100644 index 00000000..adff685a --- /dev/null +++ b/gradlew @@ -0,0 +1,248 @@ +#!/bin/sh + +# +# Copyright © 2015 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + 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 +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# 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, 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" \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ + "$@" + +# 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. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 00000000..c4bdd3ab --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,93 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* + +:end +@rem End local scope for the variables with windows NT shell +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! +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 + +:omega diff --git a/pom.xml b/pom.xml deleted file mode 100644 index 7ba63380..00000000 --- a/pom.xml +++ /dev/null @@ -1,384 +0,0 @@ - - - - - 4.0.0 - - io.zonky.test - embedded-postgres - 2.1.2-SNAPSHOT - - embedded-postgres - Embedded PostgreSQL Server - - - 1.8 - 1.8 - - UTF-8 - UTF-8 - - 14.19.0 - 1.17.1 - 1.26.2 - 2.16.1 - 3.18.0 - 9.22.3 - 5.10.5 - 4.13.2 - 4.30.0 - 4.11.0 - 7.4.0 - 42.7.7 - 1.7.36 - 1.10 - 3.5.0 - 1.6 - 3.8.0 - 3.24.0 - 3.1.1 - 3.3.1 - 3.3.1 - - - https://github.com/zonkyio/embedded-postgres - - - scm:git:https://github.com/zonkyio/embedded-postgres.git - scm:git:https://github.com/zonkyio/embedded-postgres.git - https://github.com/zonkyio/embedded-postgres - HEAD - - - - - The Apache License, Version 2.0 - http://www.apache.org/licenses/LICENSE-2.0.txt - - - - - - Tomas Vanek - tomix26@gmail.com - - - Zonky Developers - developers@zonky.cz - - - - - - ossrh - https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2/ - - - ossrh - https://central.sonatype.com/repository/maven-snapshots/ - - - - - - - commons-io - commons-io - ${commons-io.version} - - - org.apache.commons - commons-lang3 - ${commons-lang3.version} - - - org.apache.commons - commons-compress - ${commons-compress.version} - - - commons-codec - commons-codec - ${commons-codec.version} - - - org.junit - junit-bom - ${junit5.version} - pom - import - - - - - - io.zonky.test.postgres - embedded-postgres-binaries-windows-amd64 - ${embedded-postgres-binaries.version} - runtime - - - io.zonky.test.postgres - embedded-postgres-binaries-darwin-amd64 - ${embedded-postgres-binaries.version} - runtime - - - io.zonky.test.postgres - embedded-postgres-binaries-linux-amd64 - ${embedded-postgres-binaries.version} - runtime - - - io.zonky.test.postgres - embedded-postgres-binaries-linux-amd64-alpine - ${embedded-postgres-binaries.version} - runtime - - - - org.slf4j - slf4j-api - ${slf4j.version} - - - org.apache.commons - commons-lang3 - - - org.apache.commons - commons-compress - - - org.tukaani - xz - ${xz.version} - - - commons-io - commons-io - - - commons-codec - commons-codec - - - org.flywaydb - flyway-core - ${flyway.version} - true - - - org.liquibase - liquibase-core - ${liquibase.version} - true - - - org.postgresql - postgresql - ${postgresql.version} - - - junit - junit - ${junit4.version} - provided - true - - - org.junit.jupiter - junit-jupiter-api - provided - true - - - org.junit.vintage - junit-vintage-engine - test - - - org.junit.jupiter - junit-jupiter-engine - test - - - - org.slf4j - slf4j-simple - ${slf4j.version} - test - - - org.mockito - mockito-core - ${mockito.version} - test - - - - - - - org.apache.maven.plugins - maven-enforcer-plugin - ${maven-enforcer-plugin.version} - - - enforce-versions - validate - - enforce - - - - - - - - - - - maven-surefire-plugin - ${maven-surefire-plugin.version} - - - ${env.LC_ALL} - - - - - maven-pmd-plugin - ${maven-pmd-plugin.version} - - - verify - - check - - - - - - net.sourceforge.pmd - pmd-core - ${pmd.version} - compile - - - net.sourceforge.pmd - pmd-java - ${pmd.version} - compile - - - - false - true - 1.8 - UTF-8 - 100 - 4 - - - - org.apache.maven.plugins - maven-source-plugin - ${maven-source-plugin.version} - - - attach-sources - - jar - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - ${maven-javadoc-plugin.version} - - - attach-javadocs - - jar - - - - - none - - - - org.apache.maven.plugins - maven-release-plugin - ${maven-release-plugin.version} - - false - release - v@{project.version} - - - - - - - - - default-lc-all - - - !env.LC_ALL - - - Unix - - - - en_US.UTF-8 - - - - release - - - - org.apache.maven.plugins - maven-gpg-plugin - ${maven-gpg-plugin.version} - - - sign-artifacts - verify - - sign - - - - - --pinentry-mode - loopback - - - - - - - - - - - diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 00000000..50ffa18f --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,19 @@ +val name = providers.gradleProperty("name") +rootProject.name = name.get() + +pluginManagement { + repositories { + mavenCentral() + gradlePluginPortal() + } + val yumiGradleLicenserVersion = providers.gradleProperty("yumi_gradle_licenser_version") + val nmcpVersion = providers.gradleProperty("nmcp_version") + val cpdVersion = providers.gradleProperty("cpd_version") + val enforcerGradleVersion = providers.gradleProperty("enforcer_gradle_version") + plugins { + id("dev.yumi.gradle.licenser").version(yumiGradleLicenserVersion.get()) + id("com.gradleup.nmcp").version(nmcpVersion.get()) + id("de.aaschmid.cpd").version(cpdVersion.get()) + id("org.kordamp.gradle.project-enforcer").version(enforcerGradleVersion.get()) + } +} diff --git a/src/main/java/io/zonky/test/db/postgres/embedded/ConnectionInfo.java b/src/main/java/io/zonky/test/db/postgres/embedded/ConnectionInfo.java index acef3179..1722beb1 100644 --- a/src/main/java/io/zonky/test/db/postgres/embedded/ConnectionInfo.java +++ b/src/main/java/io/zonky/test/db/postgres/embedded/ConnectionInfo.java @@ -1,9 +1,11 @@ /* + * Copyright 2025 Tomas Vanek + * * Licensed 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 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -11,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package io.zonky.test.db.postgres.embedded; import java.util.HashMap; @@ -26,6 +29,7 @@ public class ConnectionInfo { private final String user; private final Map properties; + @SuppressWarnings("unused") public ConnectionInfo(final String dbName, final int port, final String user) { this(dbName, port, user, emptyMap()); } diff --git a/src/main/java/io/zonky/test/db/postgres/embedded/DatabaseConnectionPreparer.java b/src/main/java/io/zonky/test/db/postgres/embedded/DatabaseConnectionPreparer.java index 30577f8b..33789008 100644 --- a/src/main/java/io/zonky/test/db/postgres/embedded/DatabaseConnectionPreparer.java +++ b/src/main/java/io/zonky/test/db/postgres/embedded/DatabaseConnectionPreparer.java @@ -1,9 +1,11 @@ /* + * Copyright 2025 Tomas Vanek + * * Licensed 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 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -11,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package io.zonky.test.db.postgres.embedded; +import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; -import javax.sql.DataSource; - public interface DatabaseConnectionPreparer extends DatabasePreparer { @Override diff --git a/src/main/java/io/zonky/test/db/postgres/embedded/DatabasePreparer.java b/src/main/java/io/zonky/test/db/postgres/embedded/DatabasePreparer.java index 432c09c1..b385dc1f 100644 --- a/src/main/java/io/zonky/test/db/postgres/embedded/DatabasePreparer.java +++ b/src/main/java/io/zonky/test/db/postgres/embedded/DatabasePreparer.java @@ -1,9 +1,11 @@ /* + * Copyright 2025 Tomas Vanek + * * Licensed 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 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -11,17 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.zonky.test.db.postgres.embedded; -import java.sql.SQLException; +package io.zonky.test.db.postgres.embedded; import javax.sql.DataSource; +import java.sql.SQLException; /** * A DatabasePreparer applies an arbitrary set of changes * (e.g. database migrations, user creation) to a database * before it is presented to the user. - * + *

* The preparation steps are expected to be deterministic. * For efficiency reasons, databases created by DatabasePreparer * instances may be pooled, using {@link Object#hashCode()} and diff --git a/src/main/java/io/zonky/test/db/postgres/embedded/DefaultPostgresBinaryResolver.java b/src/main/java/io/zonky/test/db/postgres/embedded/DefaultPostgresBinaryResolver.java index b90fda68..3e4ced37 100644 --- a/src/main/java/io/zonky/test/db/postgres/embedded/DefaultPostgresBinaryResolver.java +++ b/src/main/java/io/zonky/test/db/postgres/embedded/DefaultPostgresBinaryResolver.java @@ -1,9 +1,11 @@ /* + * Copyright 2025 Tomas Vanek + * * Licensed 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 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -11,12 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package io.zonky.test.db.postgres.embedded; import io.zonky.test.db.postgres.util.ArchUtils; import io.zonky.test.db.postgres.util.LinuxUtils; import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -45,7 +49,8 @@ public InputStream getPgBinary(String system, String machineHardware) throws IOE String architecture = ArchUtils.normalize(machineHardware); String distribution = LinuxUtils.getDistributionName(); - logger.info("Detected distribution: '{}'", Optional.ofNullable(distribution).orElse("Unknown")); + if (logger.isInfoEnabled()) + logger.info("Detected distribution: '{}'", Optional.ofNullable(distribution).orElse("Unknown")); if (distribution != null) { Resource resource = findPgBinary(normalize(format("postgres-%s-%s-%s.txz", system, architecture, distribution))); @@ -63,8 +68,8 @@ public InputStream getPgBinary(String system, String machineHardware) throws IOE return resource.getInputStream(); } - if ((StringUtils.equals(system, "Darwin") && StringUtils.equals(machineHardware, "aarch64")) // NOPMD - || (StringUtils.equals(system, "Windows") && StringUtils.equals(architecture, "arm_64"))) { // NOPMD + if ((Strings.CS.equals(system, "Darwin") && Strings.CS.equals(machineHardware, "aarch64")) + || (Strings.CS.equals(system, "Windows") && Strings.CS.equals(architecture, "arm_64"))) { resource = findPgBinary(normalize(format("postgres-%s-%s.txz", system, "x86_64"))); if (resource != null) { logger.warn("No native binaries supporting ARM architecture found. " + @@ -81,9 +86,10 @@ public InputStream getPgBinary(String system, String machineHardware) throws IOE throw new IllegalStateException("Missing embedded postgres binaries"); } + @SuppressWarnings("PMD.AvoidLiteralsInIfCondition") private static Resource findPgBinary(String resourceLocation) throws IOException { logger.trace("Searching for postgres binaries - location: '{}'", resourceLocation); - ClassLoader classLoader = DefaultPostgresBinaryResolver.class.getClassLoader(); + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); List urls = Collections.list(classLoader.getResources(resourceLocation)); if (urls.size() > 1) { @@ -120,8 +126,7 @@ public InputStream getInputStream() throws IOException { URLConnection con = this.url.openConnection(); try { return con.getInputStream(); - } - catch (IOException ex) { + } catch (IOException ex) { // Close the HTTP connection (if applicable). if (con instanceof HttpURLConnection) { ((HttpURLConnection) con).disconnect(); diff --git a/src/main/java/io/zonky/test/db/postgres/embedded/EmbeddedPostgres.java b/src/main/java/io/zonky/test/db/postgres/embedded/EmbeddedPostgres.java index 48fe5843..844dbb41 100644 --- a/src/main/java/io/zonky/test/db/postgres/embedded/EmbeddedPostgres.java +++ b/src/main/java/io/zonky/test/db/postgres/embedded/EmbeddedPostgres.java @@ -1,9 +1,11 @@ /* + * Copyright 2025 Tomas Vanek + * * Licensed 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 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -11,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package io.zonky.test.db.postgres.embedded; import io.zonky.test.db.postgres.util.LinuxUtils; @@ -28,22 +31,13 @@ import org.tukaani.xz.XZInputStream; import javax.sql.DataSource; -import java.io.ByteArrayInputStream; -import java.io.Closeable; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; +import java.io.*; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.nio.ByteBuffer; -import java.nio.channels.AsynchronousFileChannel; -import java.nio.channels.Channel; -import java.nio.channels.CompletionHandler; -import java.nio.channels.FileLock; -import java.nio.channels.OverlappingFileLockException; +import java.nio.channels.*; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; @@ -55,17 +49,8 @@ import java.sql.SQLException; import java.sql.Statement; import java.time.Duration; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.Map.Entry; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.UUID; import java.util.concurrent.Phaser; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -79,8 +64,7 @@ import static java.util.Collections.unmodifiableMap; @SuppressWarnings("PMD.AvoidDuplicateLiterals") // "postgres" -public class EmbeddedPostgres implements Closeable -{ +public class EmbeddedPostgres implements Closeable { private static final Logger LOG = LoggerFactory.getLogger(EmbeddedPostgres.class); private static final String JDBC_FORMAT = "jdbc:postgresql://localhost:%s/%s?user=%s"; @@ -93,7 +77,8 @@ public class EmbeddedPostgres implements Closeable private final File pgDir; private final Duration pgStartupWait; - private final File dataDirectory, lockFile; + private final File dataDirectory; + private final File lockFile; private final UUID instanceId = UUID.randomUUID(); private final int port; private final AtomicBoolean started = new AtomicBoolean(); @@ -104,6 +89,7 @@ public class EmbeddedPostgres implements Closeable private final Map connectConfig; private volatile FileOutputStream lockStream; + @SuppressWarnings("PMD.AvoidFieldNameMatchingMethodName") private volatile FileLock lock; private final boolean cleanDataDirectory; @@ -111,20 +97,20 @@ public class EmbeddedPostgres implements Closeable private final ProcessBuilder.Redirect outputRedirector; private final Process process; + @SuppressWarnings("unused") EmbeddedPostgres(File parentDirectory, File dataDirectory, boolean cleanDataDirectory, Map postgresConfig, Map localeConfig, int port, Map connectConfig, - PgBinaryResolver pgBinaryResolver, ProcessBuilder.Redirect errorRedirector, ProcessBuilder.Redirect outputRedirector) throws IOException - { + PgBinaryResolver pgBinaryResolver, ProcessBuilder.Redirect errorRedirector, ProcessBuilder.Redirect outputRedirector) throws IOException { this(parentDirectory, dataDirectory, cleanDataDirectory, postgresConfig, localeConfig, port, connectConfig, pgBinaryResolver, errorRedirector, outputRedirector, DEFAULT_PG_STARTUP_WAIT, null, null); } + @SuppressWarnings("PMD.ConstructorCallsOverridableMethod") EmbeddedPostgres(File parentDirectory, File dataDirectory, boolean cleanDataDirectory, - Map postgresConfig, Map localeConfig, int port, Map connectConfig, - PgBinaryResolver pgBinaryResolver, ProcessBuilder.Redirect errorRedirector, - ProcessBuilder.Redirect outputRedirector, Duration pgStartupWait, - File overrideWorkingDirectory, Consumer dataDirectoryCustomizer) throws IOException - { + Map postgresConfig, Map localeConfig, int port, Map connectConfig, + PgBinaryResolver pgBinaryResolver, ProcessBuilder.Redirect errorRedirector, + ProcessBuilder.Redirect outputRedirector, Duration pgStartupWait, + File overrideWorkingDirectory, Consumer dataDirectoryCustomizer) throws IOException { this.cleanDataDirectory = cleanDataDirectory; this.postgresConfig = new HashMap<>(postgresConfig); this.localeConfig = new HashMap<>(localeConfig); @@ -168,17 +154,17 @@ public class EmbeddedPostgres implements Closeable this.process = startPostmaster(); } + @SuppressWarnings("unused") public Process getProcess() { - return this.process; + return this.process; } - public DataSource getTemplateDatabase() - { + public DataSource getTemplateDatabase() { return getDatabase("postgres", "template1"); } - public DataSource getTemplateDatabase(Map properties) - { + @SuppressWarnings("unused") + public DataSource getTemplateDatabase(Map properties) { return getDatabase("postgres", "template1", properties); } @@ -186,8 +172,8 @@ public DataSource getPostgresDatabase() { return getDatabase("postgres", "postgres"); } - public DataSource getPostgresDatabase(Map properties) - { + @SuppressWarnings("unused") + public DataSource getPostgresDatabase(Map properties) { return getDatabase("postgres", "postgres", properties); } @@ -195,11 +181,10 @@ public DataSource getDatabase(String userName, String dbName) { return getDatabase(userName, dbName, connectConfig); } - public DataSource getDatabase(String userName, String dbName, Map properties) - { + public DataSource getDatabase(String userName, String dbName, Map properties) { final PGSimpleDataSource ds = new PGSimpleDataSource(); - ds.setServerName("localhost"); - ds.setPortNumber(port); + ds.setServerNames(new String[]{"localhost"}); + ds.setPortNumbers(new int[]{port}); ds.setDatabaseName(dbName); ds.setUser(userName); @@ -213,23 +198,20 @@ public DataSource getDatabase(String userName, String dbName, Map getConnectConfig() - { + Map getConnectConfig() { return unmodifiableMap(connectConfig); } - private static int detectPort() throws IOException - { + private static int detectPort() throws IOException { try (ServerSocket socket = new ServerSocket(0)) { while (!socket.isBound()) { Thread.sleep(50); @@ -241,16 +223,15 @@ private static int detectPort() throws IOException } } - private void lock() throws IOException - { + @SuppressWarnings("PMD.AssignmentInOperand") + private void lock() throws IOException { lockStream = new FileOutputStream(lockFile); if ((lock = lockStream.getChannel().tryLock()) == null) { throw new IllegalStateException("could not lock " + lockFile); } } - private void initdb() - { + private void initdb() { final StopWatch watch = new StopWatch(); watch.start(); List args = new ArrayList<>(); @@ -262,16 +243,14 @@ private void initdb() LOG.info("{} initdb completed in {}", instanceId, watch); } - private Process startPostmaster() throws IOException - { + private Process startPostmaster() throws IOException { final StopWatch watch = new StopWatch(); watch.start(); if (started.getAndSet(true)) { throw new IllegalStateException("Postmaster already started"); } - final List args = new ArrayList<>(); - args.addAll(Arrays.asList( + final List args = new ArrayList<>(Arrays.asList( "-D", dataDirectory.getPath(), "-o", String.join(" ", createInitOptions()), "-w", "start" @@ -289,7 +268,7 @@ private Process startPostmaster() throws IOException ProcessOutputLogger.logOutput(LOG, postmaster, POSTGRES.processName()); } - LOG.info("{} postmaster started as {} on port {}. Waiting up to {} for server startup to finish.", instanceId, postmaster.toString(), port, pgStartupWait); + LOG.info("{} postmaster started as {} on port {}. Waiting up to {} for server startup to finish.", instanceId, postmaster, port, pgStartupWait); Runtime.getRuntime().addShutdownHook(newCloserThread()); @@ -297,15 +276,12 @@ private Process startPostmaster() throws IOException return postmaster; } - private List createInitOptions() - { - final List initOptions = new ArrayList<>(); - initOptions.addAll(Arrays.asList( + private List createInitOptions() { + final List initOptions = new ArrayList<>(Arrays.asList( "-p", Integer.toString(port), "-F")); - for (final Entry config : postgresConfig.entrySet()) - { + for (final Entry config : postgresConfig.entrySet()) { initOptions.add("-c"); initOptions.add(config.getKey() + "=" + config.getValue()); } @@ -313,8 +289,7 @@ private List createInitOptions() return initOptions; } - private List createLocaleOptions() - { + private List createLocaleOptions() { final List localeOptions = new ArrayList<>(); for (final Entry config : localeConfig.entrySet()) { localeOptions.add(String.format("--%s=%s", config.getKey(), config.getValue())); @@ -322,8 +297,7 @@ private List createLocaleOptions() return localeOptions; } - private void waitForServerStartup(StopWatch watch) throws IOException - { + private void waitForServerStartup(StopWatch watch) throws IOException { Throwable lastCause = null; final long start = System.nanoTime(); final long maxWaitNs = TimeUnit.NANOSECONDS.convert(pgStartupWait.toMillis(), TimeUnit.MILLISECONDS); @@ -347,8 +321,8 @@ private void waitForServerStartup(StopWatch watch) throws IOException throw new IOException("Gave up waiting for server to start after " + pgStartupWait.toMillis() + "ms", lastCause); } - private void verifyReady() throws SQLException - { + @SuppressWarnings({"PMD.AvoidLiteralsInIfCondition", "SqlNoDataSourceInspection"}) + private void verifyReady() throws SQLException { final InetAddress localhost = InetAddress.getLoopbackAddress(); try (Socket sock = new Socket()) { sock.setSoTimeout((int) Duration.ofMillis(500).toMillis()); @@ -358,8 +332,7 @@ private void verifyReady() throws SQLException } try (Connection c = getPostgresDatabase().getConnection() ; Statement s = c.createStatement() ; - ResultSet rs = s.executeQuery("SELECT 1")) - { + ResultSet rs = s.executeQuery("SELECT 1")) { if (!rs.next()) { throw new IllegalStateException("expecting single row"); } @@ -372,27 +345,21 @@ private void verifyReady() throws SQLException } } - private Thread newCloserThread() - { - final Thread closeThread = new Thread(new Runnable() { - @Override - public void run() - { - try { - EmbeddedPostgres.this.close(); - } - catch (IOException ex) { - LOG.error("Unexpected IOException from Closeables.close", ex); - } + private Thread newCloserThread() { + final Thread closeThread = new Thread(() -> { + try { + EmbeddedPostgres.this.close(); + } catch (IOException ex) { + LOG.error("Unexpected IOException from Closeables.close", ex); } }); closeThread.setName("postgres-" + instanceId + "-closer"); return closeThread; } + @SuppressWarnings("PMD.AvoidCatchingGenericException") @Override - public void close() throws IOException - { + public void close() throws IOException { if (closed.getAndSet(true)) { return; } @@ -402,7 +369,7 @@ public void close() throws IOException pgCtl(dataDirectory, "stop"); LOG.info("{} shut down postmaster in {}", instanceId, watch); } catch (final Exception e) { - LOG.error("Could not stop postmaster " + instanceId, e); + LOG.error("Could not stop postmaster {}", instanceId, e); } if (lock != null) { lock.release(); @@ -424,10 +391,9 @@ public void close() throws IOException } } - private void pgCtl(File dir, String action) - { - final List args = new ArrayList<>(); - args.addAll(Arrays.asList( + @SuppressWarnings("SameParameterValue") + private void pgCtl(File dir, String action) { + final List args = new ArrayList<>(Arrays.asList( "-D", dir.getPath(), action, "-m", PG_STOP_MODE, "-t", PG_STOP_WAIT_S, "-w" @@ -435,14 +401,13 @@ private void pgCtl(File dir, String action) system(PG_CTL, args); } - private void cleanOldDataDirectories(File parentDirectory) - { + @SuppressWarnings("PMD.AvoidCatchingGenericException") + private void cleanOldDataDirectories(File parentDirectory) { final File[] children = parentDirectory.listFiles(); if (children == null) { return; } - for (final File dir : children) - { + for (final File dir : children) { if (!dir.isDirectory()) { continue; } @@ -453,7 +418,7 @@ private void cleanOldDataDirectories(File parentDirectory) continue; } try (FileOutputStream fos = new FileOutputStream(lockFile); - FileLock lock = fos.getChannel().tryLock()) { + FileLock lock = fos.getChannel().tryLock()) { if (lock != null) { LOG.info("Found stale data directory {}", dir); if (new File(dir, "postmaster.pid").exists()) { @@ -462,9 +427,9 @@ private void cleanOldDataDirectories(File parentDirectory) LOG.info("Shut down orphaned postmaster!"); } catch (Exception e) { if (LOG.isDebugEnabled()) { - LOG.warn("Failed to stop postmaster " + dir, e); + LOG.warn("Failed to stop postmaster {}", dir, e); } else { - LOG.warn("Failed to stop postmaster " + dir + ": " + e.getMessage()); + LOG.warn("Failed to stop postmaster {}: {}", dir, e.getMessage()); } } } @@ -479,24 +444,20 @@ private void cleanOldDataDirectories(File parentDirectory) } } - private static File getWorkingDirectory() - { + private static File getWorkingDirectory() { final File tempWorkingDirectory = new File(System.getProperty("java.io.tmpdir"), "embedded-pg"); return new File(System.getProperty("ot.epg.working-dir", tempWorkingDirectory.getPath())); } - public static EmbeddedPostgres start() throws IOException - { + public static EmbeddedPostgres start() throws IOException { return builder().start(); } - public static EmbeddedPostgres.Builder builder() - { + public static EmbeddedPostgres.Builder builder() { return new Builder(); } - public static class Builder - { + public static class Builder { private final File parentDirectory = getWorkingDirectory(); private File overrideWorkingDirectory; private File builderDataDirectory; @@ -518,15 +479,17 @@ public static class Builder config.put("max_connections", "300"); } + @SuppressWarnings("UnusedReturnValue") public Builder setPGStartupWait(Duration pgStartupWait) { Objects.requireNonNull(pgStartupWait); if (pgStartupWait.isNegative()) { - throw new IllegalArgumentException("Negative durations are not permitted."); + throw new IllegalArgumentException("Negative durations are not permitted."); } this.pgStartupWait = pgStartupWait; return this; } + @SuppressWarnings("unused") public Builder setCleanDataDirectory(boolean cleanDataDirectory) { builderCleanDataDirectory = cleanDataDirectory; return this; @@ -541,46 +504,54 @@ public Builder setDataDirectory(File directory) { return this; } + @SuppressWarnings("unused") public Builder setDataDirectory(String path) { return setDataDirectory(new File(path)); } + @SuppressWarnings("unused") public Builder setServerConfig(String key, String value) { config.put(key, value); return this; } + @SuppressWarnings("unused") public Builder setLocaleConfig(String key, String value) { localeConfig.put(key, value); return this; } + @SuppressWarnings("UnusedReturnValue") public Builder setConnectConfig(String key, String value) { connectConfig.put(key, value); return this; } + @SuppressWarnings("unused") public Builder setOverrideWorkingDirectory(File workingDirectory) { overrideWorkingDirectory = workingDirectory; return this; } + @SuppressWarnings("unused") public Builder setPort(int port) { builderPort = port; return this; } + @SuppressWarnings("unused") public Builder setErrorRedirector(ProcessBuilder.Redirect errRedirector) { this.errRedirector = errRedirector; return this; } - public Builder setOutputRedirector(ProcessBuilder.Redirect outRedirector) - { + @SuppressWarnings("unused") + public Builder setOutputRedirector(ProcessBuilder.Redirect outRedirector) { this.outRedirector = outRedirector; return this; } + @SuppressWarnings("unused") public Builder setPgBinaryResolver(PgBinaryResolver pgBinaryResolver) { this.pgBinaryResolver = pgBinaryResolver; return this; @@ -592,8 +563,7 @@ public Builder setDataDirectoryCustomizer(final Consumer dataDirectoryCust } public EmbeddedPostgres start() throws IOException { - if (builderPort == 0) - { + if (builderPort == 0) { builderPort = detectPort(); } if (builderDataDirectory == null) { @@ -625,7 +595,7 @@ public boolean equals(Object o) { Objects.equals(errRedirector, builder.errRedirector) && Objects.equals(outRedirector, builder.outRedirector) && Objects.equals(dataDirectoryCustomizer != null ? dataDirectoryCustomizer.getClass() : null, - builder.dataDirectoryCustomizer != null ? builder.dataDirectoryCustomizer.getClass() : null); + builder.dataDirectoryCustomizer != null ? builder.dataDirectoryCustomizer.getClass() : null); } @Override @@ -634,8 +604,8 @@ public int hashCode() { } } - private void system(Command command, List args) - { + @SuppressWarnings("PMD.AvoidCatchingGenericException") + private void system(Command command, List args) { try { final ProcessBuilder builder = new ProcessBuilder(); @@ -652,15 +622,14 @@ private void system(Command command, List args) if (0 != process.waitFor()) { throw new IllegalStateException(String.format("Process %s failed", builder.command())); } - } catch (final RuntimeException e) { // NOPMD + } catch (final RuntimeException e) { throw e; } catch (final Exception e) { throw new RuntimeException(e); } } - private static void mkdirs(File dir) - { + private static void mkdirs(File dir) { if (!dir.mkdirs() && !(dir.isDirectory() && dir.exists())) { throw new IllegalStateException("could not create " + dir); } @@ -674,8 +643,7 @@ private static void mkdirs(File dir) * * @return Current operating system string. */ - private static String getOS() - { + private static String getOS() { if (SystemUtils.IS_OS_WINDOWS) { return "Windows"; } @@ -693,18 +661,18 @@ private static String getOS() * * @return Current machine architecture string. */ - private static String getArchitecture() - { + private static String getArchitecture() { return "amd64".equals(SystemUtils.OS_ARCH) ? "x86_64" : SystemUtils.OS_ARCH; } /** - * Unpack archive compressed by tar with xz compression. By default system tar is used (faster). If not found, then the + * Unpack archive compressed by tar with xz compression. By default, system tar is used (faster). If not found, then the * java implementation takes place. * * @param stream A stream with the postgres binaries. * @param targetDir The directory to extract the content to. */ + @SuppressWarnings({"PMD.AssignmentInOperand", "PMD.CloseResource", "ResultOfMethodCallIgnored"}) private static void extractTxz(InputStream stream, File targetDir) throws IOException { try ( XZInputStream xzIn = new XZInputStream(stream); @@ -714,7 +682,7 @@ private static void extractTxz(InputStream stream, File targetDir) throws IOExce final Phaser phaser = new Phaser(1); TarArchiveEntry entry; - while ((entry = tarIn.getNextTarEntry()) != null) { + while ((entry = tarIn.getNextEntry()) != null) { final String individualFile = entry.getName(); final File fsObject = new File(targetDir, individualFile); @@ -787,8 +755,8 @@ private void closeChannel(Channel channel) { } } - private static File prepareBinaries(PgBinaryResolver pgBinaryResolver, File overrideWorkingDirectory) - { + @SuppressWarnings({"PMD.AssignmentInOperand", "PMD.CloseResource", "ResultOfMethodCallIgnored"}) + private static File prepareBinaries(PgBinaryResolver pgBinaryResolver, File overrideWorkingDirectory) { PREPARE_BINARIES_LOCK.lock(); try { if (PREPARE_BINARIES.containsKey(pgBinaryResolver) && PREPARE_BINARIES.get(pgBinaryResolver).exists()) { @@ -812,7 +780,7 @@ private static File prepareBinaries(PgBinaryResolver pgBinaryResolver, File over } try (DigestInputStream pgArchiveData = new DigestInputStream(pgBinary, MessageDigest.getInstance("MD5")); - ByteArrayOutputStream baos = new ByteArrayOutputStream()) { + ByteArrayOutputStream baos = new ByteArrayOutputStream()) { IOUtils.copy(pgArchiveData, baos); pgArchiveData.close(); @@ -828,7 +796,7 @@ private static File prepareBinaries(PgBinaryResolver pgBinaryResolver, File over if (!isPgBinReady(pgDirExists)) { File unpackLockFile = new File(pgDir, LOCK_FILE_NAME); try (FileOutputStream lockStream = new FileOutputStream(unpackLockFile); - FileLock unpackLock = lockStream.getChannel().tryLock()) { + FileLock unpackLock = lockStream.getChannel().tryLock()) { if (unpackLock != null) { LOG.info("Extracting Postgres..."); try (ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray())) { @@ -868,6 +836,7 @@ private static File prepareBinaries(PgBinaryResolver pgBinaryResolver, File over } } + @SuppressWarnings("BooleanMethodIsAlwaysInverted") private static boolean isPgBinReady(File pgDirExists) { if (!pgDirExists.exists()) { return false; @@ -881,8 +850,7 @@ private static boolean isPgBinReady(File pgDirExists) { } @Override - public String toString() - { + public String toString() { return "EmbeddedPG-" + instanceId; } diff --git a/src/main/java/io/zonky/test/db/postgres/embedded/FlywayPreparer.java b/src/main/java/io/zonky/test/db/postgres/embedded/FlywayPreparer.java index f7fecf4d..83379662 100644 --- a/src/main/java/io/zonky/test/db/postgres/embedded/FlywayPreparer.java +++ b/src/main/java/io/zonky/test/db/postgres/embedded/FlywayPreparer.java @@ -1,9 +1,11 @@ /* + * Copyright 2025 Tomas Vanek + * * Licensed 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 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -11,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package io.zonky.test.db.postgres.embedded; import org.apache.commons.lang3.reflect.MethodUtils; @@ -18,12 +21,7 @@ import org.flywaydb.core.api.configuration.FluentConfiguration; import javax.sql.DataSource; -import java.sql.SQLException; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import java.util.*; public final class FlywayPreparer implements DatabasePreparer { @@ -62,8 +60,9 @@ private FlywayPreparer(FluentConfiguration configuration, List locations this.properties = properties; } + @SuppressWarnings("PMD.AvoidCatchingGenericException") @Override - public void prepare(DataSource ds) throws SQLException { + public void prepare(DataSource ds) { configuration.dataSource(ds); Flyway flyway = configuration.load(); try { diff --git a/src/main/java/io/zonky/test/db/postgres/embedded/LiquibasePreparer.java b/src/main/java/io/zonky/test/db/postgres/embedded/LiquibasePreparer.java index d611681e..66eec754 100644 --- a/src/main/java/io/zonky/test/db/postgres/embedded/LiquibasePreparer.java +++ b/src/main/java/io/zonky/test/db/postgres/embedded/LiquibasePreparer.java @@ -1,9 +1,11 @@ /* + * Copyright 2025 Tomas Vanek + * * Licensed 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 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -11,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package io.zonky.test.db.postgres.embedded; import liquibase.Contexts; @@ -19,11 +22,12 @@ import liquibase.database.jvm.JdbcConnection; import liquibase.exception.LiquibaseException; import liquibase.resource.ClassLoaderResourceAccessor; -import liquibase.resource.FileSystemResourceAccessor; +import liquibase.resource.DirectoryResourceAccessor; import liquibase.resource.ResourceAccessor; import javax.sql.DataSource; import java.io.File; +import java.io.FileNotFoundException; import java.sql.Connection; import java.sql.SQLException; import java.util.Objects; @@ -55,7 +59,11 @@ public static LiquibasePreparer forFile(File file, Contexts contexts) { if (dir == null) throw new IllegalArgumentException("Cannot get parent dir from file"); - return new LiquibasePreparer(file.getName(), new FileSystemResourceAccessor(dir), contexts); + try { + return new LiquibasePreparer(file.getName(), new DirectoryResourceAccessor(dir), contexts); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } } private LiquibasePreparer(String location, ResourceAccessor accessor, Contexts contexts) { @@ -64,10 +72,11 @@ private LiquibasePreparer(String location, ResourceAccessor accessor, Contexts c this.contexts = contexts != null ? contexts : new Contexts(); } + @SuppressWarnings("PMD.CloseResource") @Override public void prepare(DataSource ds) throws SQLException { - try (Connection connection = ds.getConnection()) { - Database database = getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection)); + try (Connection connection = ds.getConnection(); + Database database = getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection))) { Liquibase liquibase = new Liquibase(location, accessor, database); liquibase.update(contexts); } catch (LiquibaseException e) { diff --git a/src/main/java/io/zonky/test/db/postgres/embedded/PgBinaryResolver.java b/src/main/java/io/zonky/test/db/postgres/embedded/PgBinaryResolver.java index 2102ab7c..b2f49143 100644 --- a/src/main/java/io/zonky/test/db/postgres/embedded/PgBinaryResolver.java +++ b/src/main/java/io/zonky/test/db/postgres/embedded/PgBinaryResolver.java @@ -1,9 +1,11 @@ /* + * Copyright 2025 Tomas Vanek + * * Licensed 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 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -26,7 +28,7 @@ public interface PgBinaryResolver { /** * Returns an input stream with the postgress binary for the given - * systen and hardware architecture. + * system and hardware architecture. * @param system a system identification (Darwin, Linux...) * @param machineHardware a machine hardware architecture (x86_64...) * @return the binary diff --git a/src/main/java/io/zonky/test/db/postgres/embedded/PreparedDbProvider.java b/src/main/java/io/zonky/test/db/postgres/embedded/PreparedDbProvider.java index 0e306cc5..ed369cfa 100644 --- a/src/main/java/io/zonky/test/db/postgres/embedded/PreparedDbProvider.java +++ b/src/main/java/io/zonky/test/db/postgres/embedded/PreparedDbProvider.java @@ -1,9 +1,11 @@ /* + * Copyright 2025 Tomas Vanek + * * Licensed 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 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -11,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package io.zonky.test.db.postgres.embedded; import io.zonky.test.db.postgres.embedded.EmbeddedPostgres.Builder; @@ -22,13 +25,8 @@ import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; -import java.util.Collections; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; +import java.util.*; import java.util.Map.Entry; -import java.util.Objects; -import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.SynchronousQueue; @@ -38,8 +36,7 @@ import static java.util.Collections.emptyMap; import static java.util.Collections.unmodifiableMap; -public class PreparedDbProvider -{ +public class PreparedDbProvider { private static final String JDBC_FORMAT = "jdbc:postgresql://localhost:%d/%s?user=%s"; /** @@ -51,6 +48,7 @@ public class PreparedDbProvider private final PrepPipeline dbPreparer; + @SuppressWarnings({"unused", "PMD.AvoidDuplicateLiterals"}) public static PreparedDbProvider forPreparer(DatabasePreparer preparer) { return forPreparer(preparer, Collections.emptyList()); } @@ -71,8 +69,8 @@ private PreparedDbProvider(DatabasePreparer preparer, Iterable * Each schema set has its own database cluster. The template1 database has the schema preloaded so that * each test case need only create a new database and not re-invoke your preparer. */ - private static synchronized PrepPipeline createOrFindPreparer(DatabasePreparer preparer, Iterable> customizers) throws IOException, SQLException - { + @SuppressWarnings("PMD.CloseResource") + private static synchronized PrepPipeline createOrFindPreparer(DatabasePreparer preparer, Iterable> customizers) throws IOException, SQLException { final ClusterKey key = new ClusterKey(preparer, customizers); PrepPipeline result = CLUSTERS.get(key); if (result != null) { @@ -93,8 +91,7 @@ private static synchronized PrepPipeline createOrFindPreparer(DatabasePreparer p * Create a new database, and return it as a JDBC connection string. * NB: No two invocations will return the same database. */ - public String createDatabase() throws SQLException - { + public String createDatabase() throws SQLException { return getJdbcUri(createNewDB()); } @@ -105,25 +102,22 @@ public String createDatabase() throws SQLException * get the JDBC connection string. * NB: No two invocations will return the same database. */ - private DbInfo createNewDB() throws SQLException - { - return dbPreparer.getNextDb(); + private DbInfo createNewDB() throws SQLException { + return dbPreparer.getNextDb(); } - public ConnectionInfo createNewDatabase() throws SQLException - { + public ConnectionInfo createNewDatabase() throws SQLException { final DbInfo dbInfo = createNewDB(); - return dbInfo == null || !dbInfo.isSuccess() ? null : new ConnectionInfo(dbInfo.getDbName(), dbInfo.getPort(), dbInfo.getUser(), dbInfo.getProperties()); + return !dbInfo.isSuccess() ? null : new ConnectionInfo(dbInfo.getDbName(), dbInfo.getPort(), dbInfo.getUser(), dbInfo.getProperties()); } /** * Create a new Datasource given DBInfo. * More common usage is to call createDatasource(). */ - public DataSource createDataSourceFromConnectionInfo(final ConnectionInfo connectionInfo) throws SQLException - { + public DataSource createDataSourceFromConnectionInfo(final ConnectionInfo connectionInfo) throws SQLException { final PGSimpleDataSource ds = new PGSimpleDataSource(); - ds.setPortNumber(connectionInfo.getPort()); + ds.setPortNumbers(new int[]{connectionInfo.getPort()}); ds.setDatabaseName(connectionInfo.getDbName()); ds.setUser(connectionInfo.getUser()); @@ -139,13 +133,12 @@ public DataSource createDataSourceFromConnectionInfo(final ConnectionInfo connec * Create a new database, and return it as a DataSource. * No two invocations will return the same database. */ - public DataSource createDataSource() throws SQLException - { + @SuppressWarnings("unused") + public DataSource createDataSource() throws SQLException { return createDataSourceFromConnectionInfo(createNewDatabase()); } - private String getJdbcUri(DbInfo db) - { + private String getJdbcUri(DbInfo db) { String additionalParameters = db.getProperties().entrySet().stream() .map(e -> String.format("&%s=%s", e.getKey(), e.getValue())) .collect(Collectors.joining()); @@ -155,8 +148,8 @@ private String getJdbcUri(DbInfo db) /** * Return configuration tweaks in a format appropriate for otj-jdbc DatabaseModule. */ - public Map getConfigurationTweak(String dbModuleName) throws SQLException - { + @SuppressWarnings("unused") + public Map getConfigurationTweak(String dbModuleName) throws SQLException { final DbInfo db = dbPreparer.getNextDb(); final Map result = new HashMap<>(); result.put("ot.db." + dbModuleName + ".uri", getJdbcUri(db)); @@ -168,18 +161,15 @@ public Map getConfigurationTweak(String dbModuleName) throws SQL * Spawns a background thread that prepares databases ahead of time for speed, and then uses a * synchronous queue to hand the prepared databases off to test cases. */ - private static class PrepPipeline implements Runnable - { + private static class PrepPipeline implements Runnable { private final EmbeddedPostgres pg; - private final SynchronousQueue nextDatabase = new SynchronousQueue(); + private final SynchronousQueue nextDatabase = new SynchronousQueue<>(); - PrepPipeline(EmbeddedPostgres pg) - { + PrepPipeline(EmbeddedPostgres pg) { this.pg = pg; } - PrepPipeline start() - { + PrepPipeline start() { final ExecutorService service = Executors.newSingleThreadExecutor(r -> { final Thread t = new Thread(r); t.setDaemon(true); @@ -191,8 +181,7 @@ PrepPipeline start() return this; } - DbInfo getNextDb() throws SQLException - { + DbInfo getNextDb() throws SQLException { try { final DbInfo next = nextDatabase.take(); if (next.ex != null) { @@ -206,10 +195,9 @@ DbInfo getNextDb() throws SQLException } @Override - public void run() - { + public void run() { while (true) { - final String newDbName = RandomStringUtils.randomAlphabetic(12).toLowerCase(Locale.ENGLISH); + final String newDbName = RandomStringUtils.secure().nextAlphabetic(12).toLowerCase(Locale.ENGLISH); SQLException failure = null; try { create(pg.getPostgresDatabase(), newDbName, "postgres"); @@ -230,8 +218,8 @@ public void run() } } - private static void create(final DataSource connectDb, final String dbName, final String userName) throws SQLException - { + @SuppressWarnings("SameParameterValue") + private static void create(final DataSource connectDb, final String dbName, final String userName) throws SQLException { if (dbName == null) { throw new IllegalStateException("the database name must not be null!"); } @@ -240,7 +228,7 @@ private static void create(final DataSource connectDb, final String dbName, fina } try (Connection c = connectDb.getConnection(); - PreparedStatement stmt = c.prepareStatement(String.format("CREATE DATABASE %s OWNER %s ENCODING = 'utf8'", dbName, userName))) { + PreparedStatement stmt = c.prepareStatement(String.format("CREATE DATABASE %s OWNER %s ENCODING = 'utf8'", dbName, userName))) { stmt.execute(); } } @@ -275,8 +263,8 @@ public int hashCode() { } } - public static class DbInfo - { + public static class DbInfo { + @SuppressWarnings("unused") public static DbInfo ok(final String dbName, final int port, final String user) { return ok(dbName, port, user, emptyMap()); } diff --git a/src/main/java/io/zonky/test/db/postgres/embedded/ProcessOutputLogger.java b/src/main/java/io/zonky/test/db/postgres/embedded/ProcessOutputLogger.java index 708a685f..009d642b 100644 --- a/src/main/java/io/zonky/test/db/postgres/embedded/ProcessOutputLogger.java +++ b/src/main/java/io/zonky/test/db/postgres/embedded/ProcessOutputLogger.java @@ -1,9 +1,11 @@ /* + * Copyright 2025 Tomas Vanek + * * Licensed 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 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -11,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package io.zonky.test.db.postgres.embedded; import org.slf4j.Logger; @@ -70,16 +73,17 @@ static void logOutput(final Logger logger, final Process process, final String p t.start(); } + @SuppressWarnings({"PMD.AvoidAccessibilityAlteration", "PMD.AvoidCatchingGenericException", "PMD.AvoidCatchingThrowable", "JavaLangInvokeHandleSignature"}) private static String processId(Process process) { try { // java 9+ return String.format("pid(%s)", MethodHandles.lookup().findVirtual(Process.class, "pid", MethodType.methodType(long.class)).invoke(process)); - } catch (Throwable ignored) {} // NOPMD since MethodHandles.invoke throws Throwable + } catch (Throwable ignored) {} try { // openjdk / oraclejdk 8 final Field pid = process.getClass().getDeclaredField("pid"); pid.setAccessible(true); return String.format("pid(%s)", pid.getInt(process)); - } catch (Exception ignored) {} // NOPMD + } catch (Exception ignored) {} return String.format("id(%s)", process.hashCode()); } diff --git a/src/main/java/io/zonky/test/db/postgres/junit/EmbeddedPostgresRules.java b/src/main/java/io/zonky/test/db/postgres/junit/EmbeddedPostgresRules.java index dd31423d..c1824d4b 100644 --- a/src/main/java/io/zonky/test/db/postgres/junit/EmbeddedPostgresRules.java +++ b/src/main/java/io/zonky/test/db/postgres/junit/EmbeddedPostgresRules.java @@ -1,9 +1,11 @@ /* + * Copyright 2025 Tomas Vanek + * * Licensed 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 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -11,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package io.zonky.test.db.postgres.junit; import io.zonky.test.db.postgres.embedded.DatabasePreparer; import org.junit.rules.TestRule; public final class EmbeddedPostgresRules { - private EmbeddedPostgresRules() { - } + private EmbeddedPostgresRules() {} /** * Create a vanilla Postgres cluster -- just initialized, no customizations applied. @@ -31,8 +33,7 @@ public static SingleInstancePostgresRule singleInstance() { * Returns a {@link TestRule} to create a Postgres cluster, shared amongst all test cases in this JVM. * The rule contributes Config switches to configure each test case to get its own database. */ - public static PreparedDbRule preparedDatabase(DatabasePreparer preparer) - { + public static PreparedDbRule preparedDatabase(DatabasePreparer preparer) { return new PreparedDbRule(preparer); } } diff --git a/src/main/java/io/zonky/test/db/postgres/junit/PreparedDbRule.java b/src/main/java/io/zonky/test/db/postgres/junit/PreparedDbRule.java index 9fc2b671..8c139dbb 100644 --- a/src/main/java/io/zonky/test/db/postgres/junit/PreparedDbRule.java +++ b/src/main/java/io/zonky/test/db/postgres/junit/PreparedDbRule.java @@ -1,9 +1,11 @@ /* + * Copyright 2025 Tomas Vanek + * * Licensed 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 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -11,13 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.zonky.test.db.postgres.junit; - -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.function.Consumer; -import javax.sql.DataSource; +package io.zonky.test.db.postgres.junit; import io.zonky.test.db.postgres.embedded.ConnectionInfo; import io.zonky.test.db.postgres.embedded.DatabasePreparer; @@ -25,6 +22,11 @@ import io.zonky.test.db.postgres.embedded.PreparedDbProvider; import org.junit.rules.ExternalResource; +import javax.sql.DataSource; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.function.Consumer; + public class PreparedDbRule extends ExternalResource { private final DatabasePreparer preparer; @@ -56,6 +58,7 @@ protected void before() throws Throwable { dataSource = provider.createDataSourceFromConnectionInfo(connectionInfo); } + @SuppressWarnings("PMD.NullAssignment") @Override protected void after() { dataSource = null; @@ -64,9 +67,9 @@ protected void after() { } public DataSource getTestDatabase() { - if (dataSource == null) { - throw new AssertionError("not initialized"); - } + if (dataSource == null) { + throw new AssertionError("not initialized"); + } return dataSource; } diff --git a/src/main/java/io/zonky/test/db/postgres/junit/SingleInstancePostgresRule.java b/src/main/java/io/zonky/test/db/postgres/junit/SingleInstancePostgresRule.java index ea2bb5d7..02d4b2a7 100644 --- a/src/main/java/io/zonky/test/db/postgres/junit/SingleInstancePostgresRule.java +++ b/src/main/java/io/zonky/test/db/postgres/junit/SingleInstancePostgresRule.java @@ -1,9 +1,11 @@ /* + * Copyright 2025 Tomas Vanek + * * Licensed 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 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -11,8 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package io.zonky.test.db.postgres.junit; +import io.zonky.test.db.postgres.embedded.EmbeddedPostgres; +import org.junit.rules.ExternalResource; + import java.io.IOException; import java.sql.Connection; import java.sql.SQLException; @@ -20,20 +26,15 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Consumer; -import io.zonky.test.db.postgres.embedded.EmbeddedPostgres; -import org.junit.rules.ExternalResource; - -public class SingleInstancePostgresRule extends ExternalResource -{ +public class SingleInstancePostgresRule extends ExternalResource { private volatile EmbeddedPostgres epg; private volatile Connection postgresConnection; private final List> builderCustomizers = new CopyOnWriteArrayList<>(); - SingleInstancePostgresRule() { } + SingleInstancePostgresRule() {} @Override - protected void before() throws Throwable - { + protected void before() throws Throwable { super.before(); epg = pg(); postgresConnection = epg.getPostgresDatabase().getConnection(); @@ -45,6 +46,7 @@ private EmbeddedPostgres pg() throws IOException { return builder.start(); } + @SuppressWarnings("unused") public SingleInstancePostgresRule customize(Consumer customizer) { if (epg != null) { throw new AssertionError("already started"); @@ -53,8 +55,7 @@ public SingleInstancePostgresRule customize(Consumer c return this; } - public EmbeddedPostgres getEmbeddedPostgres() - { + public EmbeddedPostgres getEmbeddedPostgres() { EmbeddedPostgres epg = this.epg; if (epg == null) { throw new AssertionError("JUnit test not started yet!"); @@ -63,8 +64,7 @@ public EmbeddedPostgres getEmbeddedPostgres() } @Override - protected void after() - { + protected void after() { try { postgresConnection.close(); } catch (SQLException e) { diff --git a/src/main/java/io/zonky/test/db/postgres/junit5/EmbeddedPostgresExtension.java b/src/main/java/io/zonky/test/db/postgres/junit5/EmbeddedPostgresExtension.java index 2cb49ce0..a75b9ca5 100644 --- a/src/main/java/io/zonky/test/db/postgres/junit5/EmbeddedPostgresExtension.java +++ b/src/main/java/io/zonky/test/db/postgres/junit5/EmbeddedPostgresExtension.java @@ -1,9 +1,11 @@ /* + * Copyright 2025 Tomas Vanek + * * Licensed 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 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -11,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package io.zonky.test.db.postgres.junit5; import io.zonky.test.db.postgres.embedded.DatabasePreparer; @@ -31,8 +34,7 @@ public static SingleInstancePostgresExtension singleInstance() { * Returns a {@link Extension} to create a Postgres cluster, shared amongst all test cases in this JVM. * The rule contributes Config switches to configure each test case to get its own database. */ - public static PreparedDbExtension preparedDatabase(DatabasePreparer preparer) - { + public static PreparedDbExtension preparedDatabase(DatabasePreparer preparer) { return new PreparedDbExtension(preparer); } diff --git a/src/main/java/io/zonky/test/db/postgres/junit5/PreparedDbExtension.java b/src/main/java/io/zonky/test/db/postgres/junit5/PreparedDbExtension.java index 81cf457f..66a5c9f6 100644 --- a/src/main/java/io/zonky/test/db/postgres/junit5/PreparedDbExtension.java +++ b/src/main/java/io/zonky/test/db/postgres/junit5/PreparedDbExtension.java @@ -1,9 +1,11 @@ /* + * Copyright 2025 Tomas Vanek + * * Licensed 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 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -11,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package io.zonky.test.db.postgres.junit5; import io.zonky.test.db.postgres.embedded.ConnectionInfo; @@ -57,6 +60,7 @@ public void beforeAll(ExtensionContext extensionContext) throws Exception { perClass = true; } + @SuppressWarnings("PMD.NullAssignment") @Override public void afterAll(ExtensionContext extensionContext) { dataSource = null; @@ -74,6 +78,7 @@ public void beforeEach(ExtensionContext extensionContext) throws Exception { } } + @SuppressWarnings("PMD.NullAssignment") @Override public void afterEach(ExtensionContext extensionContext) { if (!perClass) { diff --git a/src/main/java/io/zonky/test/db/postgres/junit5/SingleInstancePostgresExtension.java b/src/main/java/io/zonky/test/db/postgres/junit5/SingleInstancePostgresExtension.java index 0b8cc27c..cfa48631 100644 --- a/src/main/java/io/zonky/test/db/postgres/junit5/SingleInstancePostgresExtension.java +++ b/src/main/java/io/zonky/test/db/postgres/junit5/SingleInstancePostgresExtension.java @@ -1,9 +1,11 @@ /* + * Copyright 2025 Tomas Vanek + * * Licensed 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 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -11,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package io.zonky.test.db.postgres.junit5; import io.zonky.test.db.postgres.embedded.EmbeddedPostgres; @@ -31,7 +34,7 @@ public class SingleInstancePostgresExtension implements AfterTestExecutionCallba private volatile Connection postgresConnection; private final List> builderCustomizers = new CopyOnWriteArrayList<>(); - SingleInstancePostgresExtension() { } + SingleInstancePostgresExtension() {} @Override public void beforeTestExecution(ExtensionContext extensionContext) throws Exception { @@ -45,6 +48,7 @@ private EmbeddedPostgres pg() throws IOException { return builder.start(); } + @SuppressWarnings("unused") public SingleInstancePostgresExtension customize(Consumer customizer) { if (epg != null) { throw new AssertionError("already started"); @@ -53,8 +57,7 @@ public SingleInstancePostgresExtension customize(Consumer builder.setConnectConfig("connectTimeout", "20")); @@ -35,7 +52,7 @@ public void test() throws SQLException { assertEquals("20", preparerDataSource.getProperty("connectTimeout")); } - private class CapturingDatabasePreparer implements DatabasePreparer { + private static class CapturingDatabasePreparer implements DatabasePreparer { private DataSource dataSource; diff --git a/src/test/java/io/zonky/test/db/postgres/junit/FlywayPreparerTest.java b/src/test/java/io/zonky/test/db/postgres/junit/FlywayPreparerTest.java index cebb9376..73776e8b 100644 --- a/src/test/java/io/zonky/test/db/postgres/junit/FlywayPreparerTest.java +++ b/src/test/java/io/zonky/test/db/postgres/junit/FlywayPreparerTest.java @@ -1,9 +1,11 @@ /* + * Copyright 2025 Tomas Vanek + * * Licensed 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 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -11,29 +13,31 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package io.zonky.test.db.postgres.junit; -import static org.junit.Assert.assertEquals; +import io.zonky.test.db.postgres.embedded.FlywayPreparer; +import org.junit.Rule; +import org.junit.Test; import java.sql.Connection; import java.sql.ResultSet; import java.sql.Statement; import java.util.Collections; -import io.zonky.test.db.postgres.embedded.FlywayPreparer; -import org.junit.Rule; -import org.junit.Test; +import static org.junit.Assert.assertEquals; public class FlywayPreparerTest { @Rule public PreparedDbRule db = EmbeddedPostgresRules.preparedDatabase(FlywayPreparer.fromConfiguration( Collections.singletonMap("flyway.locations", "db/testing"))); + @SuppressWarnings("SqlNoDataSourceInspection") @Test public void testTablesMade() throws Exception { try (Connection c = db.getTestDatabase().getConnection(); - Statement s = c.createStatement()) { - ResultSet rs = s.executeQuery("SELECT * FROM foo"); + Statement s = c.createStatement(); + ResultSet rs = s.executeQuery("SELECT * FROM foo")) { rs.next(); assertEquals("bar", rs.getString(1)); } diff --git a/src/test/java/io/zonky/test/db/postgres/junit/IsolationTest.java b/src/test/java/io/zonky/test/db/postgres/junit/IsolationTest.java index 7184d23a..898d1171 100644 --- a/src/test/java/io/zonky/test/db/postgres/junit/IsolationTest.java +++ b/src/test/java/io/zonky/test/db/postgres/junit/IsolationTest.java @@ -1,9 +1,11 @@ /* + * Copyright 2025 Tomas Vanek + * * Licensed 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 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -11,17 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package io.zonky.test.db.postgres.junit; +import org.junit.Rule; +import org.junit.Test; + import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; -import org.junit.Rule; -import org.junit.Test; - -public class IsolationTest -{ +public class IsolationTest { @Rule public SingleInstancePostgresRule pg1 = EmbeddedPostgresRules.singleInstance(); @@ -29,8 +31,7 @@ public class IsolationTest public SingleInstancePostgresRule pg2 = EmbeddedPostgresRules.singleInstance(); @Test - public void testIsolation() throws Exception - { + public void testIsolation() throws Exception { try (Connection c = getConnection(pg1)) { makeTable(c); try (Connection c2 = getConnection(pg2)) { @@ -39,14 +40,14 @@ public void testIsolation() throws Exception } } - private void makeTable(Connection c) throws SQLException - { - Statement s = c.createStatement(); - s.execute("CREATE TABLE public.foo (a INTEGER)"); + @SuppressWarnings("SqlNoDataSourceInspection") + private void makeTable(Connection c) throws SQLException { + try (Statement s = c.createStatement()) { + s.execute("CREATE TABLE public.foo (a INTEGER)"); + } } - private Connection getConnection(SingleInstancePostgresRule epg) throws SQLException - { + private Connection getConnection(SingleInstancePostgresRule epg) throws SQLException { return epg.getEmbeddedPostgres().getPostgresDatabase().getConnection(); } } diff --git a/src/test/java/io/zonky/test/db/postgres/junit/LiquibasePreparerClasspathContextTest.java b/src/test/java/io/zonky/test/db/postgres/junit/LiquibasePreparerClasspathContextTest.java index 647a514d..13318560 100644 --- a/src/test/java/io/zonky/test/db/postgres/junit/LiquibasePreparerClasspathContextTest.java +++ b/src/test/java/io/zonky/test/db/postgres/junit/LiquibasePreparerClasspathContextTest.java @@ -1,9 +1,11 @@ /* + * Copyright 2025 Tomas Vanek + * * Licensed 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 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -11,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package io.zonky.test.db.postgres.junit; import io.zonky.test.db.postgres.embedded.LiquibasePreparer; @@ -29,11 +32,12 @@ public class LiquibasePreparerClasspathContextTest { @Rule public PreparedDbRule db = EmbeddedPostgresRules.preparedDatabase(LiquibasePreparer.forClasspathLocation("liqui/master-test.xml", new Contexts("test"))); + @SuppressWarnings("SqlNoDataSourceInspection") @Test public void testEmptyTables() throws Exception { try (Connection c = db.getTestDatabase().getConnection(); - Statement s = c.createStatement()) { - ResultSet rs = s.executeQuery("SELECT COUNT(*) FROM foo"); + Statement s = c.createStatement(); + ResultSet rs = s.executeQuery("SELECT COUNT(*) FROM foo")) { rs.next(); assertEquals(0, rs.getInt(1)); } diff --git a/src/test/java/io/zonky/test/db/postgres/junit/LiquibasePreparerClasspathTest.java b/src/test/java/io/zonky/test/db/postgres/junit/LiquibasePreparerClasspathTest.java index 07156b36..70b88b52 100644 --- a/src/test/java/io/zonky/test/db/postgres/junit/LiquibasePreparerClasspathTest.java +++ b/src/test/java/io/zonky/test/db/postgres/junit/LiquibasePreparerClasspathTest.java @@ -1,9 +1,11 @@ /* + * Copyright 2025 Tomas Vanek + * * Licensed 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 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -11,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package io.zonky.test.db.postgres.junit; import io.zonky.test.db.postgres.embedded.LiquibasePreparer; @@ -28,11 +31,12 @@ public class LiquibasePreparerClasspathTest { @Rule public PreparedDbRule db = EmbeddedPostgresRules.preparedDatabase(LiquibasePreparer.forClasspathLocation("liqui/master.xml")); + @SuppressWarnings("SqlNoDataSourceInspection") @Test public void testTablesMade() throws Exception { try (Connection c = db.getTestDatabase().getConnection(); - Statement s = c.createStatement()) { - ResultSet rs = s.executeQuery("SELECT * FROM foo"); + Statement s = c.createStatement(); + ResultSet rs = s.executeQuery("SELECT * FROM foo")) { rs.next(); assertEquals("bar", rs.getString(1)); } diff --git a/src/test/java/io/zonky/test/db/postgres/junit/LiquibasePreparerFileContextTest.java b/src/test/java/io/zonky/test/db/postgres/junit/LiquibasePreparerFileContextTest.java index f1b38523..52527616 100644 --- a/src/test/java/io/zonky/test/db/postgres/junit/LiquibasePreparerFileContextTest.java +++ b/src/test/java/io/zonky/test/db/postgres/junit/LiquibasePreparerFileContextTest.java @@ -1,9 +1,11 @@ /* + * Copyright 2025 Tomas Vanek + * * Licensed 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 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -11,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package io.zonky.test.db.postgres.junit; import io.zonky.test.db.postgres.embedded.LiquibasePreparer; @@ -30,11 +33,12 @@ public class LiquibasePreparerFileContextTest { @Rule public PreparedDbRule db = EmbeddedPostgresRules.preparedDatabase(LiquibasePreparer.forFile(new File("src/test/resources/liqui/master-test.xml"), new Contexts("test"))); + @SuppressWarnings("SqlNoDataSourceInspection") @Test public void testEmptyTables() throws Exception { try (Connection c = db.getTestDatabase().getConnection(); - Statement s = c.createStatement()) { - ResultSet rs = s.executeQuery("SELECT COUNT(*) FROM foo"); + Statement s = c.createStatement(); + ResultSet rs = s.executeQuery("SELECT COUNT(*) FROM foo")) { rs.next(); assertEquals(0, rs.getInt(1)); } diff --git a/src/test/java/io/zonky/test/db/postgres/junit/LiquibasePreparerFileTest.java b/src/test/java/io/zonky/test/db/postgres/junit/LiquibasePreparerFileTest.java index 233bda84..7d89dc56 100644 --- a/src/test/java/io/zonky/test/db/postgres/junit/LiquibasePreparerFileTest.java +++ b/src/test/java/io/zonky/test/db/postgres/junit/LiquibasePreparerFileTest.java @@ -1,9 +1,11 @@ /* + * Copyright 2025 Tomas Vanek + * * Licensed 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 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -11,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package io.zonky.test.db.postgres.junit; import io.zonky.test.db.postgres.embedded.LiquibasePreparer; @@ -29,11 +32,12 @@ public class LiquibasePreparerFileTest { @Rule public PreparedDbRule db = EmbeddedPostgresRules.preparedDatabase(LiquibasePreparer.forFile(new File("src/test/resources/liqui/master.xml"))); + @SuppressWarnings("SqlNoDataSourceInspection") @Test public void testTablesMade() throws Exception { try (Connection c = db.getTestDatabase().getConnection(); - Statement s = c.createStatement()) { - ResultSet rs = s.executeQuery("SELECT * FROM foo"); + Statement s = c.createStatement(); + ResultSet rs = s.executeQuery("SELECT * FROM foo")) { rs.next(); assertEquals("bar", rs.getString(1)); } diff --git a/src/test/java/io/zonky/test/db/postgres/junit/PreparedDbCustomizerTest.java b/src/test/java/io/zonky/test/db/postgres/junit/PreparedDbCustomizerTest.java index 41c0542c..24407ae0 100644 --- a/src/test/java/io/zonky/test/db/postgres/junit/PreparedDbCustomizerTest.java +++ b/src/test/java/io/zonky/test/db/postgres/junit/PreparedDbCustomizerTest.java @@ -1,9 +1,11 @@ /* + * Copyright 2025 Tomas Vanek + * * Licensed 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 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -11,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package io.zonky.test.db.postgres.junit; import io.zonky.test.db.postgres.embedded.DatabasePreparer; diff --git a/src/test/java/io/zonky/test/db/postgres/junit/PreparedDbTest.java b/src/test/java/io/zonky/test/db/postgres/junit/PreparedDbTest.java index 7b01c181..9f0eb58f 100644 --- a/src/test/java/io/zonky/test/db/postgres/junit/PreparedDbTest.java +++ b/src/test/java/io/zonky/test/db/postgres/junit/PreparedDbTest.java @@ -1,9 +1,11 @@ /* + * Copyright 2025 Tomas Vanek + * * Licensed 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 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -11,18 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.zonky.test.db.postgres.junit; - -import static org.junit.Assert.assertEquals; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - -import javax.sql.DataSource; +package io.zonky.test.db.postgres.junit; import io.zonky.test.db.postgres.embedded.ConnectionInfo; import io.zonky.test.db.postgres.embedded.DatabaseConnectionPreparer; @@ -30,6 +22,11 @@ import org.junit.Rule; import org.junit.Test; +import javax.sql.DataSource; +import java.sql.*; + +import static org.junit.Assert.assertEquals; + public class PreparedDbTest { private final DatabasePreparer prepA = new SimplePreparer("a"); @@ -42,6 +39,7 @@ public class PreparedDbTest { @Rule public PreparedDbRule dbB1 = EmbeddedPostgresRules.preparedDatabase(prepB); + @SuppressWarnings("SqlNoDataSourceInspection") @Test public void testDbs() throws Exception { try (Connection c = dbA1.getTestDatabase().getConnection(); @@ -49,8 +47,8 @@ public void testDbs() throws Exception { commonAssertion(stmt); } try (Connection c = dbA2.getTestDatabase().getConnection(); - PreparedStatement stmt = c.prepareStatement("SELECT count(1) FROM a")) { - ResultSet rs = stmt.executeQuery(); + PreparedStatement stmt = c.prepareStatement("SELECT count(1) FROM a"); + ResultSet rs = stmt.executeQuery()) { rs.next(); assertEquals(0, rs.getInt(1)); } @@ -60,11 +58,13 @@ public void testDbs() throws Exception { } } + @SuppressWarnings("SqlNoDataSourceInspection") private void commonAssertion(final Statement stmt) throws SQLException { stmt.execute("INSERT INTO a VALUES(1)"); - ResultSet rs = stmt.executeQuery("SELECT COUNT(1) FROM a"); - rs.next(); - assertEquals(1, rs.getInt(1)); + try (ResultSet rs = stmt.executeQuery("SELECT COUNT(1) FROM a")) { + rs.next(); + assertEquals(1, rs.getInt(1)); + } } @Test @@ -80,7 +80,7 @@ public void testEquivalentAccess() throws SQLException { @Test public void testDbUri() throws Exception { try (Connection c = DriverManager.getConnection(dbA1.getDbProvider().createDatabase()); - Statement stmt = c.createStatement()) { + Statement stmt = c.createStatement()) { commonAssertion(stmt); } } diff --git a/src/test/java/io/zonky/test/db/postgres/junit/SingleInstanceRuleTest.java b/src/test/java/io/zonky/test/db/postgres/junit/SingleInstanceRuleTest.java index d8ec7f21..cd5a79fe 100644 --- a/src/test/java/io/zonky/test/db/postgres/junit/SingleInstanceRuleTest.java +++ b/src/test/java/io/zonky/test/db/postgres/junit/SingleInstanceRuleTest.java @@ -1,9 +1,11 @@ /* + * Copyright 2025 Tomas Vanek + * * Licensed 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 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -11,29 +13,28 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package io.zonky.test.db.postgres.junit; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import org.junit.Rule; +import org.junit.Test; import java.sql.Connection; import java.sql.ResultSet; import java.sql.Statement; -import org.junit.Rule; -import org.junit.Test; +import static org.junit.Assert.*; -public class SingleInstanceRuleTest -{ +public class SingleInstanceRuleTest { @Rule public SingleInstancePostgresRule epg = EmbeddedPostgresRules.singleInstance(); + @SuppressWarnings("SqlNoDataSourceInspection") @Test public void testRule() throws Exception { - try (Connection c = epg.getEmbeddedPostgres().getPostgresDatabase().getConnection()) { - Statement s = c.createStatement(); - ResultSet rs = s.executeQuery("SELECT 1"); + try (Connection c = epg.getEmbeddedPostgres().getPostgresDatabase().getConnection(); + Statement s = c.createStatement(); + ResultSet rs = s.executeQuery("SELECT 1")) { assertTrue(rs.next()); assertEquals(1, rs.getInt(1)); assertFalse(rs.next()); diff --git a/src/test/java/io/zonky/test/db/postgres/junit5/ConnectConfigTest.java b/src/test/java/io/zonky/test/db/postgres/junit5/ConnectConfigTest.java index 62e7865d..7df570c6 100644 --- a/src/test/java/io/zonky/test/db/postgres/junit5/ConnectConfigTest.java +++ b/src/test/java/io/zonky/test/db/postgres/junit5/ConnectConfigTest.java @@ -1,3 +1,19 @@ +/* + * Copyright 2025 Tomas Vanek + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package io.zonky.test.db.postgres.junit5; import io.zonky.test.db.postgres.embedded.ConnectionInfo; @@ -12,16 +28,17 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -public class ConnectConfigTest { +class ConnectConfigTest { private final CapturingDatabasePreparer preparer = new CapturingDatabasePreparer(); + @SuppressWarnings({"PMD.AvoidDuplicateLiterals", "JUnitMalformedDeclaration"}) @RegisterExtension - public PreparedDbExtension db = EmbeddedPostgresExtension.preparedDatabase(preparer) + PreparedDbExtension db = EmbeddedPostgresExtension.preparedDatabase(preparer) .customize(builder -> builder.setConnectConfig("connectTimeout", "20")); @Test - public void test() throws SQLException { + void test() throws SQLException { ConnectionInfo connectionInfo = db.getConnectionInfo(); Map properties = connectionInfo.getProperties(); @@ -35,7 +52,7 @@ public void test() throws SQLException { assertEquals("20", preparerDataSource.getProperty("connectTimeout")); } - private class CapturingDatabasePreparer implements DatabasePreparer { + private static class CapturingDatabasePreparer implements DatabasePreparer { private DataSource dataSource; diff --git a/src/test/java/io/zonky/test/db/postgres/junit5/DatabaseLifecycleTest.java b/src/test/java/io/zonky/test/db/postgres/junit5/DatabaseLifecycleTest.java index a37eff69..48fb1bed 100644 --- a/src/test/java/io/zonky/test/db/postgres/junit5/DatabaseLifecycleTest.java +++ b/src/test/java/io/zonky/test/db/postgres/junit5/DatabaseLifecycleTest.java @@ -1,3 +1,19 @@ +/* + * Copyright 2025 Tomas Vanek + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package io.zonky.test.db.postgres.junit5; import org.junit.jupiter.api.MethodOrderer.OrderAnnotation; @@ -15,52 +31,48 @@ import static org.junit.jupiter.api.Assertions.assertTrue; @TestMethodOrder(OrderAnnotation.class) -public class DatabaseLifecycleTest { +class DatabaseLifecycleTest { @RegisterExtension - public static PreparedDbExtension staticExtension = EmbeddedPostgresExtension.preparedDatabase(ds -> {}); + static PreparedDbExtension staticExtension = EmbeddedPostgresExtension.preparedDatabase(ds -> {}); + @SuppressWarnings("JUnitMalformedDeclaration") @RegisterExtension - public PreparedDbExtension instanceExtension = EmbeddedPostgresExtension.preparedDatabase(ds -> {}); + PreparedDbExtension instanceExtension = EmbeddedPostgresExtension.preparedDatabase(ds -> {}); @Test @Order(1) - public void testCreate1() throws Exception - { + void testCreate1() throws Exception { createTable(staticExtension, "table1"); createTable(instanceExtension, "table2"); } @Test @Order(2) - public void testCreate2() throws Exception - { + void testCreate2() throws Exception { assertTrue(existsTable(staticExtension, "table1")); assertFalse(existsTable(instanceExtension, "table2")); } @Test @Order(3) - public void testCreate3() throws Exception - { + void testCreate3() throws Exception { assertTrue(existsTable(staticExtension, "table1")); assertFalse(existsTable(instanceExtension, "table2")); } - private void createTable(PreparedDbExtension extension, String table) throws SQLException - { + private void createTable(PreparedDbExtension extension, String table) throws SQLException { try (Connection connection = extension.getTestDatabase().getConnection(); - Statement statement = connection.createStatement()) { + Statement statement = connection.createStatement()) { statement.execute(String.format("CREATE TABLE public.%s (a INTEGER)", table)); } } - private boolean existsTable(PreparedDbExtension extension, String table) throws SQLException - { + private boolean existsTable(PreparedDbExtension extension, String table) throws SQLException { + String query = String.format("SELECT EXISTS (SELECT FROM information_schema.tables WHERE table_schema = 'public' AND table_name = '%s')", table); try (Connection connection = extension.getTestDatabase().getConnection(); - Statement statement = connection.createStatement()) { - String query = String.format("SELECT EXISTS (SELECT FROM information_schema.tables WHERE table_schema = 'public' AND table_name = '%s')", table); - ResultSet resultSet = statement.executeQuery(query); + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery(query)) { resultSet.next(); return resultSet.getBoolean(1); } diff --git a/src/test/java/io/zonky/test/db/postgres/junit5/FlywayPreparerTest.java b/src/test/java/io/zonky/test/db/postgres/junit5/FlywayPreparerTest.java index c5aa84b1..a02080f0 100644 --- a/src/test/java/io/zonky/test/db/postgres/junit5/FlywayPreparerTest.java +++ b/src/test/java/io/zonky/test/db/postgres/junit5/FlywayPreparerTest.java @@ -1,9 +1,11 @@ /* + * Copyright 2025 Tomas Vanek + * * Licensed 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 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -11,27 +13,30 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package io.zonky.test.db.postgres.junit5; -import static org.junit.jupiter.api.Assertions.assertEquals; +import io.zonky.test.db.postgres.embedded.FlywayPreparer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; import java.sql.Connection; import java.sql.ResultSet; import java.sql.Statement; -import io.zonky.test.db.postgres.embedded.FlywayPreparer; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; +import static org.junit.jupiter.api.Assertions.assertEquals; -public class FlywayPreparerTest { +class FlywayPreparerTest { + @SuppressWarnings("JUnitMalformedDeclaration") @RegisterExtension - public PreparedDbExtension db = EmbeddedPostgresExtension.preparedDatabase(FlywayPreparer.forClasspathLocation("db/testing")); + PreparedDbExtension db = EmbeddedPostgresExtension.preparedDatabase(FlywayPreparer.forClasspathLocation("db/testing")); + @SuppressWarnings("SqlNoDataSourceInspection") @Test - public void testTablesMade() throws Exception { + void testTablesMade() throws Exception { try (Connection c = db.getTestDatabase().getConnection(); - Statement s = c.createStatement()) { - ResultSet rs = s.executeQuery("SELECT * FROM foo"); + Statement s = c.createStatement(); + ResultSet rs = s.executeQuery("SELECT * FROM foo")) { rs.next(); assertEquals("bar", rs.getString(1)); } diff --git a/src/test/java/io/zonky/test/db/postgres/junit5/IsolationTest.java b/src/test/java/io/zonky/test/db/postgres/junit5/IsolationTest.java index afe4d606..a5eb765f 100644 --- a/src/test/java/io/zonky/test/db/postgres/junit5/IsolationTest.java +++ b/src/test/java/io/zonky/test/db/postgres/junit5/IsolationTest.java @@ -1,9 +1,11 @@ /* + * Copyright 2025 Tomas Vanek + * * Licensed 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 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -11,26 +13,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package io.zonky.test.db.postgres.junit5; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; - -public class IsolationTest -{ +class IsolationTest { @RegisterExtension - public SingleInstancePostgresExtension pg1 = EmbeddedPostgresExtension.singleInstance(); + SingleInstancePostgresExtension pg1 = EmbeddedPostgresExtension.singleInstance(); @RegisterExtension - public SingleInstancePostgresExtension pg2 = EmbeddedPostgresExtension.singleInstance(); + SingleInstancePostgresExtension pg2 = EmbeddedPostgresExtension.singleInstance(); @Test - public void testIsolation() throws Exception - { + void testIsolation() throws Exception { try (Connection c = getConnection(pg1)) { makeTable(c); try (Connection c2 = getConnection(pg2)) { @@ -39,14 +40,14 @@ public void testIsolation() throws Exception } } - private void makeTable(Connection c) throws SQLException - { - Statement s = c.createStatement(); - s.execute("CREATE TABLE public.foo (a INTEGER)"); + @SuppressWarnings("SqlNoDataSourceInspection") + private void makeTable(Connection c) throws SQLException { + try (Statement s = c.createStatement()) { + s.execute("CREATE TABLE public.foo (a INTEGER)"); + } } - private Connection getConnection(SingleInstancePostgresExtension epg) throws SQLException - { + private Connection getConnection(SingleInstancePostgresExtension epg) throws SQLException { return epg.getEmbeddedPostgres().getPostgresDatabase().getConnection(); } } diff --git a/src/test/java/io/zonky/test/db/postgres/junit5/LiquibasePreparerClasspathContextTest.java b/src/test/java/io/zonky/test/db/postgres/junit5/LiquibasePreparerClasspathContextTest.java index 436b64e8..56102660 100644 --- a/src/test/java/io/zonky/test/db/postgres/junit5/LiquibasePreparerClasspathContextTest.java +++ b/src/test/java/io/zonky/test/db/postgres/junit5/LiquibasePreparerClasspathContextTest.java @@ -1,9 +1,11 @@ /* + * Copyright 2025 Tomas Vanek + * * Licensed 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 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -11,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package io.zonky.test.db.postgres.junit5; import io.zonky.test.db.postgres.embedded.LiquibasePreparer; @@ -24,16 +27,18 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -public class LiquibasePreparerClasspathContextTest { +class LiquibasePreparerClasspathContextTest { + @SuppressWarnings("JUnitMalformedDeclaration") @RegisterExtension - public PreparedDbExtension db = EmbeddedPostgresExtension.preparedDatabase(LiquibasePreparer.forClasspathLocation("liqui/master-test.xml", new Contexts("test"))); + PreparedDbExtension db = EmbeddedPostgresExtension.preparedDatabase(LiquibasePreparer.forClasspathLocation("liqui/master-test.xml", new Contexts("test"))); + @SuppressWarnings("SqlNoDataSourceInspection") @Test - public void testEmptyTables() throws Exception { + void testEmptyTables() throws Exception { try (Connection c = db.getTestDatabase().getConnection(); - Statement s = c.createStatement()) { - ResultSet rs = s.executeQuery("SELECT COUNT(*) FROM foo"); + Statement s = c.createStatement(); + ResultSet rs = s.executeQuery("SELECT COUNT(*) FROM foo")) { rs.next(); assertEquals(0, rs.getInt(1)); } diff --git a/src/test/java/io/zonky/test/db/postgres/junit5/LiquibasePreparerClasspathTest.java b/src/test/java/io/zonky/test/db/postgres/junit5/LiquibasePreparerClasspathTest.java index 1319ee81..f51dfb77 100644 --- a/src/test/java/io/zonky/test/db/postgres/junit5/LiquibasePreparerClasspathTest.java +++ b/src/test/java/io/zonky/test/db/postgres/junit5/LiquibasePreparerClasspathTest.java @@ -1,9 +1,11 @@ /* + * Copyright 2025 Tomas Vanek + * * Licensed 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 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -11,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package io.zonky.test.db.postgres.junit5; import io.zonky.test.db.postgres.embedded.LiquibasePreparer; @@ -23,16 +26,18 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -public class LiquibasePreparerClasspathTest { +class LiquibasePreparerClasspathTest { + @SuppressWarnings("JUnitMalformedDeclaration") @RegisterExtension - public PreparedDbExtension db = EmbeddedPostgresExtension.preparedDatabase(LiquibasePreparer.forClasspathLocation("liqui/master.xml")); + PreparedDbExtension db = EmbeddedPostgresExtension.preparedDatabase(LiquibasePreparer.forClasspathLocation("liqui/master.xml")); + @SuppressWarnings("SqlNoDataSourceInspection") @Test - public void testTablesMade() throws Exception { + void testTablesMade() throws Exception { try (Connection c = db.getTestDatabase().getConnection(); - Statement s = c.createStatement()) { - ResultSet rs = s.executeQuery("SELECT * FROM foo"); + Statement s = c.createStatement(); + ResultSet rs = s.executeQuery("SELECT * FROM foo")) { rs.next(); assertEquals("bar", rs.getString(1)); } diff --git a/src/test/java/io/zonky/test/db/postgres/junit5/LiquibasePreparerFileContextTest.java b/src/test/java/io/zonky/test/db/postgres/junit5/LiquibasePreparerFileContextTest.java index 837792bd..c03f07d6 100644 --- a/src/test/java/io/zonky/test/db/postgres/junit5/LiquibasePreparerFileContextTest.java +++ b/src/test/java/io/zonky/test/db/postgres/junit5/LiquibasePreparerFileContextTest.java @@ -1,9 +1,11 @@ /* + * Copyright 2025 Tomas Vanek + * * Licensed 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 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -11,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package io.zonky.test.db.postgres.junit5; import io.zonky.test.db.postgres.embedded.LiquibasePreparer; @@ -25,16 +28,18 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -public class LiquibasePreparerFileContextTest { +class LiquibasePreparerFileContextTest { + @SuppressWarnings("JUnitMalformedDeclaration") @RegisterExtension - public PreparedDbExtension db = EmbeddedPostgresExtension.preparedDatabase(LiquibasePreparer.forFile(new File("src/test/resources/liqui/master-test.xml"), new Contexts("test"))); + PreparedDbExtension db = EmbeddedPostgresExtension.preparedDatabase(LiquibasePreparer.forFile(new File("src/test/resources/liqui/master-test.xml"), new Contexts("test"))); + @SuppressWarnings("SqlNoDataSourceInspection") @Test - public void testEmptyTables() throws Exception { + void testEmptyTables() throws Exception { try (Connection c = db.getTestDatabase().getConnection(); - Statement s = c.createStatement()) { - ResultSet rs = s.executeQuery("SELECT COUNT(*) FROM foo"); + Statement s = c.createStatement(); + ResultSet rs = s.executeQuery("SELECT COUNT(*) FROM foo")) { rs.next(); assertEquals(0, rs.getInt(1)); } diff --git a/src/test/java/io/zonky/test/db/postgres/junit5/LiquibasePreparerFileTest.java b/src/test/java/io/zonky/test/db/postgres/junit5/LiquibasePreparerFileTest.java index 8c0c5378..1440a1e4 100644 --- a/src/test/java/io/zonky/test/db/postgres/junit5/LiquibasePreparerFileTest.java +++ b/src/test/java/io/zonky/test/db/postgres/junit5/LiquibasePreparerFileTest.java @@ -1,9 +1,11 @@ /* + * Copyright 2025 Tomas Vanek + * * Licensed 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 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -11,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package io.zonky.test.db.postgres.junit5; import io.zonky.test.db.postgres.embedded.LiquibasePreparer; @@ -24,16 +27,18 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -public class LiquibasePreparerFileTest { +class LiquibasePreparerFileTest { + @SuppressWarnings("JUnitMalformedDeclaration") @RegisterExtension public PreparedDbExtension db = EmbeddedPostgresExtension.preparedDatabase(LiquibasePreparer.forFile(new File("src/test/resources/liqui/master.xml"))); + @SuppressWarnings("SqlNoDataSourceInspection") @Test - public void testTablesMade() throws Exception { + void testTablesMade() throws Exception { try (Connection c = db.getTestDatabase().getConnection(); - Statement s = c.createStatement()) { - ResultSet rs = s.executeQuery("SELECT * FROM foo"); + Statement s = c.createStatement(); + ResultSet rs = s.executeQuery("SELECT * FROM foo")) { rs.next(); assertEquals("bar", rs.getString(1)); } diff --git a/src/test/java/io/zonky/test/db/postgres/junit5/PreparedDbCustomizerTest.java b/src/test/java/io/zonky/test/db/postgres/junit5/PreparedDbCustomizerTest.java index a5b9bdfa..1aa01927 100644 --- a/src/test/java/io/zonky/test/db/postgres/junit5/PreparedDbCustomizerTest.java +++ b/src/test/java/io/zonky/test/db/postgres/junit5/PreparedDbCustomizerTest.java @@ -1,9 +1,11 @@ /* + * Copyright 2025 Tomas Vanek + * * Licensed 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 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -11,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package io.zonky.test.db.postgres.junit5; import io.zonky.test.db.postgres.embedded.DatabasePreparer; @@ -22,23 +25,28 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; -public class PreparedDbCustomizerTest { +class PreparedDbCustomizerTest { private static final DatabasePreparer EMPTY_PREPARER = ds -> {}; + @SuppressWarnings({"JUnitMalformedDeclaration", "PMD.AvoidDuplicateLiterals"}) @RegisterExtension - public PreparedDbExtension dbA1 = EmbeddedPostgresExtension.preparedDatabase(EMPTY_PREPARER); + PreparedDbExtension dbA1 = EmbeddedPostgresExtension.preparedDatabase(EMPTY_PREPARER); + @SuppressWarnings("JUnitMalformedDeclaration") @RegisterExtension - public PreparedDbExtension dbA2 = EmbeddedPostgresExtension.preparedDatabase(EMPTY_PREPARER).customize(builder -> {}); + PreparedDbExtension dbA2 = EmbeddedPostgresExtension.preparedDatabase(EMPTY_PREPARER).customize(builder -> {}); + @SuppressWarnings("JUnitMalformedDeclaration") @RegisterExtension - public PreparedDbExtension dbA3 = EmbeddedPostgresExtension.preparedDatabase(EMPTY_PREPARER).customize(builder -> builder.setPGStartupWait(Duration.ofSeconds(10))); + PreparedDbExtension dbA3 = EmbeddedPostgresExtension.preparedDatabase(EMPTY_PREPARER).customize(builder -> builder.setPGStartupWait(Duration.ofSeconds(10))); + @SuppressWarnings("JUnitMalformedDeclaration") @RegisterExtension - public PreparedDbExtension dbB1 = EmbeddedPostgresExtension.preparedDatabase(EMPTY_PREPARER).customize(builder -> builder.setPGStartupWait(Duration.ofSeconds(11))); + PreparedDbExtension dbB1 = EmbeddedPostgresExtension.preparedDatabase(EMPTY_PREPARER).customize(builder -> builder.setPGStartupWait(Duration.ofSeconds(11))); + @SuppressWarnings("JUnitMalformedDeclaration") @RegisterExtension - public PreparedDbExtension dbB2 = EmbeddedPostgresExtension.preparedDatabase(EMPTY_PREPARER).customize(builder -> builder.setPGStartupWait(Duration.ofSeconds(11))); + PreparedDbExtension dbB2 = EmbeddedPostgresExtension.preparedDatabase(EMPTY_PREPARER).customize(builder -> builder.setPGStartupWait(Duration.ofSeconds(11))); @Test - public void testCustomizers() { + void testCustomizers() { int dbA1Port = dbA1.getConnectionInfo().getPort(); int dbA2Port = dbA2.getConnectionInfo().getPort(); int dbA3Port = dbA3.getConnectionInfo().getPort(); diff --git a/src/test/java/io/zonky/test/db/postgres/junit5/PreparedDbTest.java b/src/test/java/io/zonky/test/db/postgres/junit5/PreparedDbTest.java index c4a75409..6174f793 100644 --- a/src/test/java/io/zonky/test/db/postgres/junit5/PreparedDbTest.java +++ b/src/test/java/io/zonky/test/db/postgres/junit5/PreparedDbTest.java @@ -1,9 +1,11 @@ /* + * Copyright 2025 Tomas Vanek + * * Licensed 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 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -11,18 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.zonky.test.db.postgres.junit5; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - -import javax.sql.DataSource; +package io.zonky.test.db.postgres.junit5; import io.zonky.test.db.postgres.embedded.ConnectionInfo; import io.zonky.test.db.postgres.embedded.DatabaseConnectionPreparer; @@ -30,27 +22,36 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; -public class PreparedDbTest { +import javax.sql.DataSource; +import java.sql.*; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class PreparedDbTest { private final DatabasePreparer prepA = new SimplePreparer("a"); private final DatabasePreparer prepB = new SimplePreparer("b"); + @SuppressWarnings("JUnitMalformedDeclaration") @RegisterExtension - public PreparedDbExtension dbA1 = EmbeddedPostgresExtension.preparedDatabase(prepA); + PreparedDbExtension dbA1 = EmbeddedPostgresExtension.preparedDatabase(prepA); + @SuppressWarnings("JUnitMalformedDeclaration") @RegisterExtension - public PreparedDbExtension dbA2 = EmbeddedPostgresExtension.preparedDatabase(prepA); + PreparedDbExtension dbA2 = EmbeddedPostgresExtension.preparedDatabase(prepA); + @SuppressWarnings("JUnitMalformedDeclaration") @RegisterExtension - public PreparedDbExtension dbB1 = EmbeddedPostgresExtension.preparedDatabase(prepB); + PreparedDbExtension dbB1 = EmbeddedPostgresExtension.preparedDatabase(prepB); + @SuppressWarnings("SqlNoDataSourceInspection") @Test - public void testDbs() throws Exception { + void testDbs() throws Exception { try (Connection c = dbA1.getTestDatabase().getConnection(); Statement stmt = c.createStatement()) { commonAssertion(stmt); } try (Connection c = dbA2.getTestDatabase().getConnection(); - PreparedStatement stmt = c.prepareStatement("SELECT count(1) FROM a")) { - ResultSet rs = stmt.executeQuery(); + PreparedStatement stmt = c.prepareStatement("SELECT count(1) FROM a"); + ResultSet rs = stmt.executeQuery()) { rs.next(); assertEquals(0, rs.getInt(1)); } @@ -60,15 +61,17 @@ public void testDbs() throws Exception { } } + @SuppressWarnings("SqlNoDataSourceInspection") private void commonAssertion(final Statement stmt) throws SQLException { stmt.execute("INSERT INTO a VALUES(1)"); - ResultSet rs = stmt.executeQuery("SELECT COUNT(1) FROM a"); - rs.next(); - assertEquals(1, rs.getInt(1)); + try (ResultSet rs = stmt.executeQuery("SELECT COUNT(1) FROM a")) { + rs.next(); + assertEquals(1, rs.getInt(1)); + } } @Test - public void testEquivalentAccess() throws SQLException { + void testEquivalentAccess() throws SQLException { ConnectionInfo dbInfo = dbA1.getConnectionInfo(); DataSource dataSource = dbA1.getTestDatabase(); try (Connection c = dataSource.getConnection(); Statement stmt = c.createStatement()) { @@ -78,9 +81,9 @@ public void testEquivalentAccess() throws SQLException { } @Test - public void testDbUri() throws Exception { + void testDbUri() throws Exception { try (Connection c = DriverManager.getConnection(dbA1.getDbProvider().createDatabase()); - Statement stmt = c.createStatement()) { + Statement stmt = c.createStatement()) { commonAssertion(stmt); } } diff --git a/src/test/java/io/zonky/test/db/postgres/junit5/SingleInstanceRuleTest.java b/src/test/java/io/zonky/test/db/postgres/junit5/SingleInstanceRuleTest.java index 1df4c0f7..6e297d6c 100644 --- a/src/test/java/io/zonky/test/db/postgres/junit5/SingleInstanceRuleTest.java +++ b/src/test/java/io/zonky/test/db/postgres/junit5/SingleInstanceRuleTest.java @@ -1,9 +1,11 @@ /* + * Copyright 2025 Tomas Vanek + * * Licensed 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 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -11,29 +13,28 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package io.zonky.test.db.postgres.junit5; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; import java.sql.Connection; import java.sql.ResultSet; import java.sql.Statement; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; +import static org.junit.jupiter.api.Assertions.*; -public class SingleInstanceRuleTest -{ +class SingleInstanceRuleTest { @RegisterExtension - public SingleInstancePostgresExtension epg = EmbeddedPostgresExtension.singleInstance(); + SingleInstancePostgresExtension epg = EmbeddedPostgresExtension.singleInstance(); + @SuppressWarnings("SqlNoDataSourceInspection") @Test - public void testRule() throws Exception { - try (Connection c = epg.getEmbeddedPostgres().getPostgresDatabase().getConnection()) { - Statement s = c.createStatement(); - ResultSet rs = s.executeQuery("SELECT 1"); + void testRule() throws Exception { + try (Connection c = epg.getEmbeddedPostgres().getPostgresDatabase().getConnection(); + Statement s = c.createStatement(); + ResultSet rs = s.executeQuery("SELECT 1")) { assertTrue(rs.next()); assertEquals(1, rs.getInt(1)); assertFalse(rs.next()); diff --git a/src/test/resources/liqui/master-test.xml b/src/test/resources/liqui/master-test.xml index 3670a29b..7871dd78 100644 --- a/src/test/resources/liqui/master-test.xml +++ b/src/test/resources/liqui/master-test.xml @@ -15,7 +15,7 @@ + xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd"> @@ -26,6 +26,7 @@ Fill `foo` table + INSERT INTO foo VALUES('bar'); diff --git a/src/test/resources/liqui/master.xml b/src/test/resources/liqui/master.xml index d82881b6..cc34a074 100644 --- a/src/test/resources/liqui/master.xml +++ b/src/test/resources/liqui/master.xml @@ -15,7 +15,7 @@ + xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd"> @@ -23,6 +23,7 @@ Create table `foo` + CREATE TABLE foo (test VARCHAR); @@ -30,6 +31,7 @@ Fill `foo` table + INSERT INTO foo VALUES('bar'); diff --git a/src/test/resources/simplelogger.properties b/src/test/resources/simplelogger.properties index 6dfc7aa3..e4595c26 100644 --- a/src/test/resources/simplelogger.properties +++ b/src/test/resources/simplelogger.properties @@ -1 +1 @@ -org.slf4j.simpleLogger.showDateTime=true \ No newline at end of file +org.slf4j.simpleLogger.showDateTime = true \ No newline at end of file From 4a9e3e20ff8769dc9d7b5f6b3fafeffc95c3305a Mon Sep 17 00:00:00 2001 From: Nikan Radan Date: Fri, 7 Nov 2025 22:34:14 -0800 Subject: [PATCH 2/3] Delete Static Analysis Files (oops) --- .PVS-Studio/ide-warnings.json | 144 ---------------------------------- .PVS-Studio/settings.json | 46 ----------- 2 files changed, 190 deletions(-) delete mode 100644 .PVS-Studio/ide-warnings.json delete mode 100644 .PVS-Studio/settings.json diff --git a/.PVS-Studio/ide-warnings.json b/.PVS-Studio/ide-warnings.json deleted file mode 100644 index 2f171482..00000000 --- a/.PVS-Studio/ide-warnings.json +++ /dev/null @@ -1,144 +0,0 @@ -{ - "languages": { - "JAVA": { - "groups": { - "OWASP": "DISABLED", - "GA": "SHOW_ALL" - } - } - }, - "warnings": { - "V6027": true, - "V6026": true, - "V6029": true, - "V6028": true, - "V6023": true, - "V6022": true, - "V6025": true, - "V6024": true, - "V6021": true, - "V6020": true, - "V6038": true, - "V6037": true, - "V6039": true, - "V6034": true, - "V6033": true, - "V6036": true, - "V6035": true, - "V6030": true, - "V6032": true, - "V6031": true, - "V6126": true, - "V6005": true, - "V6125": true, - "V6004": true, - "V6007": true, - "V6128": true, - "V6006": true, - "V6127": true, - "V6001": true, - "V6089": true, - "V6122": true, - "V6088": true, - "V6121": true, - "V6124": true, - "V6003": true, - "V6002": true, - "V6123": true, - "V6009": true, - "V6008": true, - "V6129": true, - "V6085": true, - "V6084": true, - "V6087": true, - "V6120": true, - "V6086": true, - "V6081": true, - "V6080": true, - "V6083": true, - "V6082": true, - "V6016": true, - "V6015": true, - "V6018": true, - "V6017": true, - "V6012": true, - "V6011": true, - "V6099": true, - "V6132": true, - "V6014": true, - "V6013": true, - "V6019": true, - "V6090": true, - "V6096": true, - "V6095": true, - "V6010": true, - "V6131": true, - "V6098": true, - "V6097": true, - "V6130": true, - "V6092": true, - "V6091": true, - "V6094": true, - "V6093": true, - "V6104": true, - "V6103": true, - "V6106": true, - "V6105": true, - "V6100": true, - "V6067": true, - "V6066": true, - "V6069": true, - "V6102": true, - "V6068": true, - "V6101": true, - "V6108": true, - "V6107": true, - "V6109": true, - "V6063": true, - "V6062": true, - "V6065": true, - "V6064": true, - "V6061": true, - "V6060": true, - "V6115": true, - "V6114": true, - "V6117": true, - "V6116": true, - "V6078": true, - "V6111": true, - "V6077": true, - "V6110": true, - "V6113": true, - "V6079": true, - "V6112": true, - "V6119": true, - "V6118": true, - "V6074": true, - "V6073": true, - "V6076": true, - "V6075": true, - "V6070": true, - "V6072": true, - "V6071": true, - "V6049": true, - "V6048": true, - "V6045": true, - "V6044": true, - "V6047": true, - "V6046": true, - "V6041": true, - "V6040": true, - "V6043": true, - "V6042": true, - "V6059": true, - "V6056": true, - "V6055": true, - "V6058": true, - "V6057": true, - "V6052": true, - "V6051": true, - "V6054": true, - "V6053": true, - "V6050": true - } -} \ No newline at end of file diff --git a/.PVS-Studio/settings.json b/.PVS-Studio/settings.json deleted file mode 100644 index 12631c48..00000000 --- a/.PVS-Studio/settings.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "src": [], - "ext": [], - "threads": 15, - "output-type": "json", - "securityRelatedIssues": false, - "annotation-file": [], - "incremental": false, - "force-rebuild": false, - "disable-cache": false, - "exclude": [], - "analyze-only": [], - "fail-on-warnings": false, - "analysis-mode": [ - "GA" - ], - "disabled-warnings": [], - "enabled-warnings": [], - "additional-warnings": [], - "suppress-base": ".PVS-Studio/suppress_base.json", - "timeout": 10, - "compatibility": false, - "exclude-packages": [], - "activate-license": false, - "version": false, - "is-java-core-subprocess-with-add-opens-for-native-libs-field-reflective-access": false, - "write-to-stdout": false, - "verbose": false, - "useOfflineDocumentation": false, - "skip-modules": [], - "include-generated": false, - "launch-mode": "IDEA", - "enable-all-warnings": false, - "benchmark": false, - "java": "java", - "jvm-arguments": [ - "-Xss64m" - ], - "traceLogFileName": "pvs.log", - "traceSpoonLogFileName": "spoon.log", - "check-license": false, - "logging": "OFF", - "project": "C:/Users/organ/Documents/GitHub/embedded-postgres", - "type": "sources", - "disableDiag": false -} \ No newline at end of file From 91a6717de8805e215fb06f99eeb35ba71002ea4b Mon Sep 17 00:00:00 2001 From: Nikan Radan Date: Sat, 8 Nov 2025 02:30:58 -0800 Subject: [PATCH 3/3] Use JDK 17 for Gradle The binaries will still be compiled for JDK 8 but the JDK that runs Gradle will be 17. --- .github/workflows/release.yml | 4 ++-- .github/workflows/test.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6be0656b..b154bfde 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,11 +18,11 @@ jobs: run: | git config user.name "Zonky Bot" git config user.email "bot@zonky.com" - - name: Set up JDK 8 + - name: Set up JDK 17 uses: actions/setup-java@v5 with: distribution: 'zulu' - java-version: '8' + java-version: '17' cache: 'gradle' - name: Make Gradle wrapper executable run: chmod +x gradlew diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f573b40b..c178b8ea 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,7 +6,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - java: [8, 11, 17, 21, 25] # LTS and newer versions + java: [17, 21, 25] # LTS and newer versions steps: - name: Checkout project uses: actions/checkout@v5