diff --git a/.github/workflows/merge-build.yml b/.github/workflows/merge-build.yml index 84168a5..7f869cf 100644 --- a/.github/workflows/merge-build.yml +++ b/.github/workflows/merge-build.yml @@ -25,7 +25,7 @@ jobs: publish-snapshot: name: publish to oss sonatype & push image - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest permissions: contents: read @@ -42,12 +42,7 @@ jobs: with: distribution: 'temurin' architecture: x64 - java-version: 11 - - - name: Set up Maven - uses: stCarolas/setup-maven@v4.5 - with: - maven-version: 3.8.8 + java-version: 17 - name: maven-settings-xml-action uses: whelk-io/maven-settings-xml-action@v14 diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml index bbc3277..317862b 100644 --- a/.github/workflows/pr-build.yml +++ b/.github/workflows/pr-build.yml @@ -24,7 +24,7 @@ on: [pull_request] jobs: build: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 @@ -32,14 +32,9 @@ jobs: - name: Set up JDK uses: actions/setup-java@v2 with: - java-version: '11' + java-version: '17' distribution: 'adopt' - - name: Set up Maven - uses: stCarolas/setup-maven@v4.5 - with: - maven-version: 3.8.8 - - name: maven-settings-xml-action uses: whelk-io/maven-settings-xml-action@v14 with: diff --git a/README.md b/README.md index 50c459c..3e31fe1 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Users r/w the files via REST api. Multiple users can r/w same file without affec The concurrent r/w is no surprise when you run a standalone service which only concerns one node. The most significant fact lies on the 'cluster' mode. You can deploy it on a Cloud platform, such as k8s or Openshift, and scale up to as many nodes as you want. The concurrent r/w promise still hold. On cluster mode, all nodes share the same persistent volume and connect to the same Cassandra as the backend DB. ## Prerequisite -1. jdk11 +1. jdk17 2. mvn 3.6.2+ ## Prerequisite for debugging in local diff --git a/pom.xml b/pom.xml index 87733e1..e32b0cf 100644 --- a/pom.xml +++ b/pom.xml @@ -44,7 +44,6 @@ UTF-8 3.0 3.0.0 - 3.8 uber-jar 1.19.7 false @@ -196,6 +195,11 @@ localstack test + + org.testcontainers + cassandra + test + @@ -254,7 +258,7 @@ - 11 + 17 OpenJDK @@ -279,34 +283,6 @@ - - org.codehaus.mojo - cassandra-maven-plugin - ${cassandra-maven-plugin.version} - - true - 9942 - true - - ${skipTests} - - - - net.java.dev.jna - jna - 5.8.0 - - - - - cassandra - - start - stop - - - - org.apache.maven.plugins maven-release-plugin diff --git a/src/main/image/Dockerfile.jvm b/src/main/image/Dockerfile.jvm index 24ca0fd..ecf968e 100644 --- a/src/main/image/Dockerfile.jvm +++ b/src/main/image/Dockerfile.jvm @@ -23,7 +23,7 @@ ### FROM registry.access.redhat.com/ubi8/ubi-minimal:8.1 -ARG JAVA_PACKAGE=java-11-openjdk-headless +ARG JAVA_PACKAGE=java-17-openjdk-headless ARG RUN_JAVA_VERSION=1.3.8 ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' diff --git a/src/test/java/org/commonjava/service/storage/S3StorageIT.java b/src/test/java/org/commonjava/service/storage/S3StorageIT.java index 127cb1d..a17cb49 100644 --- a/src/test/java/org/commonjava/service/storage/S3StorageIT.java +++ b/src/test/java/org/commonjava/service/storage/S3StorageIT.java @@ -18,6 +18,7 @@ import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.junit.QuarkusTest; import jakarta.inject.Inject; +import org.commonjava.service.storage.util.CassandraTestResource; import org.commonjava.service.storage.util.LocalStackTestResource; import org.junit.jupiter.api.Test; import software.amazon.awssdk.services.s3.S3Client; @@ -32,6 +33,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; @QuarkusTest +@QuarkusTestResource(CassandraTestResource.class) @QuarkusTestResource(LocalStackTestResource.class) public class S3StorageIT extends StorageIT diff --git a/src/test/java/org/commonjava/service/storage/StorageIT.java b/src/test/java/org/commonjava/service/storage/StorageIT.java index 79b9ea5..e45bf58 100644 --- a/src/test/java/org/commonjava/service/storage/StorageIT.java +++ b/src/test/java/org/commonjava/service/storage/StorageIT.java @@ -15,8 +15,10 @@ */ package org.commonjava.service.storage; +import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.common.http.TestHTTPResource; import org.apache.commons.io.IOUtils; +import org.commonjava.service.storage.util.CassandraTestResource; import org.commonjava.storage.pathmapped.core.PathMappedFileManager; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; @@ -27,6 +29,7 @@ import java.io.OutputStream; import java.net.URL; +@QuarkusTestResource(CassandraTestResource.class) public abstract class StorageIT { protected final String PATH = "io/quarkus/quarkus-junit5/quarkus-junit5-1.12.0.Final.jar"; @@ -45,27 +48,18 @@ public abstract class StorageIT public static void init() throws Exception { /* - * The reason I dropped embedded cassandra: - * Previously I use 'cassandra-unit' which is great because we can run the unit tests both - * by mvn command and in IDEA. Unfortunately, after upgrading to Quarkus 3.x, there is a - * dependence change, and it breaks the embedded cassandra. + * Now using testcontainers for Cassandra which supports Java 17. + * The CassandraTestResource starts/stops the container automatically. + * Tests can now be run both from mvn and directly in IDEA. * - * Because of that, I moved to cassandra-maven-plugin in pom.xml. It works well with Quarkus 3 - * to start/stop cassandra. But I have to move Junit tests to integration tests because - * this plugin works for integration phase only. The test classes are refactored as '*IT.java'. - * The downside is that we can not run the IT tests in IDEA by simply clicking the 'Run'. - * We need to do from command line as 'mvn verify'. Or we run 'mvn cassandra:start' beforehand - * then run IT tests in IDEA. - * - * ruhan Feb 9, 2024 + * Updated for Java 17 migration, March 2026 */ - //EmbeddedCassandraServerHelper.startEmbeddedCassandra(); } @AfterAll public static void stop() throws Exception { - //EmbeddedCassandraServerHelper.cleanEmbeddedCassandra(); + // Cleanup handled by CassandraTestResource } @BeforeEach diff --git a/src/test/java/org/commonjava/service/storage/util/CassandraTestResource.java b/src/test/java/org/commonjava/service/storage/util/CassandraTestResource.java new file mode 100644 index 0000000..0653862 --- /dev/null +++ b/src/test/java/org/commonjava/service/storage/util/CassandraTestResource.java @@ -0,0 +1,74 @@ +/** + * Copyright (C) 2021 Red Hat, Inc. (https://github.com/Commonjava/service-parent) + * + * 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 + * + * 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 org.commonjava.service.storage.util; + +import com.datastax.driver.core.Cluster; +import com.datastax.driver.core.Session; +import io.quarkus.test.common.QuarkusTestResourceLifecycleManager; +import org.testcontainers.containers.CassandraContainer; +import org.testcontainers.utility.DockerImageName; + +import java.util.HashMap; +import java.util.Map; + +public class CassandraTestResource implements QuarkusTestResourceLifecycleManager { + + static DockerImageName dockerImageName = DockerImageName.parse("cassandra:3.11.10"); + static CassandraContainer cassandraContainer = new CassandraContainer<>(dockerImageName); + + @Override + public Map start() { + cassandraContainer.start(); + + // Wait for Cassandra to be truly ready by attempting to connect + waitForCassandraToBeReady(); + + HashMap map = new HashMap<>(); + map.put("cassandra.host", cassandraContainer.getHost()); + map.put("cassandra.port", String.valueOf(cassandraContainer.getMappedPort(9042))); + map.put("cassandra.user", cassandraContainer.getUsername()); + map.put("cassandra.pass", cassandraContainer.getPassword()); + return map; + } + + private void waitForCassandraToBeReady() { + int maxAttempts = 30; + for (int i = 0; i < maxAttempts; i++) { + try (Cluster cluster = cassandraContainer.getCluster(); + Session session = cluster.connect()) { + // Successfully connected + return; + } catch (Exception e) { + if (i == maxAttempts - 1) { + throw new RuntimeException("Cassandra did not become ready in time", e); + } + try { + Thread.sleep(1000); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + throw new RuntimeException("Interrupted while waiting for Cassandra", ie); + } + } + } + } + + @Override + public void stop() { + if (cassandraContainer != null) { + cassandraContainer.stop(); + } + } +} diff --git a/src/test/resources/application.yaml b/src/test/resources/application.yaml index b9141cc..3ebae89 100644 --- a/src/test/resources/application.yaml +++ b/src/test/resources/application.yaml @@ -32,11 +32,8 @@ quarkus: swagger-ui: always-include: true +# Cassandra configuration is provided by CassandraTestResource at runtime cassandra: - host: localhost - port: 9942 - user: cassandra - pass: cassandra keyspace: indystorage storage: diff --git a/toolchains.xml b/toolchains.xml index 0314f4a..de1ef43 100644 --- a/toolchains.xml +++ b/toolchains.xml @@ -30,11 +30,11 @@ jdk - 11 + 17 OpenJDK - /usr/lib/jvm/java-11-openjdk + /usr/lib/jvm/java-17-openjdk