This is an automated email from the ASF dual-hosted git repository.

rustyrazorblade pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cassandra-easy-stress.git


The following commit(s) were added to refs/heads/main by this push:
     new 2f2f9bf  feat(build): support JDK 21 and 25, migrate build.gradle to 
Kotlin DSL
2f2f9bf is described below

commit 2f2f9bfbb78fffa32508cc58afe11b83665632e5
Author: Jon Haddad <[email protected]>
AuthorDate: Fri Aug 14 12:42:19 2026 -0700

    feat(build): support JDK 21 and 25, migrate build.gradle to Kotlin DSL
    
    - Target whichever JDK is actually compiling (21 or 25) instead of a fixed 
floor; add JDK 25 to the CI test matrix alongside 21 (current + next LTS)
    - Default the launch script and Docker image to Generational ZGC, 
JDK-version-aware (JDK 23+ removed the explicit flag)
    - Upgrade Gradle 8.14.3 -> 9.7.0 (required: Gradle before 9.1.0 can't run 
its own daemon on JDK 25) and convert build.gradle to Kotlin DSL
    - Upgrade Kotlin 2.2.20 -> 2.4.10 (JDK 25 as an explicit compile target 
requires Kotlin 2.3+)
    - Bump jib 3.3.0 -> 3.5.4 and kover 0.9.2 -> 0.9.9 for Gradle 9 / Kotlin 
2.4 compatibility; bump testcontainers 1.19.8 -> 2.0.5, fixing local 
Docker-integration-test connectivity
    - Bump mockk, junit-jupiter/junit-platform, and 
hadoop-common/hadoop-mapreduce-client-common for JDK 21+ bytecode and JDK 24+ 
Security Manager removal compatibility
    - Fix Gradle 9/10 deprecations in the build script and a real blocker 
introduced during the Kotlin DSL conversion (illegal task-container mutation 
breaking ./gradlew tasks/testAllVersions)
---
 .github/workflows/ci.yml                     |  24 +-
 .github/workflows/gradle-publish-disttar.yml |   4 +-
 .github/workflows/publish-release.yml        |   4 +-
 README.md                                    |   8 +-
 bin/cassandra-easy-stress                    |  13 +-
 build.gradle                                 | 297 -----------------------
 build.gradle.kts                             | 348 +++++++++++++++++++++++++++
 gradle/libs.versions.toml                    |  19 +-
 gradle/wrapper/gradle-wrapper.jar            | Bin 59536 -> 43764 bytes
 gradle/wrapper/gradle-wrapper.properties     |   4 +-
 gradlew                                      |  47 ++--
 gradlew.bat                                  |  41 ++--
 12 files changed, 448 insertions(+), 361 deletions(-)

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 9a18b79..69fb725 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -18,7 +18,7 @@ jobs:
 
     strategy:
       matrix:
-        java: [17, 21]
+        java: [21, 25]
         test-task: ["test40", "test41", "test50"]
       fail-fast: false
 
@@ -44,10 +44,10 @@ jobs:
       - name: Checkout code
         uses: actions/checkout@v6
 
-      - name: Set up JDK 17
+      - name: Set up JDK 21
         uses: actions/setup-java@v5
         with:
-          java-version: 17
+          java-version: 21
           distribution: "temurin"
           cache: "gradle"
 
@@ -62,10 +62,10 @@ jobs:
       - name: Checkout code
         uses: actions/checkout@v6
 
-      - name: Set up JDK 17
+      - name: Set up JDK 21
         uses: actions/setup-java@v5
         with:
-          java-version: 17
+          java-version: 21
           distribution: "temurin"
           cache: "gradle"
 
@@ -80,10 +80,10 @@ jobs:
       - name: Checkout code
         uses: actions/checkout@v6
 
-      - name: Set up JDK 17
+      - name: Set up JDK 21
         uses: actions/setup-java@v5
         with:
-          java-version: 17
+          java-version: 21
           distribution: "temurin"
           cache: "gradle"
 
@@ -99,10 +99,10 @@ jobs:
       - name: Checkout code
         uses: actions/checkout@v6
 
-      - name: Set up JDK 17
+      - name: Set up JDK 21
         uses: actions/setup-java@v5
         with:
-          java-version: 17
+          java-version: 21
           distribution: "temurin"
           cache: "gradle"
 
@@ -122,10 +122,10 @@ jobs:
       - name: Checkout code
         uses: actions/checkout@v6
 
-      - name: Set up JDK 17
+      - name: Set up JDK 21
         uses: actions/setup-java@v5
         with:
-          java-version: 17
+          java-version: 21
           distribution: "temurin"
           cache: "gradle"
 
@@ -225,7 +225,7 @@ jobs:
             - **Artifact Size**: ${{ steps.artifact.outputs.artifact_size }}
             - **Workflow Run**: ${{ github.server_url }}/${{ github.repository 
}}/actions/runs/${{ github.run_id }}
             - **Commit**: ${{ github.sha }}
-            - **Java Version**: 17 (Temurin)
+            - **Java Version**: 21 (Temurin)
 
             ### Usage
 
diff --git a/.github/workflows/gradle-publish-disttar.yml 
b/.github/workflows/gradle-publish-disttar.yml
index 0acb1e6..2ec3b6c 100644
--- a/.github/workflows/gradle-publish-disttar.yml
+++ b/.github/workflows/gradle-publish-disttar.yml
@@ -17,10 +17,10 @@ jobs:
 
     steps:
     - uses: actions/checkout@v6
-    - name: Set up JDK 17
+    - name: Set up JDK 21
       uses: actions/setup-java@v5
       with:
-        java-version: '17'
+        java-version: '21'
         distribution: 'temurin'
         cache: 'gradle'
         server-id: github # Value of the distributionManagement/repository/id 
field of the pom.xml
diff --git a/.github/workflows/publish-release.yml 
b/.github/workflows/publish-release.yml
index 7386e37..92ca42e 100644
--- a/.github/workflows/publish-release.yml
+++ b/.github/workflows/publish-release.yml
@@ -15,10 +15,10 @@ jobs:
       - name: Checkout code
         uses: actions/checkout@v6
 
-      - name: Set up JDK 17
+      - name: Set up JDK 21
         uses: actions/setup-java@v5
         with:
-          java-version: '17'
+          java-version: '21'
           distribution: 'temurin'
           cache: 'gradle'
 
diff --git a/README.md b/README.md
index e9d0046..bdf60b0 100644
--- a/README.md
+++ b/README.md
@@ -264,13 +264,13 @@ If `CASSANDRA_VERSION` is not set, it defaults to "5.0".
 The GitHub Actions CI workflow (`.github/workflows/ci.yml`) runs on every push 
and pull request.
 
 **Test matrix:**
-- **Java versions**: 17 and 21
+- **Java versions**: 21 and 25 (current + next LTS)
 - **Cassandra versions**: 4.0, 4.1, 5.0
 
 This creates 6 test jobs total:
-- Cassandra 4.0 on Java 17 and 21
-- Cassandra 4.1 on Java 17 and 21
-- Cassandra 5.0 on Java 17 and 21
+- Cassandra 4.0 on Java 21 and 25
+- Cassandra 4.1 on Java 21 and 25
+- Cassandra 5.0 on Java 21 and 25
 
 **Workflow steps:**
 
diff --git a/bin/cassandra-easy-stress b/bin/cassandra-easy-stress
index 99267d6..6ad5d08 100755
--- a/bin/cassandra-easy-stress
+++ b/bin/cassandra-easy-stress
@@ -6,7 +6,18 @@ cd $BASE_STRESS_DIR
 
 JAR=$(find build/libs -name '*-all.jar' | tail -n 1)
 
-java -jar $JAR "$@"
+# Generational ZGC by default; set JAVA_OPTS to override (e.g. to select a
+# different collector). JDK 23+ made generational collection the only ZGC
+# mode and removed -XX:+ZGenerational, so only pass it on older JDKs.
+JAVA_MAJOR_VERSION=$(java -version 2>&1 | awk -F'"' '/version/ {print $2}' | 
cut -d. -f1)
+if [ "$JAVA_MAJOR_VERSION" -ge 23 ] 2>/dev/null; then
+    DEFAULT_GC_OPTS="-XX:+UseZGC"
+else
+    DEFAULT_GC_OPTS="-XX:+UseZGC -XX:+ZGenerational"
+fi
+JAVA_OPTS="${JAVA_OPTS:-$DEFAULT_GC_OPTS}"
+
+java $JAVA_OPTS -jar $JAR "$@"
 
 
 
diff --git a/build.gradle b/build.gradle
deleted file mode 100644
index 4041edc..0000000
--- a/build.gradle
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-plugins {
-    alias(libs.plugins.jib)
-    alias(libs.plugins.kotlin.jvm)
-    alias(libs.plugins.kotlin.serialization)
-    alias(libs.plugins.nebula.ospackage)
-    alias(libs.plugins.nebula.ospackage.application)
-    alias(libs.plugins.ktlint)
-    alias(libs.plugins.detekt)
-    alias(libs.plugins.shadow)
-    alias(libs.plugins.kover)
-}
-
-
-apply plugin: 'idea'
-apply plugin: 'java'
-apply plugin: 'kotlin'
-apply plugin: 'application'
-
-group 'org.apache.cassandra'
-
-sourceCompatibility = 11
-
-application {
-    applicationName = "cassandra-easy-stress"
-    mainClassName = "org.apache.cassandra.easystress.MainKt"
-}
-
-repositories {
-    mavenCentral()
-}
-
-dependencies {
-    implementation libs.jcommander
-    implementation libs.commons.text
-    implementation libs.commons.math3
-
-    // Java driver v4
-    implementation libs.cassandra.driver.core
-    implementation libs.jackson.module.kotlin
-
-    implementation libs.reflections
-
-    // Logging
-    implementation libs.log4j.api
-    implementation libs.log4j.core
-    implementation libs.log4j.api.kotlin
-    implementation libs.kotlin.reflect
-    // maps the datastax driver slf4j calls to log4j
-    implementation libs.log4j.slf4j18.impl
-
-    // needed for yaml logging configurations
-    implementation libs.jackson.databind
-    implementation libs.jackson.dataformat.yaml
-
-    // Metrics
-    implementation libs.dropwizard.metrics.core
-    implementation libs.prometheus.simpleclient
-    implementation libs.prometheus.simpleclient.dropwizard
-    implementation libs.prometheus.simpleclient.httpserver
-
-    implementation libs.guava
-    implementation libs.mordant
-    implementation libs.progressbar
-    implementation libs.hdrhistogram
-    implementation libs.agrona // can't use the 2.x or 1.23+ line as it 
requires JDK 17
-
-    // Parquet support
-    implementation libs.parquet.hadoop
-    implementation libs.hadoop.common
-    implementation libs.hadoop.mapreduce.client.common
-
-    // MCP Server dependencies
-    implementation (libs.mcp.sdk) {
-        exclude group: 'org.slf4j', module: 'slf4j-api'
-    }
-    implementation (libs.ktor.server.core) {
-        exclude group: 'org.slf4j', module: 'slf4j-api'
-    }
-    implementation (libs.ktor.server.cio) {
-        exclude group: 'org.slf4j', module: 'slf4j-api'
-    }
-    implementation (libs.ktor.server.content.negotiation) {
-        exclude group: 'org.slf4j', module: 'slf4j-api'
-    }
-    implementation (libs.ktor.serialization.kotlinx.json) {
-        exclude group: 'org.slf4j', module: 'slf4j-api'
-    }
-    implementation (libs.ktor.server.sse) {
-        exclude group: 'org.slf4j', module: 'slf4j-api'
-    }
-
-    // Test dependencies
-    testImplementation libs.junit.jupiter.engine
-    testImplementation libs.junit.jupiter.params
-    testImplementation libs.assertj.core
-    testImplementation libs.kotlin.test.junit
-    testImplementation libs.mockk
-    testImplementation libs.kotlinx.coroutines.test
-    testImplementation platform(libs.testcontainers.bom)
-    testImplementation libs.testcontainers.core
-    testImplementation libs.testcontainers.cassandra
-
-}
-
-compileKotlin {
-    kotlinOptions.jvmTarget = JavaVersion.VERSION_11
-}
-compileTestKotlin {
-    kotlinOptions.jvmTarget = JavaVersion.VERSION_11
-}
-
-sourceSets {
-    main.java.srcDirs += "src/main/kotlin"
-    test.java.srcDirs += "src/test/kotlin"
-}
-
-test {
-    useJUnitPlatform()
-
-    // Make Gradle aware of CASSANDRA_VERSION environment variable
-    // This ensures tests rerun when the version changes
-    def cassandraVersion = System.getenv("CASSANDRA_VERSION") ?: "5.0"
-    inputs.property("cassandraVersion", cassandraVersion)
-
-    // Pass environment variable to test JVM
-    environment "CASSANDRA_VERSION", cassandraVersion
-}
-
-// Create individual test tasks for each Cassandra version
-["4.0", "4.1", "5.0"].each { version ->
-    def versionName = version.replace(".", "")
-    tasks.register("test${versionName}", Test) {
-        group = "Verification"
-        description = "Run tests against Cassandra ${version}"
-
-        useJUnitPlatform()
-
-        // Set the Cassandra version for this test task
-        environment "CASSANDRA_VERSION", version
-        inputs.property("cassandraVersion", version)
-
-        // Use same test sources and classpath as main test task
-        testClassesDirs = sourceSets.test.output.classesDirs
-        classpath = sourceSets.test.runtimeClasspath
-
-        doFirst {
-            println ""
-            println "=" * 80
-            println "Testing Cassandra ${version}"
-            println "=" * 80
-        }
-
-        doLast {
-            println ""
-            println "✅ Cassandra ${version} tests PASSED"
-        }
-    }
-}
-
-task testAllVersions {
-    group = "Verification"
-    description = "Run tests against all Cassandra versions (4.0, 4.1, 5.0)"
-
-    // Depend on all version-specific test tasks
-    dependsOn tasks.test40, tasks.test41, tasks.test50
-
-    // Ensure sequential execution
-    tasks.test41.mustRunAfter tasks.test40
-    tasks.test50.mustRunAfter tasks.test41
-
-    doFirst {
-        println ""
-        println "=" * 80
-        println "Running tests against all Cassandra versions: 4.0, 4.1, 5.0"
-        println "=" * 80
-    }
-
-    doLast {
-        println ""
-        println "=" * 80
-        println "Test Summary"
-        println "=" * 80
-        println "✅ Cassandra 4.0: PASSED"
-        println "✅ Cassandra 4.1: PASSED"
-        println "✅ Cassandra 5.0: PASSED"
-        println "=" * 80
-        println ""
-    }
-}
-
-task docs(type:Exec) {
-    dependsOn("shadowJar")
-    dependsOn("generateExamples")
-
-    environment "CASSANDRA_EASY_STRESS_VERSION", "${version}"
-    commandLine 'docker-compose', 'up', 'docs'
-    group = "Documentation"
-    description = "Build website documentation"
-}
-
-task generateExamples(type: Exec) {
-    dependsOn("shadowJar")
-    commandLine "manual/generate_examples.sh"
-    group = "Documentation"
-    description = "Generate examples for documentation"
-}
-
-jib {
-    to {
-        image = "ghcr.io/${System.getenv('GITHUB_REPOSITORY') ?: 
'apache/cassandra-easy-stress'}"
-        tags = ["latest"]
-    }
-    from {
-        image = "eclipse-temurin:17-jre"
-    }
-}
-
-ospackage {
-    os = LINUX
-    link("/usr/local/bin/cassandra-easy-stress", 
"/opt/cassandra-easy-stress/bin/cassandra-easy-stress" )
-    packager "Jon Haddad"
-    maintainer "Jon Haddad"
-    vendor "Rustyrazorblade Consulting"
-    url "http://rustyrazorblade.com/cassandra-easy-stress/";
-    license "Apache License 2.0"
-    description "Stress Tool for Apache Cassandra by Rustyrazorblade 
Consulting"
-}
-
-buildDeb {
-    distribution "weezy,bionic,xenial,jessie"
-    requires("openjdk-8-jre")
-    group = "build"
-}
-
-buildRpm {
-    requires("java-1.8.0-openjdk")
-    user "root"
-    group = "build"
-}
-
-task buildAll {
-    group = "build"
-    dependsOn "buildDeb"
-    dependsOn "buildRpm"
-    dependsOn "distTar"
-}
-
-tasks.distTar {
-    compression = Compression.GZIP
-    archiveExtension.set("tar.gz")
-}
-
-assemble.mustRunAfter clean
-
-applicationDistribution.from("LICENSE.txt") {
-    into ""
-}
-
-wrapper {
-    distributionType = Wrapper.DistributionType.ALL
-}
-targetCompatibility = JavaVersion.VERSION_11
-
-detekt {
-    toolVersion = "1.23.7"
-    source = files("src/main/kotlin", "src/test/kotlin")
-    parallel = true
-    config = files("$projectDir/detekt-config.yml")
-    buildUponDefaultConfig = true
-    allRules = false
-    baseline = file("$projectDir/detekt-baseline.xml")
-    disableDefaultRuleSets = false
-    debug = false
-    ignoreFailures = false
-    ignoredBuildTypes = ["release"]
-    ignoredFlavors = ["production"]
-    ignoredVariants = ["productionRelease"]
-    autoCorrect = false
-}
diff --git a/build.gradle.kts b/build.gradle.kts
new file mode 100644
index 0000000..160320a
--- /dev/null
+++ b/build.gradle.kts
@@ -0,0 +1,348 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import com.netflix.gradle.plugins.deb.Deb
+import com.netflix.gradle.plugins.rpm.Rpm
+import io.gitlab.arturbosch.detekt.Detekt
+import io.gitlab.arturbosch.detekt.DetektCreateBaselineTask
+import org.jetbrains.kotlin.gradle.dsl.JvmTarget
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+import org.redline_rpm.header.Os
+
+plugins {
+    idea
+    java
+    application
+    alias(libs.plugins.jib)
+    alias(libs.plugins.kotlin.jvm)
+    alias(libs.plugins.kotlin.serialization)
+    alias(libs.plugins.nebula.ospackage)
+    alias(libs.plugins.nebula.ospackage.application)
+    alias(libs.plugins.ktlint)
+    alias(libs.plugins.detekt)
+    alias(libs.plugins.shadow)
+    alias(libs.plugins.kover)
+}
+
+apply(plugin = "kotlin")
+
+group = "org.apache.cassandra"
+
+// Target whatever JDK is actually running the build (21 or 25 in CI) rather
+// than pinning a fixed floor here -- the release-artifact-building CI jobs
+// (build, build-check, create-test-artifact) are the single source of truth
+// for what the shipped artifact requires, and they're pinned to JDK 21.
+java {
+    sourceCompatibility = JavaVersion.current()
+    targetCompatibility = JavaVersion.current()
+}
+
+application {
+    applicationName = "cassandra-easy-stress"
+    mainClass = "org.apache.cassandra.easystress.MainKt"
+}
+
+repositories {
+    mavenCentral()
+}
+
+dependencies {
+    implementation(libs.jcommander)
+    implementation(libs.commons.text)
+    implementation(libs.commons.math3)
+
+    // Java driver v4
+    implementation(libs.cassandra.driver.core)
+    implementation(libs.jackson.module.kotlin)
+
+    implementation(libs.reflections)
+
+    // Logging
+    implementation(libs.log4j.api)
+    implementation(libs.log4j.core)
+    implementation(libs.log4j.api.kotlin)
+    implementation(libs.kotlin.reflect)
+    // maps the datastax driver slf4j calls to log4j
+    implementation(libs.log4j.slf4j18.impl)
+
+    // needed for yaml logging configurations
+    implementation(libs.jackson.databind)
+    implementation(libs.jackson.dataformat.yaml)
+
+    // Metrics
+    implementation(libs.dropwizard.metrics.core)
+    implementation(libs.prometheus.simpleclient)
+    implementation(libs.prometheus.simpleclient.dropwizard)
+    implementation(libs.prometheus.simpleclient.httpserver)
+
+    implementation(libs.guava)
+    implementation(libs.mordant)
+    implementation(libs.progressbar)
+    implementation(libs.hdrhistogram)
+    // Pinned to 1.22.0; the project now targets JDK 21, so the 2.x/1.23+
+    // line's former JDK 17 requirement is no longer a blocker -- upgrading
+    // is possible but left out of scope here.
+    implementation(libs.agrona)
+
+    // Parquet support
+    implementation(libs.parquet.hadoop)
+    implementation(libs.hadoop.common)
+    implementation(libs.hadoop.mapreduce.client.common)
+
+    // MCP Server dependencies
+    implementation(libs.mcp.sdk) {
+        exclude(group = "org.slf4j", module = "slf4j-api")
+    }
+    implementation(libs.ktor.server.core) {
+        exclude(group = "org.slf4j", module = "slf4j-api")
+    }
+    implementation(libs.ktor.server.cio) {
+        exclude(group = "org.slf4j", module = "slf4j-api")
+    }
+    implementation(libs.ktor.server.content.negotiation) {
+        exclude(group = "org.slf4j", module = "slf4j-api")
+    }
+    implementation(libs.ktor.serialization.kotlinx.json) {
+        exclude(group = "org.slf4j", module = "slf4j-api")
+    }
+    implementation(libs.ktor.server.sse) {
+        exclude(group = "org.slf4j", module = "slf4j-api")
+    }
+
+    // Test dependencies
+    testImplementation(libs.junit.jupiter.engine)
+    testImplementation(libs.junit.jupiter.params)
+    testRuntimeOnly(libs.junit.platform.launcher)
+    testImplementation(libs.assertj.core)
+    testImplementation(libs.kotlin.test.junit)
+    testImplementation(libs.mockk)
+    testImplementation(libs.kotlinx.coroutines.test)
+    testImplementation(platform(libs.testcontainers.bom))
+    testImplementation(libs.testcontainers.core)
+    testImplementation(libs.testcontainers.cassandra)
+}
+
+// Target whatever JDK is actually running the build, matching the java {}
+// block above -- see the comment there.
+tasks.withType<KotlinCompile>().configureEach {
+    compilerOptions {
+        jvmTarget.set(JvmTarget.fromTarget(JavaVersion.current().majorVersion))
+    }
+}
+
+sourceSets {
+    main {
+        java.srcDirs("src/main/kotlin")
+    }
+    test {
+        java.srcDirs("src/test/kotlin")
+    }
+}
+
+tasks.test {
+    useJUnitPlatform()
+
+    // Make Gradle aware of CASSANDRA_VERSION environment variable
+    // This ensures tests rerun when the version changes
+    val cassandraVersion = System.getenv("CASSANDRA_VERSION") ?: "5.0"
+    inputs.property("cassandraVersion", cassandraVersion)
+
+    // Pass environment variable to test JVM
+    environment("CASSANDRA_VERSION", cassandraVersion)
+}
+
+// Create individual test tasks for each Cassandra version
+listOf("4.0", "4.1", "5.0").forEach { version ->
+    val versionName = version.replace(".", "")
+    tasks.register<Test>("test$versionName") {
+        group = "Verification"
+        description = "Run tests against Cassandra $version"
+
+        useJUnitPlatform()
+
+        // Set the Cassandra version for this test task
+        environment("CASSANDRA_VERSION", version)
+        inputs.property("cassandraVersion", version)
+
+        // Use same test sources and classpath as main test task
+        testClassesDirs =
+            sourceSets.test
+                .get()
+                .output.classesDirs
+        classpath = sourceSets.test.get().runtimeClasspath
+
+        doFirst {
+            println()
+            println("=".repeat(80))
+            println("Testing Cassandra $version")
+            println("=".repeat(80))
+        }
+
+        doLast {
+            println()
+            println("✅ Cassandra $version tests PASSED")
+        }
+    }
+}
+
+// Ensure sequential execution
+tasks.named("test41") { mustRunAfter(tasks.named("test40")) }
+tasks.named("test50") { mustRunAfter(tasks.named("test41")) }
+
+tasks.register("testAllVersions") {
+    group = "Verification"
+    description = "Run tests against all Cassandra versions (4.0, 4.1, 5.0)"
+
+    // Depend on all version-specific test tasks
+    dependsOn(tasks.named("test40"), tasks.named("test41"), 
tasks.named("test50"))
+
+    doFirst {
+        println()
+        println("=".repeat(80))
+        println("Running tests against all Cassandra versions: 4.0, 4.1, 5.0")
+        println("=".repeat(80))
+    }
+
+    doLast {
+        println()
+        println("=".repeat(80))
+        println("Test Summary")
+        println("=".repeat(80))
+        println("✅ Cassandra 4.0: PASSED")
+        println("✅ Cassandra 4.1: PASSED")
+        println("✅ Cassandra 5.0: PASSED")
+        println("=".repeat(80))
+        println()
+    }
+}
+
+tasks.register<Exec>("docs") {
+    dependsOn("shadowJar")
+    dependsOn("generateExamples")
+
+    environment("CASSANDRA_EASY_STRESS_VERSION", project.version.toString())
+    commandLine("docker-compose", "up", "docs")
+    group = "Documentation"
+    description = "Build website documentation"
+}
+
+tasks.register<Exec>("generateExamples") {
+    dependsOn("shadowJar")
+    commandLine("manual/generate_examples.sh")
+    group = "Documentation"
+    description = "Generate examples for documentation"
+}
+
+// JDK 23+ removed -XX:+ZGenerational (generational collection is ZGC's only
+// mode there); keep this in sync with the JDK-version check in
+// bin/cassandra-easy-stress.
+val jibBaseJdkVersion = 21
+val jibGcOpts =
+    if (jibBaseJdkVersion >= 23) "-XX:+UseZGC" else "-XX:+UseZGC 
-XX:+ZGenerational"
+
+jib {
+    to {
+        image = "ghcr.io/${System.getenv("GITHUB_REPOSITORY") ?: 
"apache/cassandra-easy-stress"}"
+        tags = setOf("latest")
+    }
+    from {
+        image = "eclipse-temurin:$jibBaseJdkVersion-jre"
+    }
+    container {
+        // Generational ZGC by default; override at "docker run" time with
+        // -e JAVA_TOOL_OPTIONS="..." to select a different collector.
+        environment = mapOf("JAVA_TOOL_OPTIONS" to jibGcOpts)
+    }
+}
+
+ospackage {
+    os = Os.LINUX
+    link("/usr/local/bin/cassandra-easy-stress", 
"/opt/cassandra-easy-stress/bin/cassandra-easy-stress")
+    packager = "Jon Haddad"
+    maintainer = "Jon Haddad"
+    vendor = "Rustyrazorblade Consulting"
+    url = "http://rustyrazorblade.com/cassandra-easy-stress/";
+    license = "Apache License 2.0"
+    description = "Stress Tool for Apache Cassandra by Rustyrazorblade 
Consulting"
+}
+
+tasks.named<Deb>("buildDeb") {
+    distribution = "weezy,bionic,xenial,jessie"
+    requires("openjdk-21-jre")
+    group = "build"
+}
+
+tasks.named<Rpm>("buildRpm") {
+    requires("java-21-openjdk")
+    user = "root"
+    group = "build"
+}
+
+tasks.register("buildAll") {
+    group = "build"
+    dependsOn("buildDeb")
+    dependsOn("buildRpm")
+    dependsOn("distTar")
+}
+
+tasks.distTar {
+    compression = Compression.GZIP
+    archiveExtension.set("tar.gz")
+}
+
+tasks.assemble {
+    mustRunAfter(tasks.clean)
+}
+
+distributions {
+    main {
+        contents {
+            from("LICENSE.txt") {
+                into("")
+            }
+        }
+    }
+}
+
+tasks.wrapper {
+    distributionType = Wrapper.DistributionType.ALL
+}
+
+detekt {
+    toolVersion = "1.23.8"
+    source.setFrom(files("src/main/kotlin", "src/test/kotlin"))
+    parallel = true
+    config.setFrom(files("$projectDir/detekt-config.yml"))
+    buildUponDefaultConfig = true
+    allRules = false
+    baseline = file("$projectDir/detekt-baseline.xml")
+    disableDefaultRuleSets = false
+    debug = false
+    ignoreFailures = false
+    ignoredBuildTypes = listOf("release")
+    ignoredFlavors = listOf("production")
+    ignoredVariants = listOf("productionRelease")
+    autoCorrect = false
+}
+
+tasks.withType<Detekt>().configureEach {
+    jvmTarget = "21"
+}
+tasks.withType<DetektCreateBaselineTask>().configureEach {
+    jvmTarget = "21"
+}
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 10d134a..5d9f65f 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,11 +1,11 @@
 [versions]
-kotlin = "2.2.20"
-jib = "3.3.0"
+kotlin = "2.4.10"
+jib = "3.5.4"
 nebula-ospackage = "12.1.1"
 ktlint = "14.0.1"
 detekt = "1.23.8"
 shadow = "9.2.2"
-kover = "0.9.2"
+kover = "0.9.9"
 
 jcommander = "1.82"
 commons-text = "1.3"
@@ -26,15 +26,15 @@ progressbar = "0.7.2"
 hdrhistogram = "2.1.12"
 agrona = "1.22.0"
 parquet = "1.15.2"
-hadoop = "3.4.1"
-junit = "5.1.0"
-junit-params = "5.4.0"
+hadoop = "3.4.3"
+junit = "6.1.3"
+junit-params = "6.1.3"
 assertj = "3.9.1"
-mockk = "1.12.7"
+mockk = "1.14.3"
 coroutines-test = "1.9.0"
 mcp-sdk = "0.7.2"
 ktor = "3.3.0"
-testcontainers = "1.19.8"
+testcontainers = "2.0.5"
 
 [libraries]
 jcommander = { module = "com.beust:jcommander", version.ref = "jcommander" }
@@ -73,6 +73,7 @@ hadoop-mapreduce-client-common = { module = 
"org.apache.hadoop:hadoop-mapreduce-
 
 junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine", 
version.ref = "junit" }
 junit-jupiter-params = { module = "org.junit.jupiter:junit-jupiter-params", 
version.ref = "junit-params" }
+junit-platform-launcher = { module = 
"org.junit.platform:junit-platform-launcher", version.ref = "junit" }
 assertj-core = { module = "org.assertj:assertj-core", version.ref = "assertj" }
 kotlin-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit" }
 kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect" }
@@ -80,7 +81,7 @@ mockk = { module = "io.mockk:mockk", version.ref = "mockk" }
 kotlinx-coroutines-test = { module = 
"org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = 
"coroutines-test" }
 testcontainers-bom = { module = "org.testcontainers:testcontainers-bom", 
version.ref = "testcontainers" }
 testcontainers-core = { module = "org.testcontainers:testcontainers" }
-testcontainers-cassandra = { module = "org.testcontainers:cassandra" }
+testcontainers-cassandra = { module = 
"org.testcontainers:testcontainers-cassandra" }
 
 mcp-sdk = { module = "io.modelcontextprotocol:kotlin-sdk", version.ref = 
"mcp-sdk" }
 ktor-server-core = { module = "io.ktor:ktor-server-core-jvm", version.ref = 
"ktor" }
diff --git a/gradle/wrapper/gradle-wrapper.jar 
b/gradle/wrapper/gradle-wrapper.jar
index 7454180..1b33c55 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and 
b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties 
b/gradle/wrapper/gradle-wrapper.properties
index e69d040..d953c1f 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,7 @@
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.0-all.zip
+networkTimeout=10000
+validateDistributionUrl=true
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index 1b6c787..23d15a9 100755
--- a/gradlew
+++ b/gradlew
@@ -15,6 +15,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
+# SPDX-License-Identifier: Apache-2.0
+#
 
 ##############################################################################
 #
@@ -55,7 +57,7 @@
 #       Darwin, MinGW, and NonStop.
 #
 #   (3) This script is generated from the Groovy template
-#       
https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+#       
https://github.com/gradle/gradle/blob/HEAD/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/.
@@ -80,13 +82,11 @@ do
     esac
 done
 
-APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
-
-APP_NAME="Gradle"
+# This is normally unused
+# shellcheck disable=SC2034
 APP_BASE_NAME=${0##*/}
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to 
pass JVM options to this script.
-DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+# Discard cd standard output in case $CDPATH is set 
(https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd -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
@@ -114,7 +114,7 @@ case "$( uname )" in                #(
   NONSTOP* )        nonstop=true ;;
 esac
 
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+CLASSPATH="\\\"\\\""
 
 
 # Determine the Java command to use to start the JVM.
@@ -133,22 +133,29 @@ location of your Java installation."
     fi
 else
     JAVACMD=java
-    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 
'java' command could be found in your PATH.
+    if ! command -v java >/dev/null 2>&1
+    then
+        die "ERROR: JAVA_HOME is not set and no 'java' command could be found 
in your PATH.
 
 Please set the JAVA_HOME variable in your environment to match the
 location of your Java installation."
+    fi
 fi
 
 # Increase the maximum file descriptors if we can.
 if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
     case $MAX_FD in #(
       max*)
+        # In POSIX sh, ulimit -H is undefined. That's why the result is 
checked to see if it worked.
+        # shellcheck disable=SC2039,SC3045
         MAX_FD=$( ulimit -H -n ) ||
             warn "Could not query maximum file descriptor limit"
     esac
     case $MAX_FD in  #(
       '' | soft) :;; #(
       *)
+        # In POSIX sh, ulimit -n is undefined. That's why the result is 
checked to see if it worked.
+        # shellcheck disable=SC2039,SC3045
         ulimit -n "$MAX_FD" ||
             warn "Could not set maximum file descriptor limit to $MAX_FD"
     esac
@@ -193,18 +200,28 @@ if "$cygwin" || "$msys" ; then
     done
 fi
 
-# Collect all arguments for the java command;
-#   * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
-#     shell script including quotes and variable substitutions, so put them in
-#     double quotes to make sure that they get re-expanded; and
-#   * put everything else in single quotes, so that it's not re-expanded.
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to 
pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+#   * DEFAULT_JVM_OPTS, JAVA_OPTS, 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" \
         -classpath "$CLASSPATH" \
-        org.gradle.wrapper.GradleWrapperMain \
+        -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.
diff --git a/gradlew.bat b/gradlew.bat
index ac1b06f..5eed7ee 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -13,8 +13,10 @@
 @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
+@if "%DEBUG%"=="" @echo off
 @rem ##########################################################################
 @rem
 @rem  Gradle startup script for Windows
@@ -25,7 +27,8 @@
 if "%OS%"=="Windows_NT" setlocal
 
 set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
 set APP_BASE_NAME=%~n0
 set APP_HOME=%DIRNAME%
 
@@ -40,13 +43,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome
 
 set JAVA_EXE=java.exe
 %JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto execute
+if %ERRORLEVEL% equ 0 goto execute
 
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your 
PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
+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
 
@@ -56,32 +59,34 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
 
 if exist "%JAVA_EXE%" goto execute
 
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
+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
 
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+set CLASSPATH=
 
 
 @rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% 
"-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" 
org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% 
"-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar 
"%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
 
 :end
 @rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
+if %ERRORLEVEL% equ 0 goto mainEnd
 
 :fail
 rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code 
instead of
 rem the _cmd.exe /c_ return code!
-if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
 
 :mainEnd
 if "%OS%"=="Windows_NT" endlocal


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to