From ef43d4ae62bb11d289212d56044443bdb60317e9 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Wed, 29 Oct 2025 19:14:54 +0100 Subject: [PATCH 01/59] chore: enforce minimal server version --- .../client6/v1/api/WeaviateClient.java | 5 ++ .../client6/v1/api/WeaviateClientAsync.java | 5 ++ .../WeaviateUnsupportedVersionException.java | 19 ++++++++ .../client6/v1/internal/VersionSupport.java | 46 +++++++++++++++++++ 4 files changed, 75 insertions(+) create mode 100644 src/main/java/io/weaviate/client6/v1/api/WeaviateUnsupportedVersionException.java create mode 100644 src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java diff --git a/src/main/java/io/weaviate/client6/v1/api/WeaviateClient.java b/src/main/java/io/weaviate/client6/v1/api/WeaviateClient.java index a4c51cbe9..63e14c3bf 100644 --- a/src/main/java/io/weaviate/client6/v1/api/WeaviateClient.java +++ b/src/main/java/io/weaviate/client6/v1/api/WeaviateClient.java @@ -13,6 +13,7 @@ import io.weaviate.client6.v1.internal.ObjectBuilder; import io.weaviate.client6.v1.internal.Timeout; import io.weaviate.client6.v1.internal.TokenProvider; +import io.weaviate.client6.v1.internal.VersionSupport; import io.weaviate.client6.v1.internal.grpc.DefaultGrpcTransport; import io.weaviate.client6.v1.internal.grpc.GrpcChannelOptions; import io.weaviate.client6.v1.internal.grpc.GrpcTransport; @@ -105,6 +106,10 @@ public WeaviateClient(Config config) { throw ex; } + if (!VersionSupport.isSupported(meta.version())) { + throw new WeaviateUnsupportedVersionException(meta.version()); + } + if (meta.grpcMaxMessageSize() != null) { grpcOpt = grpcOpt.withMaxMessageSize(meta.grpcMaxMessageSize()); } diff --git a/src/main/java/io/weaviate/client6/v1/api/WeaviateClientAsync.java b/src/main/java/io/weaviate/client6/v1/api/WeaviateClientAsync.java index 7858300ec..1e5b07ae3 100644 --- a/src/main/java/io/weaviate/client6/v1/api/WeaviateClientAsync.java +++ b/src/main/java/io/weaviate/client6/v1/api/WeaviateClientAsync.java @@ -15,6 +15,7 @@ import io.weaviate.client6.v1.internal.ObjectBuilder; import io.weaviate.client6.v1.internal.Timeout; import io.weaviate.client6.v1.internal.TokenProvider; +import io.weaviate.client6.v1.internal.VersionSupport; import io.weaviate.client6.v1.internal.grpc.DefaultGrpcTransport; import io.weaviate.client6.v1.internal.grpc.GrpcChannelOptions; import io.weaviate.client6.v1.internal.grpc.GrpcTransport; @@ -108,6 +109,10 @@ public WeaviateClientAsync(Config config) { throw ex; } + if (!VersionSupport.isSupported(meta.version())) { + throw new WeaviateUnsupportedVersionException(meta.version()); + } + if (meta.grpcMaxMessageSize() != null) { grpcOpt = grpcOpt.withMaxMessageSize(meta.grpcMaxMessageSize()); } diff --git a/src/main/java/io/weaviate/client6/v1/api/WeaviateUnsupportedVersionException.java b/src/main/java/io/weaviate/client6/v1/api/WeaviateUnsupportedVersionException.java new file mode 100644 index 000000000..215fc95b2 --- /dev/null +++ b/src/main/java/io/weaviate/client6/v1/api/WeaviateUnsupportedVersionException.java @@ -0,0 +1,19 @@ +package io.weaviate.client6.v1.api; + +import io.weaviate.client6.v1.internal.VersionSupport; + +/** + * This exception is thrown when the client refuses to talk to an unsupported + * version of the server. + * + * @see VersionSupport#MINIMAL_SUPPORTED_VERSION. + */ +public class WeaviateUnsupportedVersionException extends WeaviateException { + public WeaviateUnsupportedVersionException(String actual) { + this(VersionSupport.MINIMAL_SUPPORTED_VERSION.toString(), actual); + } + + public WeaviateUnsupportedVersionException(String minimal, String actual) { + super("Server version %s is not supported. Earliest supported version is %s.".formatted(actual, minimal)); + } +} diff --git a/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java b/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java new file mode 100644 index 000000000..8cf30c83a --- /dev/null +++ b/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java @@ -0,0 +1,46 @@ +package io.weaviate.client6.v1.internal; + +import java.util.Arrays; + +public final class VersionSupport { + public static final SemanticVersion MINIMAL_SUPPORTED_VERSION = new SemanticVersion(1, 33); + + /** + * Returns true if the {@code version} is the same as or older than the + * {@link VersionSupport#MINIMAL_SUPPORTED_VERSION}. + */ + public static boolean isSupported(String version) { + var semver = SemanticVersion.of(version); + return semver.compareTo(MINIMAL_SUPPORTED_VERSION) >= 0; + } + + public record SemanticVersion(int major, int minor, String patch) implements Comparable { + + public SemanticVersion(int major, int minor) { + this(major, minor, null); + } + + /** + * Parse semantic version from a formatted string, e.g. + * {@code "(v)1.23.6-rc.1"}. + */ + public static SemanticVersion of(String version) { + var parts = version.replaceFirst("v", "").split("\\."); + var major = Integer.valueOf(parts[0].replaceAll("[^0-9]", "")); + var minor = Integer.valueOf(parts[1].replaceAll("[^0-9]", "")); + var patch = String.join(".", Arrays.stream(parts, 2, parts.length).toList()); + return new SemanticVersion(major, minor, patch); + } + + @Override + public int compareTo(SemanticVersion that) { + var this_v = Integer.valueOf("%d%d".formatted(this.major, this.minor)); + var that_v = Integer.valueOf("%d%d".formatted(that.major, that.minor)); + return this_v.compareTo(that_v); + } + + public String toString() { + return String.join(".", String.valueOf(major), String.valueOf(minor), patch); + } + } +} From 9c1adc530b9fa32a3821a66fd962752e1e62474a Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Wed, 29 Oct 2025 19:31:04 +0100 Subject: [PATCH 02/59] test: add unit tests for SemanticVersion --- .../client6/v1/internal/VersionSupport.java | 6 ++- .../v1/internal/VersionSupportTest.java | 40 +++++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 src/test/java/io/weaviate/client6/v1/internal/VersionSupportTest.java diff --git a/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java b/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java index 8cf30c83a..18fc127e9 100644 --- a/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java +++ b/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java @@ -28,7 +28,9 @@ public static SemanticVersion of(String version) { var parts = version.replaceFirst("v", "").split("\\."); var major = Integer.valueOf(parts[0].replaceAll("[^0-9]", "")); var minor = Integer.valueOf(parts[1].replaceAll("[^0-9]", "")); - var patch = String.join(".", Arrays.stream(parts, 2, parts.length).toList()); + var patch = parts.length > 2 + ? String.join(".", Arrays.stream(parts, 2, parts.length).toList()) + : null; return new SemanticVersion(major, minor, patch); } @@ -40,7 +42,7 @@ public int compareTo(SemanticVersion that) { } public String toString() { - return String.join(".", String.valueOf(major), String.valueOf(minor), patch); + return String.join(".", String.valueOf(major), String.valueOf(minor), patch != null ? patch : ""); } } } diff --git a/src/test/java/io/weaviate/client6/v1/internal/VersionSupportTest.java b/src/test/java/io/weaviate/client6/v1/internal/VersionSupportTest.java new file mode 100644 index 000000000..e735f6738 --- /dev/null +++ b/src/test/java/io/weaviate/client6/v1/internal/VersionSupportTest.java @@ -0,0 +1,40 @@ +package io.weaviate.client6.v1.internal; + +import org.assertj.core.api.Assertions; +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.jparams.junit4.JParamsTestRunner; +import com.jparams.junit4.data.DataMethod; + +import io.weaviate.client6.v1.internal.VersionSupport.SemanticVersion; + +@RunWith(JParamsTestRunner.class) +public class VersionSupportTest { + public static Object[][] testCases() { + return new Object[][] { + { "1.31.6", "v1.32.1", true }, // can have a leading v + { "v1.33.0", "1.32.1", false }, // can have a leading v + { "2.36.2", "2.36.0-rc.3", true }, // patch ignored + { "1.12", "1.11", false }, // omit patch + { "0.55.6", "0.1.0", false }, // can start with zero + }; + } + + @Test + @DataMethod(source = VersionSupportTest.class, method = "testCases") + public void test_isSupported(String minimal, String actual, boolean isSupported) { + var v_minimal = SemanticVersion.of(minimal); + var v_actual = SemanticVersion.of(actual); + + if (isSupported) { + Assertions.assertThat(v_actual) + .describedAs("%s supported (minimal=%s)", actual, minimal) + .isGreaterThanOrEqualTo(v_minimal); + } else { + Assertions.assertThat(v_actual) + .describedAs("%s not supported (minimal=%s)", actual, minimal) + .isLessThan(v_minimal); + } + } +} From 0ce5a586a2f9adb1a16d2ad5374af35cec7d981b Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Wed, 29 Oct 2025 19:35:28 +0100 Subject: [PATCH 03/59] chore: fix javadoc --- .../client6/v1/api/WeaviateUnsupportedVersionException.java | 4 +--- .../java/io/weaviate/client6/v1/internal/VersionSupport.java | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/io/weaviate/client6/v1/api/WeaviateUnsupportedVersionException.java b/src/main/java/io/weaviate/client6/v1/api/WeaviateUnsupportedVersionException.java index 215fc95b2..1e4e27580 100644 --- a/src/main/java/io/weaviate/client6/v1/api/WeaviateUnsupportedVersionException.java +++ b/src/main/java/io/weaviate/client6/v1/api/WeaviateUnsupportedVersionException.java @@ -4,9 +4,7 @@ /** * This exception is thrown when the client refuses to talk to an unsupported - * version of the server. - * - * @see VersionSupport#MINIMAL_SUPPORTED_VERSION. + * version of the server, see {@link VersionSupport#MINIMAL_SUPPORTED_VERSION}. */ public class WeaviateUnsupportedVersionException extends WeaviateException { public WeaviateUnsupportedVersionException(String actual) { diff --git a/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java b/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java index 18fc127e9..e3a10f4d3 100644 --- a/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java +++ b/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java @@ -21,8 +21,8 @@ public SemanticVersion(int major, int minor) { } /** - * Parse semantic version from a formatted string, e.g. - * {@code "(v)1.23.6-rc.1"}. + * Parse semantic version from a formatted string, + * e.g. {@code "(v)1.23.6-rc.1"}. */ public static SemanticVersion of(String version) { var parts = version.replaceFirst("v", "").split("\\."); From f335f9c1c14be957a2d31231425da6ecddb47e95 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Wed, 29 Oct 2025 19:44:04 +0100 Subject: [PATCH 04/59] chore: set minimal server version to 1.31 --- .../java/io/weaviate/client6/v1/internal/VersionSupport.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java b/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java index e3a10f4d3..6ba324630 100644 --- a/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java +++ b/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java @@ -3,7 +3,7 @@ import java.util.Arrays; public final class VersionSupport { - public static final SemanticVersion MINIMAL_SUPPORTED_VERSION = new SemanticVersion(1, 33); + public static final SemanticVersion MINIMAL_SUPPORTED_VERSION = new SemanticVersion(1, 31); /** * Returns true if the {@code version} is the same as or older than the From 03530ed5976888ed22265d3d0c3a998ece471d73 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Tue, 4 Nov 2025 12:35:55 +0100 Subject: [PATCH 05/59] test: upgrate Surefire to 3.5.4 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2bb5f2e68..8eb7bd5b0 100644 --- a/pom.xml +++ b/pom.xml @@ -229,7 +229,7 @@ maven-surefire-plugin - 2.22.2 + 3.5.4 false From 1a4fbfc8dbf6588fb2c3bc5de4b3cf206ff378bb Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Tue, 4 Nov 2025 13:40:13 +0100 Subject: [PATCH 06/59] ci: run tests in parallel Reduces test execution time from 1:20min to ~45s --- .gitignore | 2 + pom.xml | 12 ++--- .../io/weaviate/containers/Container.java | 12 ----- .../io/weaviate/containers/TestListener.java | 14 ----- .../java/io/weaviate/containers/Weaviate.java | 16 ++++++ .../integration/CollectionsITest.java | 54 ++++++++++--------- .../data/ReferenceAddManyResponse.java | 16 ++++-- 7 files changed, 64 insertions(+), 62 deletions(-) delete mode 100644 src/it/java/io/weaviate/containers/TestListener.java diff --git a/.gitignore b/.gitignore index 052460830..ee565b6c5 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,5 @@ target/ # maven-lombok-plugin .factorypath +# Surefire statistics for optimized execution time +.surefire-* diff --git a/pom.xml b/pom.xml index 8eb7bd5b0..f543517dc 100644 --- a/pom.xml +++ b/pom.xml @@ -232,6 +232,12 @@ 3.5.4 false + classes + 4 + true + 1 + true + balanced --add-opens=java.base/java.lang=ALL-UNNAMED - - - listener - io.weaviate.containers.TestListener - - diff --git a/src/it/java/io/weaviate/containers/Container.java b/src/it/java/io/weaviate/containers/Container.java index 7c71ed980..304dbea91 100644 --- a/src/it/java/io/weaviate/containers/Container.java +++ b/src/it/java/io/weaviate/containers/Container.java @@ -18,18 +18,6 @@ public class Container { public static final Img2VecNeural IMG2VEC_NEURAL = Img2VecNeural.createDefault(); public static final MinIo MINIO = MinIo.createDefault(); - /** - * Stop all shared Testcontainers created in {@link #startAll}. - *

- * Testcontainer's Ryuk will reap any dangling containers after the tests - * finish. However, since {@link Weaviate} instances also hold a - * {@link WeaviateClient}, we want to stop them proactively to - * close client connections. - */ - static void stopAll() { - WEAVIATE.stop(); - } - public static ContainerGroup compose(Weaviate weaviate, GenericContainer... containers) { return new ContainerGroup(weaviate, containers); } diff --git a/src/it/java/io/weaviate/containers/TestListener.java b/src/it/java/io/weaviate/containers/TestListener.java deleted file mode 100644 index 72889125b..000000000 --- a/src/it/java/io/weaviate/containers/TestListener.java +++ /dev/null @@ -1,14 +0,0 @@ -package io.weaviate.containers; - -import org.junit.runner.Result; -import org.junit.runner.notification.RunListener; - -public class TestListener extends RunListener { - - @Override - public void testRunFinished(Result result) throws Exception { - Container.stopAll(); - super.testRunFinished(result); - } - -} diff --git a/src/it/java/io/weaviate/containers/Weaviate.java b/src/it/java/io/weaviate/containers/Weaviate.java index caaa7df88..565e1e98b 100644 --- a/src/it/java/io/weaviate/containers/Weaviate.java +++ b/src/it/java/io/weaviate/containers/Weaviate.java @@ -71,6 +71,22 @@ public WeaviateClient getClient() { return clientInstance; } + /** + * Get client that is not shared with other tests / callers. + * The returned client is not wrapped in an instance of {@link SharedClient}, + * so it can be auto-closed by the try-with-resources statement when it exists. + */ + public WeaviateClient getBareClient() { + if (!isRunning()) { + start(); + } + try { + return new WeaviateClient(Config.of(defaultConfigFn())); + } catch (Exception e) { + throw new RuntimeException("create WeaviateClient for Weaviate container", e); + } + } + /** * Create a new instance of WeaviateClient connected to this container. * Prefer using {@link #getClient} unless your test needs the initialization diff --git a/src/it/java/io/weaviate/integration/CollectionsITest.java b/src/it/java/io/weaviate/integration/CollectionsITest.java index e9d1afa87..c46a7502a 100644 --- a/src/it/java/io/weaviate/integration/CollectionsITest.java +++ b/src/it/java/io/weaviate/integration/CollectionsITest.java @@ -21,6 +21,7 @@ import io.weaviate.client6.v1.api.collections.vectorindex.Hnsw; import io.weaviate.client6.v1.api.collections.vectorizers.SelfProvidedVectorizer; import io.weaviate.containers.Container; +import io.weaviate.containers.Weaviate; public class CollectionsITest extends ConcurrentTest { private static WeaviateClient client = Container.WEAVIATE.getClient(); @@ -95,31 +96,34 @@ public void testCrossReferences() throws IOException { } @Test - public void testListDeleteAll() throws IOException { - var nsA = ns("A"); - var nsB = ns("B"); - var nsC = ns("C"); - - client.collections.create(nsA); - client.collections.create(nsB); - client.collections.create(nsC); - - Assertions.assertThat(client.collections.exists(nsA)).isTrue(); - Assertions.assertThat(client.collections.exists(nsB)).isTrue(); - Assertions.assertThat(client.collections.exists(nsC)).isTrue(); - Assertions.assertThat(client.collections.exists(ns("X"))).isFalse(); - - var all = client.collections.list(); - Assertions.assertThat(all) - .hasSizeGreaterThanOrEqualTo(3) - .extracting(CollectionConfig::collectionName) - .contains(nsA, nsB, nsC); - - client.collections.deleteAll(); - - all = client.collections.list(); - Assertions.assertThat(all.isEmpty()); - + public void testListDeleteAll() throws Exception { + // Use a separate container for this test so as not to interfere + // with other tests. + try (final var _client = Weaviate.createDefault().getBareClient()) { + var nsA = ns("A"); + var nsB = ns("B"); + var nsC = ns("C"); + + _client.collections.create(nsA); + _client.collections.create(nsB); + _client.collections.create(nsC); + + Assertions.assertThat(_client.collections.exists(nsA)).isTrue(); + Assertions.assertThat(_client.collections.exists(nsB)).isTrue(); + Assertions.assertThat(_client.collections.exists(nsC)).isTrue(); + Assertions.assertThat(_client.collections.exists(ns("X"))).isFalse(); + + var all = _client.collections.list(); + Assertions.assertThat(all) + .hasSizeGreaterThanOrEqualTo(3) + .extracting(CollectionConfig::collectionName) + .contains(nsA, nsB, nsC); + + _client.collections.deleteAll(); + + all = _client.collections.list(); + Assertions.assertThat(all.isEmpty()); + } } @Test diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/data/ReferenceAddManyResponse.java b/src/main/java/io/weaviate/client6/v1/api/collections/data/ReferenceAddManyResponse.java index d0fc89ace..d7c70d7fa 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/data/ReferenceAddManyResponse.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/data/ReferenceAddManyResponse.java @@ -24,11 +24,17 @@ public ReferenceAddManyResponse deserialize(JsonElement json, Type typeOfT, Json int i = 0; for (var el : json.getAsJsonArray()) { var result = el.getAsJsonObject().get("result").getAsJsonObject(); - if (result.get("status").getAsString().equals("FAILED")) { - var errorMsg = result - .get("errors").getAsJsonObject() - .get("error").getAsJsonArray() - .get(0).getAsString(); + if (result.get("status").getAsString().equals("FAILED") + && result.has("errors")) { + String errorMsg; + try { + errorMsg = result + .get("errors").getAsJsonObject() + .get("error").getAsJsonArray() + .get(0).getAsString(); + } catch (Exception e) { + errorMsg = result.get("errors").toString(); + } var batchErr = new BatchError(errorMsg, null, i); errors.add(batchErr); From 52e697c98e4e0ef3090c7eee307223178abd8b20 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Tue, 4 Nov 2025 13:45:04 +0100 Subject: [PATCH 07/59] test: remove ALL-UNNAMED opens from test config --- pom.xml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/pom.xml b/pom.xml index f543517dc..35a5efcfa 100644 --- a/pom.xml +++ b/pom.xml @@ -238,15 +238,6 @@ 1 true balanced - - - --add-opens=java.base/java.lang=ALL-UNNAMED - From 4f93a3561d82922dfd2bd64ad09f2343e9cf4a11 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Wed, 5 Nov 2025 22:55:53 +0100 Subject: [PATCH 08/59] ci: extend test matrix to 2 latest Weaviate versions --- .github/workflows/test.yaml | 82 +++++++++++++++---- .../java/io/weaviate/containers/Weaviate.java | 8 +- 2 files changed, 75 insertions(+), 15 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 303bba5d8..7948b94b2 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -4,33 +4,87 @@ on: branches: - main pull_request: +concurrency: + group: tests-${{ github.ref }} + cancel-in-progress: true + +env: + IMG2VEC: cr.weaviate.io/semitechnologies/img2vec-pytorch:resnet50 + MINIO: minio/minio:latest + MODEL2VEC: cr.weaviate.io/semitechnologies/model2vec-inference:minishlab-potion-retrieval-32M + SUPPORTED_VERSIONS: '["1.32.0", "1.33.0"]' + DOCKER_CACHE_KEY: docker-images-${{ env.IMG2VEC }}-${{ env.MINIO }}-${{ env.MODEL2VEC }} + DOCKER_IMAGES_TAR: docker-images.tar jobs: - tests: - name: Tests + docker-cache: + name: Cache shared Docker images runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - with: - ref: ${{ github.sha }} - name: Login to Docker Hub if: ${{ !github.event.pull_request.head.repo.fork }} - uses: docker/login-action@v2 + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + - name: Restore and update Docker cache + id: docker-cache-restore + uses: actions/cache@v4 + with: + path: ${{ env.DOCKER_IMAGES_TAR }} + key: ${{ env.DOCKER_CACHE_KEY }} + - name: Pull images + if: steps.docker-cache-restore.outputs.cache-hit != 'true' + run: | + docker pull $IMG2VEC + docker pull $MINIO + docker pull $MODEL2VEC + docker save $IMG2VEC $MINIO $MODEL2VEC -o $DOCKER_IMAGES_TAR + + maven-cache: + name: Cache Maven dependencies + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-java@v4 + with: + distribution: 'zulu' + java-version: '17' + cache: 'maven' + - run: mvn dependency:go-offline + + test: + name: Test + runs-on: ubuntu-latest + needs: [ docker-cache, maven-cache] + strategy: + matrix: + WEAVIATE_VERSION: ${{ fromJson(env.SUPPORTED_VERSIONS) }} + steps: + - uses: actions/checkout@v4 + + - uses: actions/cache@v4 with: - username: ${{secrets.DOCKER_USERNAME}} - password: ${{secrets.DOCKER_PASSWORD}} - - name: Setup JDK - uses: actions/setup-java@v4 + path: ${{ env.DOCKER_IMAGES_TAR }} + key: ${{ env.DOCKER_CACHE_KEY }} + - name: Load Docker images + run: | + if [ -f $DOCKER_IMAGES_TAR ]; then + docker load -i $DOCKER_IMAGES_TAR + fi + - uses: actions/setup-java@v4 + name: Setup JDK with: distribution: 'zulu' java-version: '17' - - name: Run Build - run: mvn -DskipTests clean package - - name: Run Tests + cache: 'maven' + + - name: Run Tests (v${{ matrix.WEAVIATE_VERSION }}) env: OKTA_DUMMY_CI_PW: ${{ secrets.OKTA_DUMMY_CI_PW }} WCS_DUMMY_CI_PW: ${{ secrets.WCS_DUMMY_CI_PW }} OKTA_CLIENT_SECRET: ${{ secrets.OKTA_CLIENT_SECRET }} AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} OPENAI_APIKEY: ${{ secrets.OPENAI_APIKEY }} - run: mvn clean test + WEAVIATE_VERSION: ${{ matrix.WEAVIATE_VERSION }} + run: mvn verify diff --git a/src/it/java/io/weaviate/containers/Weaviate.java b/src/it/java/io/weaviate/containers/Weaviate.java index 565e1e98b..f7b192ac6 100644 --- a/src/it/java/io/weaviate/containers/Weaviate.java +++ b/src/it/java/io/weaviate/containers/Weaviate.java @@ -21,8 +21,14 @@ import io.weaviate.client6.v1.internal.ObjectBuilder; public class Weaviate extends WeaviateContainer { - public static final String VERSION = "1.33.0"; public static final String DOCKER_IMAGE = "semitechnologies/weaviate"; + public static final String LATEST_VERSION = "1.33.0"; + public static final String VERSION; + + static { + VERSION = System.getenv().getOrDefault("WEAVIATE_VERSION", LATEST_VERSION); + } + public static String OIDC_ISSUER = "https://auth.wcs.api.weaviate.io/auth/realms/SeMI"; private volatile SharedClient clientInstance; From 903c8099005d6b17d56f76c264587a36a044c174 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Wed, 5 Nov 2025 23:07:16 +0100 Subject: [PATCH 09/59] ci: fix syntax --- .github/workflows/test.yaml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 7948b94b2..2ba3ccac5 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -12,8 +12,6 @@ env: IMG2VEC: cr.weaviate.io/semitechnologies/img2vec-pytorch:resnet50 MINIO: minio/minio:latest MODEL2VEC: cr.weaviate.io/semitechnologies/model2vec-inference:minishlab-potion-retrieval-32M - SUPPORTED_VERSIONS: '["1.32.0", "1.33.0"]' - DOCKER_CACHE_KEY: docker-images-${{ env.IMG2VEC }}-${{ env.MINIO }}-${{ env.MODEL2VEC }} DOCKER_IMAGES_TAR: docker-images.tar jobs: @@ -30,6 +28,8 @@ jobs: - name: Restore and update Docker cache id: docker-cache-restore uses: actions/cache@v4 + env: + DOCKER_CACHE_KEY: docker-images-${{ env.IMG2VEC }}-${{ env.MINIO }}-${{ env.MODEL2VEC }} with: path: ${{ env.DOCKER_IMAGES_TAR }} key: ${{ env.DOCKER_CACHE_KEY }} @@ -59,11 +59,13 @@ jobs: needs: [ docker-cache, maven-cache] strategy: matrix: - WEAVIATE_VERSION: ${{ fromJson(env.SUPPORTED_VERSIONS) }} + WEAVIATE_VERSION: ["1.32", "1.33"] steps: - uses: actions/checkout@v4 - uses: actions/cache@v4 + env: + DOCKER_CACHE_KEY: docker-images-${{ env.IMG2VEC }}-${{ env.MINIO }}-${{ env.MODEL2VEC }} with: path: ${{ env.DOCKER_IMAGES_TAR }} key: ${{ env.DOCKER_CACHE_KEY }} From 01a75b58a4fd24d2079fd6b3f0062af6efcd3f62 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Wed, 5 Nov 2025 23:19:08 +0100 Subject: [PATCH 10/59] chore: use smaller image --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 2ba3ccac5..41b97385c 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -11,7 +11,7 @@ concurrency: env: IMG2VEC: cr.weaviate.io/semitechnologies/img2vec-pytorch:resnet50 MINIO: minio/minio:latest - MODEL2VEC: cr.weaviate.io/semitechnologies/model2vec-inference:minishlab-potion-retrieval-32M + MODEL2VEC: cr.weaviate.io/semitechnologies/model2vec-inference:minishlab-potion-base-4M DOCKER_IMAGES_TAR: docker-images.tar jobs: From 70bdad6a94a013f6ac14c521efd5371f5fb3afa5 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Wed, 5 Nov 2025 23:29:13 +0100 Subject: [PATCH 11/59] debug(ci): do not cache model2vec image --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 41b97385c..c123f2aa5 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -38,7 +38,7 @@ jobs: run: | docker pull $IMG2VEC docker pull $MINIO - docker pull $MODEL2VEC + # docker pull $MODEL2VEC docker save $IMG2VEC $MINIO $MODEL2VEC -o $DOCKER_IMAGES_TAR maven-cache: From cfa860dfb5392a49d490b0c2061edda4761a3611 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Wed, 5 Nov 2025 23:37:24 +0100 Subject: [PATCH 12/59] ci(fix): do not save model2vec image --- .github/workflows/test.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index c123f2aa5..a0a2f1067 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -10,7 +10,7 @@ concurrency: env: IMG2VEC: cr.weaviate.io/semitechnologies/img2vec-pytorch:resnet50 - MINIO: minio/minio:latest + MINIO: minio/minio MODEL2VEC: cr.weaviate.io/semitechnologies/model2vec-inference:minishlab-potion-base-4M DOCKER_IMAGES_TAR: docker-images.tar @@ -39,7 +39,7 @@ jobs: docker pull $IMG2VEC docker pull $MINIO # docker pull $MODEL2VEC - docker save $IMG2VEC $MINIO $MODEL2VEC -o $DOCKER_IMAGES_TAR + docker save $IMG2VEC $MINIO -o $DOCKER_IMAGES_TAR maven-cache: name: Cache Maven dependencies From 2634d96b557c9416f7bcf59597d20d6532323368 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Wed, 5 Nov 2025 23:45:09 +0100 Subject: [PATCH 13/59] ci(fix): use correct version tag --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index a0a2f1067..5f572f968 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -59,7 +59,7 @@ jobs: needs: [ docker-cache, maven-cache] strategy: matrix: - WEAVIATE_VERSION: ["1.32", "1.33"] + WEAVIATE_VERSION: ["1.32.0", "1.33.0"] steps: - uses: actions/checkout@v4 From f70d37683755adc75c998886c448ab8537bf3265 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Wed, 5 Nov 2025 23:54:52 +0100 Subject: [PATCH 14/59] chore: user lookup-only restore in Docker Cache step --- .github/workflows/test.yaml | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 5f572f968..9c95fcf66 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -18,6 +18,8 @@ jobs: docker-cache: name: Cache shared Docker images runs-on: ubuntu-latest + env: + DOCKER_CACHE_KEY: docker-images-${{ env.IMG2VEC }}-${{ env.MINIO }}-${{ env.MODEL2VEC }} steps: - name: Login to Docker Hub if: ${{ !github.event.pull_request.head.repo.fork }} @@ -25,21 +27,25 @@ jobs: with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - - name: Restore and update Docker cache - id: docker-cache-restore - uses: actions/cache@v4 - env: - DOCKER_CACHE_KEY: docker-images-${{ env.IMG2VEC }}-${{ env.MINIO }}-${{ env.MODEL2VEC }} + - id: cache-check + uses: actions/cache/restore@v4 with: path: ${{ env.DOCKER_IMAGES_TAR }} key: ${{ env.DOCKER_CACHE_KEY }} + lookup-only: true # Only check if cache exists, don't download - name: Pull images - if: steps.docker-cache-restore.outputs.cache-hit != 'true' + if: steps.cache-check.outputs.cache-hit != 'true' run: | docker pull $IMG2VEC docker pull $MINIO # docker pull $MODEL2VEC docker save $IMG2VEC $MINIO -o $DOCKER_IMAGES_TAR + - name: Cache images + if: steps.cache-check.outputs.cache-hit != 'true' + uses: actions/cache/save@v4 + with: + path: ${{ env.DOCKER_IMAGES_TAR }} + key: ${{ env.DOCKER_CACHE_KEY }} maven-cache: name: Cache Maven dependencies @@ -57,15 +63,15 @@ jobs: name: Test runs-on: ubuntu-latest needs: [ docker-cache, maven-cache] + env: + DOCKER_CACHE_KEY: docker-images-${{ env.IMG2VEC }}-${{ env.MINIO }}-${{ env.MODEL2VEC }} strategy: matrix: WEAVIATE_VERSION: ["1.32.0", "1.33.0"] steps: - uses: actions/checkout@v4 - - uses: actions/cache@v4 - env: - DOCKER_CACHE_KEY: docker-images-${{ env.IMG2VEC }}-${{ env.MINIO }}-${{ env.MODEL2VEC }} + - uses: actions/cache/restore@v4 with: path: ${{ env.DOCKER_IMAGES_TAR }} key: ${{ env.DOCKER_CACHE_KEY }} From 99779df2c9767408ad232b52dbce62537795ccb1 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Wed, 5 Nov 2025 23:57:08 +0100 Subject: [PATCH 15/59] ci(fix): move env definition --- .github/workflows/test.yaml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 9c95fcf66..6eea4c120 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -18,8 +18,6 @@ jobs: docker-cache: name: Cache shared Docker images runs-on: ubuntu-latest - env: - DOCKER_CACHE_KEY: docker-images-${{ env.IMG2VEC }}-${{ env.MINIO }}-${{ env.MODEL2VEC }} steps: - name: Login to Docker Hub if: ${{ !github.event.pull_request.head.repo.fork }} @@ -29,6 +27,8 @@ jobs: password: ${{ secrets.DOCKER_PASSWORD }} - id: cache-check uses: actions/cache/restore@v4 + env: + DOCKER_CACHE_KEY: docker-images-${{ env.IMG2VEC }}-${{ env.MINIO }}-${{ env.MODEL2VEC }} with: path: ${{ env.DOCKER_IMAGES_TAR }} key: ${{ env.DOCKER_CACHE_KEY }} @@ -43,6 +43,8 @@ jobs: - name: Cache images if: steps.cache-check.outputs.cache-hit != 'true' uses: actions/cache/save@v4 + env: + DOCKER_CACHE_KEY: docker-images-${{ env.IMG2VEC }}-${{ env.MINIO }}-${{ env.MODEL2VEC }} with: path: ${{ env.DOCKER_IMAGES_TAR }} key: ${{ env.DOCKER_CACHE_KEY }} @@ -63,8 +65,6 @@ jobs: name: Test runs-on: ubuntu-latest needs: [ docker-cache, maven-cache] - env: - DOCKER_CACHE_KEY: docker-images-${{ env.IMG2VEC }}-${{ env.MINIO }}-${{ env.MODEL2VEC }} strategy: matrix: WEAVIATE_VERSION: ["1.32.0", "1.33.0"] @@ -72,6 +72,8 @@ jobs: - uses: actions/checkout@v4 - uses: actions/cache/restore@v4 + env: + DOCKER_CACHE_KEY: docker-images-${{ env.IMG2VEC }}-${{ env.MINIO }}-${{ env.MODEL2VEC }} with: path: ${{ env.DOCKER_IMAGES_TAR }} key: ${{ env.DOCKER_CACHE_KEY }} From bd7c1a51885d951d4a591e86a18c0047a1fe9a36 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Thu, 6 Nov 2025 00:04:09 +0100 Subject: [PATCH 16/59] ci: disable fail-fast --- .github/workflows/test.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 6eea4c120..76a2ea2fc 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -66,6 +66,7 @@ jobs: runs-on: ubuntu-latest needs: [ docker-cache, maven-cache] strategy: + fail-fast: false matrix: WEAVIATE_VERSION: ["1.32.0", "1.33.0"] steps: From 4d0fb6f32c43ab351a3b8e06342405f795f1ab79 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Thu, 6 Nov 2025 00:13:39 +0100 Subject: [PATCH 17/59] ci: skip GPG signing for tests job --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 76a2ea2fc..d3facfdee 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -98,4 +98,4 @@ jobs: AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} OPENAI_APIKEY: ${{ secrets.OPENAI_APIKEY }} WEAVIATE_VERSION: ${{ matrix.WEAVIATE_VERSION }} - run: mvn verify + run: mvn verify -Dgpg.skip From ac98d42bdea19362ecda92aad671e03d99e9feb7 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Thu, 6 Nov 2025 11:11:36 +0100 Subject: [PATCH 18/59] chore: skip tests that require a later version --- src/it/java/io/weaviate/ConcurrentTest.java | 24 +++++++++++++++++++ .../io/weaviate/integration/RbacITest.java | 17 ++++++++----- .../api/rbac/roles/WeaviateRolesClient.java | 15 ++++++++++++ 3 files changed, 50 insertions(+), 6 deletions(-) diff --git a/src/it/java/io/weaviate/ConcurrentTest.java b/src/it/java/io/weaviate/ConcurrentTest.java index 57584e047..83c4be098 100644 --- a/src/it/java/io/weaviate/ConcurrentTest.java +++ b/src/it/java/io/weaviate/ConcurrentTest.java @@ -10,9 +10,13 @@ import org.apache.commons.lang3.RandomStringUtils; import org.assertj.core.api.Assertions; +import org.assertj.core.api.Assumptions; import org.junit.Rule; import org.junit.rules.TestName; +import io.weaviate.client6.v1.internal.VersionSupport.SemanticVersion; +import io.weaviate.containers.Weaviate; + /** * ConcurrentTest is the base class for integration tests, which provides * utility methods to uniqualize collections and objects created in the @@ -110,4 +114,24 @@ public static void eventually(Callable cond, int intervalMillis, int ti throw new RuntimeException(ex); } } + + /** + * Skip the test if the version that the {@link Weaviate} + * container is running is older than the required one. + */ + public static void requireAtLeast(int major, int minor) { + var required = new SemanticVersion(major, minor); + var actual = SemanticVersion.of(Weaviate.VERSION); + Assumptions.assumeThat(actual) + .as("requires at least %s, but running %s", required, actual) + .isGreaterThanOrEqualTo(required); + } + + public static void requireAtLeast(int major, int minor, Runnable r) { + var required = new SemanticVersion(major, minor); + var actual = SemanticVersion.of(Weaviate.VERSION); + if (actual.compareTo(required) >= 0) { + r.run(); + } + } } diff --git a/src/it/java/io/weaviate/integration/RbacITest.java b/src/it/java/io/weaviate/integration/RbacITest.java index 7f3b90ff2..3922e6283 100644 --- a/src/it/java/io/weaviate/integration/RbacITest.java +++ b/src/it/java/io/weaviate/integration/RbacITest.java @@ -1,7 +1,7 @@ package io.weaviate.integration; import java.io.IOException; -import java.util.Arrays; +import java.util.List; import org.assertj.core.api.Assertions; import org.assertj.core.api.InstanceOfAssertFactories; @@ -64,7 +64,7 @@ public void test_roles_Lifecycle() throws IOException { var myCollection = "Things"; var nsRole = ns("VectorOwner"); - Permission[] permissions = new Permission[] { + List permissions = List.of( Permission.aliases("ThingsAlias", myCollection, AliasesPermission.Action.CREATE), Permission.backups(myCollection, BackupsPermission.Action.MANAGE), Permission.cluster(ClusterPermission.Action.READ), @@ -72,11 +72,14 @@ public void test_roles_Lifecycle() throws IOException { Permission.roles(VIEWER_ROLE, Scope.MATCH, RolesPermission.Action.CREATE), Permission.collections(myCollection, CollectionsPermission.Action.CREATE), Permission.data(myCollection, DataPermission.Action.UPDATE), - Permission.groups("my-group", GroupType.OIDC, GroupsPermission.Action.READ), Permission.tenants(myCollection, "my-tenant", TenantsPermission.Action.DELETE), Permission.users("my-user", UsersPermission.Action.READ), - Permission.replicate(myCollection, "my-shard", ReplicatePermission.Action.READ), - }; + Permission.replicate(myCollection, "my-shard", ReplicatePermission.Action.READ)); + + requireAtLeast(1, 33, () -> { + permissions.add( + Permission.groups("my-group", GroupType.OIDC, GroupsPermission.Action.READ)); + }); // Act: create role client.roles.create(nsRole, permissions); @@ -86,7 +89,7 @@ public void test_roles_Lifecycle() throws IOException { .as("created role") .returns(nsRole, Role::name) .extracting(Role::permissions, InstanceOfAssertFactories.list(Permission.class)) - .containsAll(Arrays.asList(permissions)); + .containsAll(permissions); // Act:: add extra permissions var extra = new Permission[] { @@ -150,6 +153,8 @@ public void test_roles_userAssignments() throws IOException { @Test public void test_groups() throws IOException { + requireAtLeast(1, 33); + var mediaGroup = "./media-group"; var friendGroup = "./friend-group"; diff --git a/src/main/java/io/weaviate/client6/v1/api/rbac/roles/WeaviateRolesClient.java b/src/main/java/io/weaviate/client6/v1/api/rbac/roles/WeaviateRolesClient.java index b1120465a..4cea55f8b 100644 --- a/src/main/java/io/weaviate/client6/v1/api/rbac/roles/WeaviateRolesClient.java +++ b/src/main/java/io/weaviate/client6/v1/api/rbac/roles/WeaviateRolesClient.java @@ -29,6 +29,21 @@ public WeaviateRolesClient(RestTransport restTransport) { * or the server being unavailable. */ public void create(String roleName, Permission... permissions) throws IOException { + create(roleName, Arrays.asList(permissions)); + } + + /** + * Create a new role. + * + * @param roleName Role name. + * @param permissions Permissions granted to the role. + * @throws WeaviateApiException in case the server returned with an + * error status code. + * @throws IOException in case the request was not sent successfully + * due to a malformed request, a networking error + * or the server being unavailable. + */ + public void create(String roleName, List permissions) throws IOException { var role = new Role(roleName, permissions); this.restTransport.performRequest(new CreateRoleRequest(role), CreateRoleRequest._ENDPOINT); } From 5c7e7f390fb20cfd933a9061794c00587ad21d3c Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Thu, 6 Nov 2025 11:12:33 +0100 Subject: [PATCH 19/59] ci: expand test matrix --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index d3facfdee..852f40c6a 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -68,7 +68,7 @@ jobs: strategy: fail-fast: false matrix: - WEAVIATE_VERSION: ["1.32.0", "1.33.0"] + WEAVIATE_VERSION: ["1.30.0", "1.31.0", "1.32.0", "1.33.0"] steps: - uses: actions/checkout@v4 From 9ad739ec1c42ec99290209471bec282879883c90 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Thu, 6 Nov 2025 11:28:39 +0100 Subject: [PATCH 20/59] ci: disable some tests for earlier versions --- src/it/java/io/weaviate/integration/AliasITest.java | 6 ++++++ src/it/java/io/weaviate/integration/BackupITest.java | 4 ++++ src/it/java/io/weaviate/integration/RbacITest.java | 5 ++++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/it/java/io/weaviate/integration/AliasITest.java b/src/it/java/io/weaviate/integration/AliasITest.java index 0fc40fc6b..3e1623321 100644 --- a/src/it/java/io/weaviate/integration/AliasITest.java +++ b/src/it/java/io/weaviate/integration/AliasITest.java @@ -4,6 +4,7 @@ import java.util.List; import org.assertj.core.api.Assertions; +import org.junit.BeforeClass; import org.junit.Test; import io.weaviate.ConcurrentTest; @@ -14,6 +15,11 @@ public class AliasITest extends ConcurrentTest { private static final WeaviateClient client = Container.WEAVIATE.getClient(); + @BeforeClass + public static void __() { + requireAtLeast(1, 32); + } + @Test public void test_aliasLifecycle() throws IOException { // Arrange diff --git a/src/it/java/io/weaviate/integration/BackupITest.java b/src/it/java/io/weaviate/integration/BackupITest.java index bf0997930..3e8c80a99 100644 --- a/src/it/java/io/weaviate/integration/BackupITest.java +++ b/src/it/java/io/weaviate/integration/BackupITest.java @@ -29,6 +29,8 @@ public class BackupITest extends ConcurrentTest { @Test public void test_lifecycle() throws IOException, TimeoutException { + requireAtLeast(1, 32); // List backups not implemented in earlier versions + // Arrange String nsA = ns("A"), nsB = ns("B"), nsC = ns("C"), nsBig = ns("Big"); String backup_1 = ns("backup_1").toLowerCase(); @@ -122,6 +124,8 @@ public void test_lifecycle() throws IOException, TimeoutException { @Test public void test_lifecycle_async() throws ExecutionException, InterruptedException, Exception { + requireAtLeast(1, 32); // List backups not implemented in earlier versions + // Arrange String nsA = ns("A"), nsB = ns("B"), nsC = ns("C"), nsBig = ns("Big"); String backup_1 = ns("backup_1").toLowerCase(); diff --git a/src/it/java/io/weaviate/integration/RbacITest.java b/src/it/java/io/weaviate/integration/RbacITest.java index 3922e6283..c6de5e220 100644 --- a/src/it/java/io/weaviate/integration/RbacITest.java +++ b/src/it/java/io/weaviate/integration/RbacITest.java @@ -65,7 +65,6 @@ public void test_roles_Lifecycle() throws IOException { var nsRole = ns("VectorOwner"); List permissions = List.of( - Permission.aliases("ThingsAlias", myCollection, AliasesPermission.Action.CREATE), Permission.backups(myCollection, BackupsPermission.Action.MANAGE), Permission.cluster(ClusterPermission.Action.READ), Permission.nodes(myCollection, NodesPermission.Action.READ), @@ -76,6 +75,10 @@ public void test_roles_Lifecycle() throws IOException { Permission.users("my-user", UsersPermission.Action.READ), Permission.replicate(myCollection, "my-shard", ReplicatePermission.Action.READ)); + requireAtLeast(1, 32, () -> { + permissions.add( + Permission.aliases("ThingsAlias", myCollection, AliasesPermission.Action.CREATE)); + }); requireAtLeast(1, 33, () -> { permissions.add( Permission.groups("my-group", GroupType.OIDC, GroupsPermission.Action.READ)); From 7730461cb2081e5270078ffef78eaaf7cba68ffc Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Thu, 6 Nov 2025 11:46:45 +0100 Subject: [PATCH 21/59] ci: raise minimal required version to 1.32 Replication API's changed between 1.31 and 1.32 and is completely incompatible --- .github/workflows/test.yaml | 2 +- src/it/java/io/weaviate/ConcurrentTest.java | 12 +++++------- .../java/io/weaviate/containers/Weaviate.java | 18 +++++++++++++++++- .../io/weaviate/integration/AliasITest.java | 3 ++- .../io/weaviate/integration/BackupITest.java | 4 ++-- .../io/weaviate/integration/RbacITest.java | 4 ++-- .../client6/v1/internal/VersionSupport.java | 2 +- 7 files changed, 30 insertions(+), 15 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 852f40c6a..d3facfdee 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -68,7 +68,7 @@ jobs: strategy: fail-fast: false matrix: - WEAVIATE_VERSION: ["1.30.0", "1.31.0", "1.32.0", "1.33.0"] + WEAVIATE_VERSION: ["1.32.0", "1.33.0"] steps: - uses: actions/checkout@v4 diff --git a/src/it/java/io/weaviate/ConcurrentTest.java b/src/it/java/io/weaviate/ConcurrentTest.java index 83c4be098..6e783ff06 100644 --- a/src/it/java/io/weaviate/ConcurrentTest.java +++ b/src/it/java/io/weaviate/ConcurrentTest.java @@ -119,18 +119,16 @@ public static void eventually(Callable cond, int intervalMillis, int ti * Skip the test if the version that the {@link Weaviate} * container is running is older than the required one. */ - public static void requireAtLeast(int major, int minor) { - var required = new SemanticVersion(major, minor); + public static void requireAtLeast(Weaviate.Version required) { var actual = SemanticVersion.of(Weaviate.VERSION); Assumptions.assumeThat(actual) - .as("requires at least %s, but running %s", required, actual) - .isGreaterThanOrEqualTo(required); + .as("requires at least %s, but running %s", required.semver, actual) + .isGreaterThanOrEqualTo(required.semver); } - public static void requireAtLeast(int major, int minor, Runnable r) { - var required = new SemanticVersion(major, minor); + public static void requireAtLeast(Weaviate.Version required, Runnable r) { var actual = SemanticVersion.of(Weaviate.VERSION); - if (actual.compareTo(required) >= 0) { + if (actual.compareTo(required.semver) >= 0) { r.run(); } } diff --git a/src/it/java/io/weaviate/containers/Weaviate.java b/src/it/java/io/weaviate/containers/Weaviate.java index f7b192ac6..79340241b 100644 --- a/src/it/java/io/weaviate/containers/Weaviate.java +++ b/src/it/java/io/weaviate/containers/Weaviate.java @@ -16,9 +16,11 @@ import org.testcontainers.lifecycle.Startable; import org.testcontainers.weaviate.WeaviateContainer; +import io.weaviate.ConcurrentTest; import io.weaviate.client6.v1.api.Config; import io.weaviate.client6.v1.api.WeaviateClient; import io.weaviate.client6.v1.internal.ObjectBuilder; +import io.weaviate.client6.v1.internal.VersionSupport.SemanticVersion; public class Weaviate extends WeaviateContainer { public static final String DOCKER_IMAGE = "semitechnologies/weaviate"; @@ -28,12 +30,26 @@ public class Weaviate extends WeaviateContainer { static { VERSION = System.getenv().getOrDefault("WEAVIATE_VERSION", LATEST_VERSION); } - public static String OIDC_ISSUER = "https://auth.wcs.api.weaviate.io/auth/realms/SeMI"; private volatile SharedClient clientInstance; private final String containerName; + public enum Version { + V132(1, 32), + V133(1, 33); + + public final SemanticVersion semver; + + private Version(int major, int minor) { + this.semver = new SemanticVersion(major, minor); + } + + public void orSkip() { + ConcurrentTest.requireAtLeast(this); + } + } + /** * By default, testcontainer's name is only available after calling * {@link #start}. diff --git a/src/it/java/io/weaviate/integration/AliasITest.java b/src/it/java/io/weaviate/integration/AliasITest.java index 3e1623321..8cd03e16d 100644 --- a/src/it/java/io/weaviate/integration/AliasITest.java +++ b/src/it/java/io/weaviate/integration/AliasITest.java @@ -11,13 +11,14 @@ import io.weaviate.client6.v1.api.WeaviateClient; import io.weaviate.client6.v1.api.alias.Alias; import io.weaviate.containers.Container; +import io.weaviate.containers.Weaviate; public class AliasITest extends ConcurrentTest { private static final WeaviateClient client = Container.WEAVIATE.getClient(); @BeforeClass public static void __() { - requireAtLeast(1, 32); + Weaviate.Version.V132.orSkip(); } @Test diff --git a/src/it/java/io/weaviate/integration/BackupITest.java b/src/it/java/io/weaviate/integration/BackupITest.java index 3e8c80a99..c540afaae 100644 --- a/src/it/java/io/weaviate/integration/BackupITest.java +++ b/src/it/java/io/weaviate/integration/BackupITest.java @@ -29,7 +29,7 @@ public class BackupITest extends ConcurrentTest { @Test public void test_lifecycle() throws IOException, TimeoutException { - requireAtLeast(1, 32); // List backups not implemented in earlier versions + Weaviate.Version.V132.orSkip(); // List backups not implemented in earlier versions // Arrange String nsA = ns("A"), nsB = ns("B"), nsC = ns("C"), nsBig = ns("Big"); @@ -124,7 +124,7 @@ public void test_lifecycle() throws IOException, TimeoutException { @Test public void test_lifecycle_async() throws ExecutionException, InterruptedException, Exception { - requireAtLeast(1, 32); // List backups not implemented in earlier versions + Weaviate.Version.V132.orSkip(); // List backups not implemented in earlier versions // Arrange String nsA = ns("A"), nsB = ns("B"), nsC = ns("C"), nsBig = ns("Big"); diff --git a/src/it/java/io/weaviate/integration/RbacITest.java b/src/it/java/io/weaviate/integration/RbacITest.java index c6de5e220..b50967aec 100644 --- a/src/it/java/io/weaviate/integration/RbacITest.java +++ b/src/it/java/io/weaviate/integration/RbacITest.java @@ -75,11 +75,11 @@ public void test_roles_Lifecycle() throws IOException { Permission.users("my-user", UsersPermission.Action.READ), Permission.replicate(myCollection, "my-shard", ReplicatePermission.Action.READ)); - requireAtLeast(1, 32, () -> { + requireAtLeast(Weaviate.Version.V132, () -> { permissions.add( Permission.aliases("ThingsAlias", myCollection, AliasesPermission.Action.CREATE)); }); - requireAtLeast(1, 33, () -> { + requireAtLeast(Weaviate.Version.V133, () -> { permissions.add( Permission.groups("my-group", GroupType.OIDC, GroupsPermission.Action.READ)); }); diff --git a/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java b/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java index 6ba324630..05763677c 100644 --- a/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java +++ b/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java @@ -3,7 +3,7 @@ import java.util.Arrays; public final class VersionSupport { - public static final SemanticVersion MINIMAL_SUPPORTED_VERSION = new SemanticVersion(1, 31); + public static final SemanticVersion MINIMAL_SUPPORTED_VERSION = new SemanticVersion(1, 32); /** * Returns true if the {@code version} is the same as or older than the From 8c3583a6c37c1a7458b8c73f99df1c9dcefc941f Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Thu, 6 Nov 2025 11:50:22 +0100 Subject: [PATCH 22/59] fix: use mutable list --- .../io/weaviate/integration/RbacITest.java | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/it/java/io/weaviate/integration/RbacITest.java b/src/it/java/io/weaviate/integration/RbacITest.java index b50967aec..5d90bd1c2 100644 --- a/src/it/java/io/weaviate/integration/RbacITest.java +++ b/src/it/java/io/weaviate/integration/RbacITest.java @@ -1,6 +1,7 @@ package io.weaviate.integration; import java.io.IOException; +import java.util.ArrayList; import java.util.List; import org.assertj.core.api.Assertions; @@ -64,16 +65,19 @@ public void test_roles_Lifecycle() throws IOException { var myCollection = "Things"; var nsRole = ns("VectorOwner"); - List permissions = List.of( - Permission.backups(myCollection, BackupsPermission.Action.MANAGE), - Permission.cluster(ClusterPermission.Action.READ), - Permission.nodes(myCollection, NodesPermission.Action.READ), - Permission.roles(VIEWER_ROLE, Scope.MATCH, RolesPermission.Action.CREATE), - Permission.collections(myCollection, CollectionsPermission.Action.CREATE), - Permission.data(myCollection, DataPermission.Action.UPDATE), - Permission.tenants(myCollection, "my-tenant", TenantsPermission.Action.DELETE), - Permission.users("my-user", UsersPermission.Action.READ), - Permission.replicate(myCollection, "my-shard", ReplicatePermission.Action.READ)); + List permissions = new ArrayList<>() { + { + add(Permission.backups(myCollection, BackupsPermission.Action.MANAGE)); + add(Permission.cluster(ClusterPermission.Action.READ)); + add(Permission.nodes(myCollection, NodesPermission.Action.READ)); + add(Permission.roles(VIEWER_ROLE, Scope.MATCH, RolesPermission.Action.CREATE)); + add(Permission.collections(myCollection, CollectionsPermission.Action.CREATE)); + add(Permission.data(myCollection, DataPermission.Action.UPDATE)); + add(Permission.tenants(myCollection, "my-tenant", TenantsPermission.Action.DELETE)); + add(Permission.users("my-user", UsersPermission.Action.READ)); + add(Permission.replicate(myCollection, "my-shard", ReplicatePermission.Action.READ)); + } + }; requireAtLeast(Weaviate.Version.V132, () -> { permissions.add( From b3847d51258a2fb92ea034ac9a42c916c814c1e2 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Thu, 6 Nov 2025 11:57:19 +0100 Subject: [PATCH 23/59] test: fix skip syntax --- src/it/java/io/weaviate/integration/RbacITest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/it/java/io/weaviate/integration/RbacITest.java b/src/it/java/io/weaviate/integration/RbacITest.java index 5d90bd1c2..c62b52b2a 100644 --- a/src/it/java/io/weaviate/integration/RbacITest.java +++ b/src/it/java/io/weaviate/integration/RbacITest.java @@ -160,7 +160,7 @@ public void test_roles_userAssignments() throws IOException { @Test public void test_groups() throws IOException { - requireAtLeast(1, 33); + Weaviate.Version.V133.orSkip(); var mediaGroup = "./media-group"; var friendGroup = "./friend-group"; From ecef35c6a51c7cd66d55e6869ab4bafd1f19b78c Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Thu, 6 Nov 2025 12:05:43 +0100 Subject: [PATCH 24/59] build: drop Lombok dependency --- pom.xml | 73 --------------------------------------------------------- 1 file changed, 73 deletions(-) diff --git a/pom.xml b/pom.xml index 35a5efcfa..66cb30510 100644 --- a/pom.xml +++ b/pom.xml @@ -52,7 +52,6 @@ 17 17 17 - 1.18.42 2.13.2 5.5.1 3.19.0 @@ -112,11 +111,6 @@ httpclient5 ${httpclient.version} - - org.projectlombok - lombok - ${lombok.version} - com.google.code.gson gson @@ -240,52 +234,6 @@ balanced - - org.projectlombok - lombok-maven-plugin - 1.18.20.0 - - - delombok-sources - generate-sources - - delombok - - - src/main/java - ${project.build.directory}/delombok - false - UTF-8 - - - - - - org.projectlombok - lombok - ${lombok.version} - - - - - org.apache.maven.plugins - maven-antrun-plugin - 3.0.0 - - - generate-delomboked-sources-jar - package - - run - - - - - - - - - org.codehaus.mojo versions-maven-plugin @@ -308,22 +256,6 @@ build-helper-maven-plugin 3.2.0 - - attach-delomboked-sources-jar - package - - attach-artifact - - - - - ${project.build.directory}/${project.build.finalName}-sources.jar - jar - sources - - - - add-test-source generate-test-sources @@ -375,7 +307,6 @@ - ${project.build.directory}/delombok all,-missing @@ -503,10 +434,6 @@ - - org.projectlombok - lombok-maven-plugin - org.xolstice.maven.plugins protobuf-maven-plugin From 728aad74c0a5de785933942043dfb9b82fa05d09 Mon Sep 17 00:00:00 2001 From: Ivan Despot <66276597+g-despot@users.noreply.github.com> Date: Fri, 21 Nov 2025 12:53:08 +0100 Subject: [PATCH 25/59] Update Weaviate versions --- .github/workflows/test.yaml | 2 +- src/it/java/io/weaviate/containers/Weaviate.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index d3facfdee..3587ab91a 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -68,7 +68,7 @@ jobs: strategy: fail-fast: false matrix: - WEAVIATE_VERSION: ["1.32.0", "1.33.0"] + WEAVIATE_VERSION: ["1.32.16", "1.33.4", "1.34.0"] steps: - uses: actions/checkout@v4 diff --git a/src/it/java/io/weaviate/containers/Weaviate.java b/src/it/java/io/weaviate/containers/Weaviate.java index bfd60dcfd..1e06f1b7a 100644 --- a/src/it/java/io/weaviate/containers/Weaviate.java +++ b/src/it/java/io/weaviate/containers/Weaviate.java @@ -24,7 +24,7 @@ public class Weaviate extends WeaviateContainer { public static final String DOCKER_IMAGE = "semitechnologies/weaviate"; - public static final String LATEST_VERSION = "1.33.0"; + public static final String LATEST_VERSION = "1.34.0"; public static final String VERSION; static { From 657cfab7e375212fa0d4a161a72d8997098e081a Mon Sep 17 00:00:00 2001 From: Ivan Despot <66276597+g-despot@users.noreply.github.com> Date: Fri, 21 Nov 2025 13:08:39 +0100 Subject: [PATCH 26/59] Free workflow disk space step --- .github/workflows/test.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 3587ab91a..6e063ed37 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -33,6 +33,16 @@ jobs: path: ${{ env.DOCKER_IMAGES_TAR }} key: ${{ env.DOCKER_CACHE_KEY }} lookup-only: true # Only check if cache exists, don't download + - name: Free Disk Space (Ubuntu) + uses: jlumbroso/free-disk-space@v1.3.1 + with: + tool-cache: false + android: true + dotnet: true + haskell: true + large-packages: true + docker-images: false + swap-storage: false - name: Pull images if: steps.cache-check.outputs.cache-hit != 'true' run: | From 1bde56b3a589123a1b6b743efba1b9085226df24 Mon Sep 17 00:00:00 2001 From: Ivan Despot <66276597+g-despot@users.noreply.github.com> Date: Fri, 21 Nov 2025 13:42:02 +0100 Subject: [PATCH 27/59] Free workflow disk space step --- .github/workflows/test.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 6e063ed37..dec60bc76 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -88,6 +88,16 @@ jobs: with: path: ${{ env.DOCKER_IMAGES_TAR }} key: ${{ env.DOCKER_CACHE_KEY }} + - name: Free Disk Space (Ubuntu) + uses: jlumbroso/free-disk-space@v1.3.1 + with: + tool-cache: false + android: true + dotnet: true + haskell: true + large-packages: true + docker-images: false + swap-storage: false - name: Load Docker images run: | if [ -f $DOCKER_IMAGES_TAR ]; then From e9b17438a764e68c12a6cd8f7f5f48aafc3afae0 Mon Sep 17 00:00:00 2001 From: Ivan Despot <66276597+g-despot@users.noreply.github.com> Date: Fri, 21 Nov 2025 13:57:35 +0100 Subject: [PATCH 28/59] Fix failing TCs --- src/it/java/io/weaviate/containers/Weaviate.java | 3 ++- src/it/java/io/weaviate/integration/ClusterITest.java | 5 +++++ src/main/java/io/weaviate/client6/v1/api/backup/Backup.java | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/it/java/io/weaviate/containers/Weaviate.java b/src/it/java/io/weaviate/containers/Weaviate.java index 1e06f1b7a..9ae2d2469 100644 --- a/src/it/java/io/weaviate/containers/Weaviate.java +++ b/src/it/java/io/weaviate/containers/Weaviate.java @@ -37,7 +37,8 @@ public class Weaviate extends WeaviateContainer { public enum Version { V132(1, 32), - V133(1, 33); + V133(1, 33), + V134(1, 34); public final SemanticVersion semver; diff --git a/src/it/java/io/weaviate/integration/ClusterITest.java b/src/it/java/io/weaviate/integration/ClusterITest.java index b7716717e..f43962662 100644 --- a/src/it/java/io/weaviate/integration/ClusterITest.java +++ b/src/it/java/io/weaviate/integration/ClusterITest.java @@ -14,12 +14,15 @@ import io.weaviate.client6.v1.api.cluster.replication.ReplicationState; import io.weaviate.client6.v1.api.cluster.replication.ReplicationType; import io.weaviate.containers.Weaviate; +import io.weaviate.containers.Weaviate.Version; public class ClusterITest extends ConcurrentTest { private static final WeaviateClient client = Weaviate.cluster(3).getClient(); @Test public void test_shardingState() throws IOException { + Version.V134.orSkip(); + // Arrange var nsA = ns("A"); var nsB = ns("B"); @@ -58,6 +61,8 @@ public void test_listNodes() throws IOException { @Test public void test_replicateLifecycle() throws IOException { + Version.V134.orSkip(); // Replicate endpoint not implemented in earlier versions + // Arrange // We must create the collection first before any shards exist on the nodes. diff --git a/src/main/java/io/weaviate/client6/v1/api/backup/Backup.java b/src/main/java/io/weaviate/client6/v1/api/backup/Backup.java index 066fe2e08..9d02a0673 100644 --- a/src/main/java/io/weaviate/client6/v1/api/backup/Backup.java +++ b/src/main/java/io/weaviate/client6/v1/api/backup/Backup.java @@ -34,7 +34,7 @@ public record Backup( /** Time at which the backup was completed, successfully or otherwise. */ @SerializedName("completedAt") OffsetDateTime completedAt, /** Backup size in GiB. */ - @SerializedName("size") Integer sizeGiB, + @SerializedName("size") Double sizeGiB, /** * This value indicates if a backup is being created or restored from. * For operations like LIST this value is null. From 9cd6c4029c11e2776ef3ccf57b97b891b8262e12 Mon Sep 17 00:00:00 2001 From: Ivan Despot <66276597+g-despot@users.noreply.github.com> Date: Fri, 21 Nov 2025 14:25:59 +0100 Subject: [PATCH 29/59] Update replication factor --- src/it/java/io/weaviate/integration/ClusterITest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/it/java/io/weaviate/integration/ClusterITest.java b/src/it/java/io/weaviate/integration/ClusterITest.java index f43962662..7e82481da 100644 --- a/src/it/java/io/weaviate/integration/ClusterITest.java +++ b/src/it/java/io/weaviate/integration/ClusterITest.java @@ -61,13 +61,13 @@ public void test_listNodes() throws IOException { @Test public void test_replicateLifecycle() throws IOException { - Version.V134.orSkip(); // Replicate endpoint not implemented in earlier versions + Version.V132.orSkip(); // Arrange // We must create the collection first before any shards exist on the nodes. var nsThings = ns("Things"); - client.collections.create(nsThings); + client.collections.create(nsThings, c -> c.replication(r -> r.replicationFactor(2))); var nodes = client.cluster.listNodes(opt -> opt.verbosity(NodeVerbosity.VERBOSE)); Assertions.assertThat(nodes) From 82f7c17acee7d14fba87b9aa935e94421f34a3bf Mon Sep 17 00:00:00 2001 From: Ivan Despot <66276597+g-despot@users.noreply.github.com> Date: Fri, 21 Nov 2025 14:45:14 +0100 Subject: [PATCH 30/59] Fix cluster creation --- src/it/java/io/weaviate/containers/Weaviate.java | 3 ++- src/it/java/io/weaviate/integration/ClusterITest.java | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/it/java/io/weaviate/containers/Weaviate.java b/src/it/java/io/weaviate/containers/Weaviate.java index 9ae2d2469..b573837cc 100644 --- a/src/it/java/io/weaviate/containers/Weaviate.java +++ b/src/it/java/io/weaviate/containers/Weaviate.java @@ -412,12 +412,13 @@ public void stop() { */ private void bindNodes(int gossip, int data, int raft) { var publicPort = leader.getExposedPorts().get(0); // see WeaviateContainer Testcontainer. + var clusterSize = String.valueOf(nodes.size()); nodes.forEach(node -> node .withEnv("CLUSTER_GOSSIP_BIND_PORT", String.valueOf(gossip)) .withEnv("CLUSTER_DATA_BIND_PORT", String.valueOf(data)) .withEnv("RAFT_PORT", String.valueOf(raft)) - .withEnv("RAFT_BOOTSTRAP_EXPECT", "1")); + .withEnv("RAFT_BOOTSTRAP_EXPECT", clusterSize)); followers.forEach(node -> node .withEnv("CLUSTER_JOIN", leader.containerName + ":" + gossip) diff --git a/src/it/java/io/weaviate/integration/ClusterITest.java b/src/it/java/io/weaviate/integration/ClusterITest.java index 7e82481da..6a326d5a6 100644 --- a/src/it/java/io/weaviate/integration/ClusterITest.java +++ b/src/it/java/io/weaviate/integration/ClusterITest.java @@ -21,8 +21,6 @@ public class ClusterITest extends ConcurrentTest { @Test public void test_shardingState() throws IOException { - Version.V134.orSkip(); - // Arrange var nsA = ns("A"); var nsB = ns("B"); From f4da5f67ad7da584280a0b8a7b50c27a5ffc1374 Mon Sep 17 00:00:00 2001 From: Ivan Despot <66276597+g-despot@users.noreply.github.com> Date: Fri, 21 Nov 2025 15:09:28 +0100 Subject: [PATCH 31/59] Update bindNodes --- src/it/java/io/weaviate/containers/Weaviate.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/it/java/io/weaviate/containers/Weaviate.java b/src/it/java/io/weaviate/containers/Weaviate.java index b573837cc..6f21d6038 100644 --- a/src/it/java/io/weaviate/containers/Weaviate.java +++ b/src/it/java/io/weaviate/containers/Weaviate.java @@ -411,15 +411,18 @@ public void stop() { * @param raft RAFT port. */ private void bindNodes(int gossip, int data, int raft) { - var publicPort = leader.getExposedPorts().get(0); // see WeaviateContainer Testcontainer. + var publicPort = leader.getExposedPorts().get(0); var clusterSize = String.valueOf(nodes.size()); nodes.forEach(node -> node .withEnv("CLUSTER_GOSSIP_BIND_PORT", String.valueOf(gossip)) .withEnv("CLUSTER_DATA_BIND_PORT", String.valueOf(data)) - .withEnv("RAFT_PORT", String.valueOf(raft)) - .withEnv("RAFT_BOOTSTRAP_EXPECT", clusterSize)); + .withEnv("RAFT_PORT", String.valueOf(raft))); + // Leader bootstraps the cluster + leader.withEnv("RAFT_BOOTSTRAP_EXPECT", clusterSize); + + // Followers join the existing cluster followers.forEach(node -> node .withEnv("CLUSTER_JOIN", leader.containerName + ":" + gossip) .withEnv("RAFT_JOIN", leader.containerName) @@ -427,7 +430,7 @@ private void bindNodes(int gossip, int data, int raft) { Wait.forHttp("/v1/.well-known/ready") .forPort(publicPort) .forStatusCode(200) - .withStartupTimeout(Duration.ofSeconds(10)))); + .withStartupTimeout(Duration.ofSeconds(60)))); } } } From cae7c72586b04b271638ab318dd3afafba6b2cbd Mon Sep 17 00:00:00 2001 From: Ivan Despot <66276597+g-despot@users.noreply.github.com> Date: Fri, 21 Nov 2025 15:34:31 +0100 Subject: [PATCH 32/59] Revert changes --- src/it/java/io/weaviate/containers/Weaviate.java | 10 +++------- src/it/java/io/weaviate/integration/ClusterITest.java | 2 +- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/it/java/io/weaviate/containers/Weaviate.java b/src/it/java/io/weaviate/containers/Weaviate.java index 6f21d6038..8f5f205b5 100644 --- a/src/it/java/io/weaviate/containers/Weaviate.java +++ b/src/it/java/io/weaviate/containers/Weaviate.java @@ -411,18 +411,14 @@ public void stop() { * @param raft RAFT port. */ private void bindNodes(int gossip, int data, int raft) { - var publicPort = leader.getExposedPorts().get(0); - var clusterSize = String.valueOf(nodes.size()); + var publicPort = leader.getExposedPorts().get(0); // see WeaviateContainer Testcontainer. nodes.forEach(node -> node .withEnv("CLUSTER_GOSSIP_BIND_PORT", String.valueOf(gossip)) .withEnv("CLUSTER_DATA_BIND_PORT", String.valueOf(data)) - .withEnv("RAFT_PORT", String.valueOf(raft))); + .withEnv("RAFT_PORT", String.valueOf(raft)) + .withEnv("RAFT_BOOTSTRAP_EXPECT", "1")); - // Leader bootstraps the cluster - leader.withEnv("RAFT_BOOTSTRAP_EXPECT", clusterSize); - - // Followers join the existing cluster followers.forEach(node -> node .withEnv("CLUSTER_JOIN", leader.containerName + ":" + gossip) .withEnv("RAFT_JOIN", leader.containerName) diff --git a/src/it/java/io/weaviate/integration/ClusterITest.java b/src/it/java/io/weaviate/integration/ClusterITest.java index 6a326d5a6..baea17f70 100644 --- a/src/it/java/io/weaviate/integration/ClusterITest.java +++ b/src/it/java/io/weaviate/integration/ClusterITest.java @@ -65,7 +65,7 @@ public void test_replicateLifecycle() throws IOException { // We must create the collection first before any shards exist on the nodes. var nsThings = ns("Things"); - client.collections.create(nsThings, c -> c.replication(r -> r.replicationFactor(2))); + client.collections.create(nsThings); var nodes = client.cluster.listNodes(opt -> opt.verbosity(NodeVerbosity.VERBOSE)); Assertions.assertThat(nodes) From 869e8bb9821573c4a9f40a8f352455706df5c73e Mon Sep 17 00:00:00 2001 From: Ivan Despot <66276597+g-despot@users.noreply.github.com> Date: Fri, 21 Nov 2025 15:44:40 +0100 Subject: [PATCH 33/59] Add missing env var --- src/it/java/io/weaviate/containers/Weaviate.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/it/java/io/weaviate/containers/Weaviate.java b/src/it/java/io/weaviate/containers/Weaviate.java index 8f5f205b5..8f174dea1 100644 --- a/src/it/java/io/weaviate/containers/Weaviate.java +++ b/src/it/java/io/weaviate/containers/Weaviate.java @@ -416,6 +416,7 @@ private void bindNodes(int gossip, int data, int raft) { nodes.forEach(node -> node .withEnv("CLUSTER_GOSSIP_BIND_PORT", String.valueOf(gossip)) .withEnv("CLUSTER_DATA_BIND_PORT", String.valueOf(data)) + .withEnv("REPLICA_MOVEMENT_ENABLED", "true") .withEnv("RAFT_PORT", String.valueOf(raft)) .withEnv("RAFT_BOOTSTRAP_EXPECT", "1")); @@ -426,7 +427,7 @@ private void bindNodes(int gossip, int data, int raft) { Wait.forHttp("/v1/.well-known/ready") .forPort(publicPort) .forStatusCode(200) - .withStartupTimeout(Duration.ofSeconds(60)))); + .withStartupTimeout(Duration.ofSeconds(10)))); } } } From bcf6f48096ee12a57b986ed1c8cbafa35ced7306 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Wed, 29 Oct 2025 19:14:54 +0100 Subject: [PATCH 34/59] chore: enforce minimal server version --- .../client6/v1/api/WeaviateClient.java | 5 ++ .../client6/v1/api/WeaviateClientAsync.java | 5 ++ .../WeaviateUnsupportedVersionException.java | 19 ++++++++ .../client6/v1/internal/VersionSupport.java | 46 +++++++++++++++++++ 4 files changed, 75 insertions(+) create mode 100644 src/main/java/io/weaviate/client6/v1/api/WeaviateUnsupportedVersionException.java create mode 100644 src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java diff --git a/src/main/java/io/weaviate/client6/v1/api/WeaviateClient.java b/src/main/java/io/weaviate/client6/v1/api/WeaviateClient.java index a4c51cbe9..63e14c3bf 100644 --- a/src/main/java/io/weaviate/client6/v1/api/WeaviateClient.java +++ b/src/main/java/io/weaviate/client6/v1/api/WeaviateClient.java @@ -13,6 +13,7 @@ import io.weaviate.client6.v1.internal.ObjectBuilder; import io.weaviate.client6.v1.internal.Timeout; import io.weaviate.client6.v1.internal.TokenProvider; +import io.weaviate.client6.v1.internal.VersionSupport; import io.weaviate.client6.v1.internal.grpc.DefaultGrpcTransport; import io.weaviate.client6.v1.internal.grpc.GrpcChannelOptions; import io.weaviate.client6.v1.internal.grpc.GrpcTransport; @@ -105,6 +106,10 @@ public WeaviateClient(Config config) { throw ex; } + if (!VersionSupport.isSupported(meta.version())) { + throw new WeaviateUnsupportedVersionException(meta.version()); + } + if (meta.grpcMaxMessageSize() != null) { grpcOpt = grpcOpt.withMaxMessageSize(meta.grpcMaxMessageSize()); } diff --git a/src/main/java/io/weaviate/client6/v1/api/WeaviateClientAsync.java b/src/main/java/io/weaviate/client6/v1/api/WeaviateClientAsync.java index 7858300ec..1e5b07ae3 100644 --- a/src/main/java/io/weaviate/client6/v1/api/WeaviateClientAsync.java +++ b/src/main/java/io/weaviate/client6/v1/api/WeaviateClientAsync.java @@ -15,6 +15,7 @@ import io.weaviate.client6.v1.internal.ObjectBuilder; import io.weaviate.client6.v1.internal.Timeout; import io.weaviate.client6.v1.internal.TokenProvider; +import io.weaviate.client6.v1.internal.VersionSupport; import io.weaviate.client6.v1.internal.grpc.DefaultGrpcTransport; import io.weaviate.client6.v1.internal.grpc.GrpcChannelOptions; import io.weaviate.client6.v1.internal.grpc.GrpcTransport; @@ -108,6 +109,10 @@ public WeaviateClientAsync(Config config) { throw ex; } + if (!VersionSupport.isSupported(meta.version())) { + throw new WeaviateUnsupportedVersionException(meta.version()); + } + if (meta.grpcMaxMessageSize() != null) { grpcOpt = grpcOpt.withMaxMessageSize(meta.grpcMaxMessageSize()); } diff --git a/src/main/java/io/weaviate/client6/v1/api/WeaviateUnsupportedVersionException.java b/src/main/java/io/weaviate/client6/v1/api/WeaviateUnsupportedVersionException.java new file mode 100644 index 000000000..215fc95b2 --- /dev/null +++ b/src/main/java/io/weaviate/client6/v1/api/WeaviateUnsupportedVersionException.java @@ -0,0 +1,19 @@ +package io.weaviate.client6.v1.api; + +import io.weaviate.client6.v1.internal.VersionSupport; + +/** + * This exception is thrown when the client refuses to talk to an unsupported + * version of the server. + * + * @see VersionSupport#MINIMAL_SUPPORTED_VERSION. + */ +public class WeaviateUnsupportedVersionException extends WeaviateException { + public WeaviateUnsupportedVersionException(String actual) { + this(VersionSupport.MINIMAL_SUPPORTED_VERSION.toString(), actual); + } + + public WeaviateUnsupportedVersionException(String minimal, String actual) { + super("Server version %s is not supported. Earliest supported version is %s.".formatted(actual, minimal)); + } +} diff --git a/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java b/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java new file mode 100644 index 000000000..8cf30c83a --- /dev/null +++ b/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java @@ -0,0 +1,46 @@ +package io.weaviate.client6.v1.internal; + +import java.util.Arrays; + +public final class VersionSupport { + public static final SemanticVersion MINIMAL_SUPPORTED_VERSION = new SemanticVersion(1, 33); + + /** + * Returns true if the {@code version} is the same as or older than the + * {@link VersionSupport#MINIMAL_SUPPORTED_VERSION}. + */ + public static boolean isSupported(String version) { + var semver = SemanticVersion.of(version); + return semver.compareTo(MINIMAL_SUPPORTED_VERSION) >= 0; + } + + public record SemanticVersion(int major, int minor, String patch) implements Comparable { + + public SemanticVersion(int major, int minor) { + this(major, minor, null); + } + + /** + * Parse semantic version from a formatted string, e.g. + * {@code "(v)1.23.6-rc.1"}. + */ + public static SemanticVersion of(String version) { + var parts = version.replaceFirst("v", "").split("\\."); + var major = Integer.valueOf(parts[0].replaceAll("[^0-9]", "")); + var minor = Integer.valueOf(parts[1].replaceAll("[^0-9]", "")); + var patch = String.join(".", Arrays.stream(parts, 2, parts.length).toList()); + return new SemanticVersion(major, minor, patch); + } + + @Override + public int compareTo(SemanticVersion that) { + var this_v = Integer.valueOf("%d%d".formatted(this.major, this.minor)); + var that_v = Integer.valueOf("%d%d".formatted(that.major, that.minor)); + return this_v.compareTo(that_v); + } + + public String toString() { + return String.join(".", String.valueOf(major), String.valueOf(minor), patch); + } + } +} From 703411a937107d57b36ee7d0a63423b62854c19b Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Wed, 29 Oct 2025 19:31:04 +0100 Subject: [PATCH 35/59] test: add unit tests for SemanticVersion --- .../client6/v1/internal/VersionSupport.java | 6 ++- .../v1/internal/VersionSupportTest.java | 40 +++++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 src/test/java/io/weaviate/client6/v1/internal/VersionSupportTest.java diff --git a/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java b/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java index 8cf30c83a..18fc127e9 100644 --- a/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java +++ b/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java @@ -28,7 +28,9 @@ public static SemanticVersion of(String version) { var parts = version.replaceFirst("v", "").split("\\."); var major = Integer.valueOf(parts[0].replaceAll("[^0-9]", "")); var minor = Integer.valueOf(parts[1].replaceAll("[^0-9]", "")); - var patch = String.join(".", Arrays.stream(parts, 2, parts.length).toList()); + var patch = parts.length > 2 + ? String.join(".", Arrays.stream(parts, 2, parts.length).toList()) + : null; return new SemanticVersion(major, minor, patch); } @@ -40,7 +42,7 @@ public int compareTo(SemanticVersion that) { } public String toString() { - return String.join(".", String.valueOf(major), String.valueOf(minor), patch); + return String.join(".", String.valueOf(major), String.valueOf(minor), patch != null ? patch : ""); } } } diff --git a/src/test/java/io/weaviate/client6/v1/internal/VersionSupportTest.java b/src/test/java/io/weaviate/client6/v1/internal/VersionSupportTest.java new file mode 100644 index 000000000..e735f6738 --- /dev/null +++ b/src/test/java/io/weaviate/client6/v1/internal/VersionSupportTest.java @@ -0,0 +1,40 @@ +package io.weaviate.client6.v1.internal; + +import org.assertj.core.api.Assertions; +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.jparams.junit4.JParamsTestRunner; +import com.jparams.junit4.data.DataMethod; + +import io.weaviate.client6.v1.internal.VersionSupport.SemanticVersion; + +@RunWith(JParamsTestRunner.class) +public class VersionSupportTest { + public static Object[][] testCases() { + return new Object[][] { + { "1.31.6", "v1.32.1", true }, // can have a leading v + { "v1.33.0", "1.32.1", false }, // can have a leading v + { "2.36.2", "2.36.0-rc.3", true }, // patch ignored + { "1.12", "1.11", false }, // omit patch + { "0.55.6", "0.1.0", false }, // can start with zero + }; + } + + @Test + @DataMethod(source = VersionSupportTest.class, method = "testCases") + public void test_isSupported(String minimal, String actual, boolean isSupported) { + var v_minimal = SemanticVersion.of(minimal); + var v_actual = SemanticVersion.of(actual); + + if (isSupported) { + Assertions.assertThat(v_actual) + .describedAs("%s supported (minimal=%s)", actual, minimal) + .isGreaterThanOrEqualTo(v_minimal); + } else { + Assertions.assertThat(v_actual) + .describedAs("%s not supported (minimal=%s)", actual, minimal) + .isLessThan(v_minimal); + } + } +} From 7648bf7b1d967d7af9185c3a38a657d36ccb1c19 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Wed, 29 Oct 2025 19:35:28 +0100 Subject: [PATCH 36/59] chore: fix javadoc --- .../client6/v1/api/WeaviateUnsupportedVersionException.java | 4 +--- .../java/io/weaviate/client6/v1/internal/VersionSupport.java | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/io/weaviate/client6/v1/api/WeaviateUnsupportedVersionException.java b/src/main/java/io/weaviate/client6/v1/api/WeaviateUnsupportedVersionException.java index 215fc95b2..1e4e27580 100644 --- a/src/main/java/io/weaviate/client6/v1/api/WeaviateUnsupportedVersionException.java +++ b/src/main/java/io/weaviate/client6/v1/api/WeaviateUnsupportedVersionException.java @@ -4,9 +4,7 @@ /** * This exception is thrown when the client refuses to talk to an unsupported - * version of the server. - * - * @see VersionSupport#MINIMAL_SUPPORTED_VERSION. + * version of the server, see {@link VersionSupport#MINIMAL_SUPPORTED_VERSION}. */ public class WeaviateUnsupportedVersionException extends WeaviateException { public WeaviateUnsupportedVersionException(String actual) { diff --git a/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java b/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java index 18fc127e9..e3a10f4d3 100644 --- a/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java +++ b/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java @@ -21,8 +21,8 @@ public SemanticVersion(int major, int minor) { } /** - * Parse semantic version from a formatted string, e.g. - * {@code "(v)1.23.6-rc.1"}. + * Parse semantic version from a formatted string, + * e.g. {@code "(v)1.23.6-rc.1"}. */ public static SemanticVersion of(String version) { var parts = version.replaceFirst("v", "").split("\\."); From a31b7d2f56c1e9889d4ac021a7afbb5515d74cf3 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Wed, 29 Oct 2025 19:44:04 +0100 Subject: [PATCH 37/59] chore: set minimal server version to 1.31 --- .../java/io/weaviate/client6/v1/internal/VersionSupport.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java b/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java index e3a10f4d3..6ba324630 100644 --- a/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java +++ b/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java @@ -3,7 +3,7 @@ import java.util.Arrays; public final class VersionSupport { - public static final SemanticVersion MINIMAL_SUPPORTED_VERSION = new SemanticVersion(1, 33); + public static final SemanticVersion MINIMAL_SUPPORTED_VERSION = new SemanticVersion(1, 31); /** * Returns true if the {@code version} is the same as or older than the From 7659b11a72f8cb8adbaacdd9b903dbf05e7fceb8 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Tue, 4 Nov 2025 12:35:55 +0100 Subject: [PATCH 38/59] test: upgrate Surefire to 3.5.4 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 68630eefb..aca726ad1 100644 --- a/pom.xml +++ b/pom.xml @@ -229,7 +229,7 @@ maven-surefire-plugin - 2.22.2 + 3.5.4 false From 9a585a130fb930d594e73747b3dd80dc214ced53 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Tue, 4 Nov 2025 13:40:13 +0100 Subject: [PATCH 39/59] ci: run tests in parallel Reduces test execution time from 1:20min to ~45s --- .gitignore | 2 + pom.xml | 12 ++--- .../io/weaviate/containers/Container.java | 12 ----- .../io/weaviate/containers/TestListener.java | 14 ----- .../java/io/weaviate/containers/Weaviate.java | 16 ++++++ .../integration/CollectionsITest.java | 54 ++++++++++--------- .../data/ReferenceAddManyResponse.java | 16 ++++-- 7 files changed, 64 insertions(+), 62 deletions(-) delete mode 100644 src/it/java/io/weaviate/containers/TestListener.java diff --git a/.gitignore b/.gitignore index 052460830..ee565b6c5 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,5 @@ target/ # maven-lombok-plugin .factorypath +# Surefire statistics for optimized execution time +.surefire-* diff --git a/pom.xml b/pom.xml index aca726ad1..2de9a2fa4 100644 --- a/pom.xml +++ b/pom.xml @@ -232,6 +232,12 @@ 3.5.4 false + classes + 4 + true + 1 + true + balanced --add-opens=java.base/java.lang=ALL-UNNAMED - - - listener - io.weaviate.containers.TestListener - - diff --git a/src/it/java/io/weaviate/containers/Container.java b/src/it/java/io/weaviate/containers/Container.java index 7c71ed980..304dbea91 100644 --- a/src/it/java/io/weaviate/containers/Container.java +++ b/src/it/java/io/weaviate/containers/Container.java @@ -18,18 +18,6 @@ public class Container { public static final Img2VecNeural IMG2VEC_NEURAL = Img2VecNeural.createDefault(); public static final MinIo MINIO = MinIo.createDefault(); - /** - * Stop all shared Testcontainers created in {@link #startAll}. - *

- * Testcontainer's Ryuk will reap any dangling containers after the tests - * finish. However, since {@link Weaviate} instances also hold a - * {@link WeaviateClient}, we want to stop them proactively to - * close client connections. - */ - static void stopAll() { - WEAVIATE.stop(); - } - public static ContainerGroup compose(Weaviate weaviate, GenericContainer... containers) { return new ContainerGroup(weaviate, containers); } diff --git a/src/it/java/io/weaviate/containers/TestListener.java b/src/it/java/io/weaviate/containers/TestListener.java deleted file mode 100644 index 72889125b..000000000 --- a/src/it/java/io/weaviate/containers/TestListener.java +++ /dev/null @@ -1,14 +0,0 @@ -package io.weaviate.containers; - -import org.junit.runner.Result; -import org.junit.runner.notification.RunListener; - -public class TestListener extends RunListener { - - @Override - public void testRunFinished(Result result) throws Exception { - Container.stopAll(); - super.testRunFinished(result); - } - -} diff --git a/src/it/java/io/weaviate/containers/Weaviate.java b/src/it/java/io/weaviate/containers/Weaviate.java index 1c7fc259e..48b3455ec 100644 --- a/src/it/java/io/weaviate/containers/Weaviate.java +++ b/src/it/java/io/weaviate/containers/Weaviate.java @@ -71,6 +71,22 @@ public WeaviateClient getClient() { return clientInstance; } + /** + * Get client that is not shared with other tests / callers. + * The returned client is not wrapped in an instance of {@link SharedClient}, + * so it can be auto-closed by the try-with-resources statement when it exists. + */ + public WeaviateClient getBareClient() { + if (!isRunning()) { + start(); + } + try { + return new WeaviateClient(Config.of(defaultConfigFn())); + } catch (Exception e) { + throw new RuntimeException("create WeaviateClient for Weaviate container", e); + } + } + /** * Create a new instance of WeaviateClient connected to this container. * Prefer using {@link #getClient} unless your test needs the initialization diff --git a/src/it/java/io/weaviate/integration/CollectionsITest.java b/src/it/java/io/weaviate/integration/CollectionsITest.java index 4906d48d5..c28890430 100644 --- a/src/it/java/io/weaviate/integration/CollectionsITest.java +++ b/src/it/java/io/weaviate/integration/CollectionsITest.java @@ -22,6 +22,7 @@ import io.weaviate.client6.v1.api.collections.vectorindex.Hnsw; import io.weaviate.client6.v1.api.collections.vectorizers.SelfProvidedVectorizer; import io.weaviate.containers.Container; +import io.weaviate.containers.Weaviate; public class CollectionsITest extends ConcurrentTest { private static WeaviateClient client = Container.WEAVIATE.getClient(); @@ -96,31 +97,34 @@ public void testCrossReferences() throws IOException { } @Test - public void testListDeleteAll() throws IOException { - var nsA = ns("A"); - var nsB = ns("B"); - var nsC = ns("C"); - - client.collections.create(nsA); - client.collections.create(nsB); - client.collections.create(nsC); - - Assertions.assertThat(client.collections.exists(nsA)).isTrue(); - Assertions.assertThat(client.collections.exists(nsB)).isTrue(); - Assertions.assertThat(client.collections.exists(nsC)).isTrue(); - Assertions.assertThat(client.collections.exists(ns("X"))).isFalse(); - - var all = client.collections.list(); - Assertions.assertThat(all) - .hasSizeGreaterThanOrEqualTo(3) - .extracting(CollectionConfig::collectionName) - .contains(nsA, nsB, nsC); - - client.collections.deleteAll(); - - all = client.collections.list(); - Assertions.assertThat(all.isEmpty()); - + public void testListDeleteAll() throws Exception { + // Use a separate container for this test so as not to interfere + // with other tests. + try (final var _client = Weaviate.createDefault().getBareClient()) { + var nsA = ns("A"); + var nsB = ns("B"); + var nsC = ns("C"); + + _client.collections.create(nsA); + _client.collections.create(nsB); + _client.collections.create(nsC); + + Assertions.assertThat(_client.collections.exists(nsA)).isTrue(); + Assertions.assertThat(_client.collections.exists(nsB)).isTrue(); + Assertions.assertThat(_client.collections.exists(nsC)).isTrue(); + Assertions.assertThat(_client.collections.exists(ns("X"))).isFalse(); + + var all = _client.collections.list(); + Assertions.assertThat(all) + .hasSizeGreaterThanOrEqualTo(3) + .extracting(CollectionConfig::collectionName) + .contains(nsA, nsB, nsC); + + _client.collections.deleteAll(); + + all = _client.collections.list(); + Assertions.assertThat(all.isEmpty()); + } } @Test diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/data/ReferenceAddManyResponse.java b/src/main/java/io/weaviate/client6/v1/api/collections/data/ReferenceAddManyResponse.java index d0fc89ace..d7c70d7fa 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/data/ReferenceAddManyResponse.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/data/ReferenceAddManyResponse.java @@ -24,11 +24,17 @@ public ReferenceAddManyResponse deserialize(JsonElement json, Type typeOfT, Json int i = 0; for (var el : json.getAsJsonArray()) { var result = el.getAsJsonObject().get("result").getAsJsonObject(); - if (result.get("status").getAsString().equals("FAILED")) { - var errorMsg = result - .get("errors").getAsJsonObject() - .get("error").getAsJsonArray() - .get(0).getAsString(); + if (result.get("status").getAsString().equals("FAILED") + && result.has("errors")) { + String errorMsg; + try { + errorMsg = result + .get("errors").getAsJsonObject() + .get("error").getAsJsonArray() + .get(0).getAsString(); + } catch (Exception e) { + errorMsg = result.get("errors").toString(); + } var batchErr = new BatchError(errorMsg, null, i); errors.add(batchErr); From daccf8429d45798108018954d45ec4bf998251a6 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Tue, 4 Nov 2025 13:45:04 +0100 Subject: [PATCH 40/59] test: remove ALL-UNNAMED opens from test config --- pom.xml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/pom.xml b/pom.xml index 2de9a2fa4..465e0195c 100644 --- a/pom.xml +++ b/pom.xml @@ -238,15 +238,6 @@ 1 true balanced - - - --add-opens=java.base/java.lang=ALL-UNNAMED - From 44ef2d755a0684b07b38985c3c6e265b92026205 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Wed, 5 Nov 2025 22:55:53 +0100 Subject: [PATCH 41/59] ci: extend test matrix to 2 latest Weaviate versions --- .github/workflows/test.yaml | 82 +++++++++++++++---- .../java/io/weaviate/containers/Weaviate.java | 8 +- 2 files changed, 75 insertions(+), 15 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 303bba5d8..7948b94b2 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -4,33 +4,87 @@ on: branches: - main pull_request: +concurrency: + group: tests-${{ github.ref }} + cancel-in-progress: true + +env: + IMG2VEC: cr.weaviate.io/semitechnologies/img2vec-pytorch:resnet50 + MINIO: minio/minio:latest + MODEL2VEC: cr.weaviate.io/semitechnologies/model2vec-inference:minishlab-potion-retrieval-32M + SUPPORTED_VERSIONS: '["1.32.0", "1.33.0"]' + DOCKER_CACHE_KEY: docker-images-${{ env.IMG2VEC }}-${{ env.MINIO }}-${{ env.MODEL2VEC }} + DOCKER_IMAGES_TAR: docker-images.tar jobs: - tests: - name: Tests + docker-cache: + name: Cache shared Docker images runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - with: - ref: ${{ github.sha }} - name: Login to Docker Hub if: ${{ !github.event.pull_request.head.repo.fork }} - uses: docker/login-action@v2 + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + - name: Restore and update Docker cache + id: docker-cache-restore + uses: actions/cache@v4 + with: + path: ${{ env.DOCKER_IMAGES_TAR }} + key: ${{ env.DOCKER_CACHE_KEY }} + - name: Pull images + if: steps.docker-cache-restore.outputs.cache-hit != 'true' + run: | + docker pull $IMG2VEC + docker pull $MINIO + docker pull $MODEL2VEC + docker save $IMG2VEC $MINIO $MODEL2VEC -o $DOCKER_IMAGES_TAR + + maven-cache: + name: Cache Maven dependencies + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-java@v4 + with: + distribution: 'zulu' + java-version: '17' + cache: 'maven' + - run: mvn dependency:go-offline + + test: + name: Test + runs-on: ubuntu-latest + needs: [ docker-cache, maven-cache] + strategy: + matrix: + WEAVIATE_VERSION: ${{ fromJson(env.SUPPORTED_VERSIONS) }} + steps: + - uses: actions/checkout@v4 + + - uses: actions/cache@v4 with: - username: ${{secrets.DOCKER_USERNAME}} - password: ${{secrets.DOCKER_PASSWORD}} - - name: Setup JDK - uses: actions/setup-java@v4 + path: ${{ env.DOCKER_IMAGES_TAR }} + key: ${{ env.DOCKER_CACHE_KEY }} + - name: Load Docker images + run: | + if [ -f $DOCKER_IMAGES_TAR ]; then + docker load -i $DOCKER_IMAGES_TAR + fi + - uses: actions/setup-java@v4 + name: Setup JDK with: distribution: 'zulu' java-version: '17' - - name: Run Build - run: mvn -DskipTests clean package - - name: Run Tests + cache: 'maven' + + - name: Run Tests (v${{ matrix.WEAVIATE_VERSION }}) env: OKTA_DUMMY_CI_PW: ${{ secrets.OKTA_DUMMY_CI_PW }} WCS_DUMMY_CI_PW: ${{ secrets.WCS_DUMMY_CI_PW }} OKTA_CLIENT_SECRET: ${{ secrets.OKTA_CLIENT_SECRET }} AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} OPENAI_APIKEY: ${{ secrets.OPENAI_APIKEY }} - run: mvn clean test + WEAVIATE_VERSION: ${{ matrix.WEAVIATE_VERSION }} + run: mvn verify diff --git a/src/it/java/io/weaviate/containers/Weaviate.java b/src/it/java/io/weaviate/containers/Weaviate.java index 48b3455ec..b0b9105b8 100644 --- a/src/it/java/io/weaviate/containers/Weaviate.java +++ b/src/it/java/io/weaviate/containers/Weaviate.java @@ -21,8 +21,14 @@ import io.weaviate.client6.v1.internal.ObjectBuilder; public class Weaviate extends WeaviateContainer { - public static final String VERSION = "1.33.0"; public static final String DOCKER_IMAGE = "semitechnologies/weaviate"; + public static final String LATEST_VERSION = "1.33.0"; + public static final String VERSION; + + static { + VERSION = System.getenv().getOrDefault("WEAVIATE_VERSION", LATEST_VERSION); + } + public static String OIDC_ISSUER = "https://auth.wcs.api.weaviate.io/auth/realms/SeMI"; private volatile SharedClient clientInstance; From 0169f620eec2fb5a966acda597ee3e33d17969d7 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Wed, 5 Nov 2025 23:07:16 +0100 Subject: [PATCH 42/59] ci: fix syntax --- .github/workflows/test.yaml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 7948b94b2..2ba3ccac5 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -12,8 +12,6 @@ env: IMG2VEC: cr.weaviate.io/semitechnologies/img2vec-pytorch:resnet50 MINIO: minio/minio:latest MODEL2VEC: cr.weaviate.io/semitechnologies/model2vec-inference:minishlab-potion-retrieval-32M - SUPPORTED_VERSIONS: '["1.32.0", "1.33.0"]' - DOCKER_CACHE_KEY: docker-images-${{ env.IMG2VEC }}-${{ env.MINIO }}-${{ env.MODEL2VEC }} DOCKER_IMAGES_TAR: docker-images.tar jobs: @@ -30,6 +28,8 @@ jobs: - name: Restore and update Docker cache id: docker-cache-restore uses: actions/cache@v4 + env: + DOCKER_CACHE_KEY: docker-images-${{ env.IMG2VEC }}-${{ env.MINIO }}-${{ env.MODEL2VEC }} with: path: ${{ env.DOCKER_IMAGES_TAR }} key: ${{ env.DOCKER_CACHE_KEY }} @@ -59,11 +59,13 @@ jobs: needs: [ docker-cache, maven-cache] strategy: matrix: - WEAVIATE_VERSION: ${{ fromJson(env.SUPPORTED_VERSIONS) }} + WEAVIATE_VERSION: ["1.32", "1.33"] steps: - uses: actions/checkout@v4 - uses: actions/cache@v4 + env: + DOCKER_CACHE_KEY: docker-images-${{ env.IMG2VEC }}-${{ env.MINIO }}-${{ env.MODEL2VEC }} with: path: ${{ env.DOCKER_IMAGES_TAR }} key: ${{ env.DOCKER_CACHE_KEY }} From d2a08ba074c07c78961fd7771f30b6cc582bff04 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Wed, 5 Nov 2025 23:19:08 +0100 Subject: [PATCH 43/59] chore: use smaller image --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 2ba3ccac5..41b97385c 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -11,7 +11,7 @@ concurrency: env: IMG2VEC: cr.weaviate.io/semitechnologies/img2vec-pytorch:resnet50 MINIO: minio/minio:latest - MODEL2VEC: cr.weaviate.io/semitechnologies/model2vec-inference:minishlab-potion-retrieval-32M + MODEL2VEC: cr.weaviate.io/semitechnologies/model2vec-inference:minishlab-potion-base-4M DOCKER_IMAGES_TAR: docker-images.tar jobs: From f0a96aa0639b593b695e6c96e628856fa174ecd6 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Wed, 5 Nov 2025 23:29:13 +0100 Subject: [PATCH 44/59] debug(ci): do not cache model2vec image --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 41b97385c..c123f2aa5 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -38,7 +38,7 @@ jobs: run: | docker pull $IMG2VEC docker pull $MINIO - docker pull $MODEL2VEC + # docker pull $MODEL2VEC docker save $IMG2VEC $MINIO $MODEL2VEC -o $DOCKER_IMAGES_TAR maven-cache: From d085d06c2d1f685085720abbaafd273057fc6ba3 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Wed, 5 Nov 2025 23:37:24 +0100 Subject: [PATCH 45/59] ci(fix): do not save model2vec image --- .github/workflows/test.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index c123f2aa5..a0a2f1067 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -10,7 +10,7 @@ concurrency: env: IMG2VEC: cr.weaviate.io/semitechnologies/img2vec-pytorch:resnet50 - MINIO: minio/minio:latest + MINIO: minio/minio MODEL2VEC: cr.weaviate.io/semitechnologies/model2vec-inference:minishlab-potion-base-4M DOCKER_IMAGES_TAR: docker-images.tar @@ -39,7 +39,7 @@ jobs: docker pull $IMG2VEC docker pull $MINIO # docker pull $MODEL2VEC - docker save $IMG2VEC $MINIO $MODEL2VEC -o $DOCKER_IMAGES_TAR + docker save $IMG2VEC $MINIO -o $DOCKER_IMAGES_TAR maven-cache: name: Cache Maven dependencies From 05ec2adce0651063474b26cda723fc8615d36602 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Wed, 5 Nov 2025 23:45:09 +0100 Subject: [PATCH 46/59] ci(fix): use correct version tag --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index a0a2f1067..5f572f968 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -59,7 +59,7 @@ jobs: needs: [ docker-cache, maven-cache] strategy: matrix: - WEAVIATE_VERSION: ["1.32", "1.33"] + WEAVIATE_VERSION: ["1.32.0", "1.33.0"] steps: - uses: actions/checkout@v4 From 84f967a8bc13200b1f066bab1298070d0f45d364 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Wed, 5 Nov 2025 23:54:52 +0100 Subject: [PATCH 47/59] chore: user lookup-only restore in Docker Cache step --- .github/workflows/test.yaml | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 5f572f968..9c95fcf66 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -18,6 +18,8 @@ jobs: docker-cache: name: Cache shared Docker images runs-on: ubuntu-latest + env: + DOCKER_CACHE_KEY: docker-images-${{ env.IMG2VEC }}-${{ env.MINIO }}-${{ env.MODEL2VEC }} steps: - name: Login to Docker Hub if: ${{ !github.event.pull_request.head.repo.fork }} @@ -25,21 +27,25 @@ jobs: with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - - name: Restore and update Docker cache - id: docker-cache-restore - uses: actions/cache@v4 - env: - DOCKER_CACHE_KEY: docker-images-${{ env.IMG2VEC }}-${{ env.MINIO }}-${{ env.MODEL2VEC }} + - id: cache-check + uses: actions/cache/restore@v4 with: path: ${{ env.DOCKER_IMAGES_TAR }} key: ${{ env.DOCKER_CACHE_KEY }} + lookup-only: true # Only check if cache exists, don't download - name: Pull images - if: steps.docker-cache-restore.outputs.cache-hit != 'true' + if: steps.cache-check.outputs.cache-hit != 'true' run: | docker pull $IMG2VEC docker pull $MINIO # docker pull $MODEL2VEC docker save $IMG2VEC $MINIO -o $DOCKER_IMAGES_TAR + - name: Cache images + if: steps.cache-check.outputs.cache-hit != 'true' + uses: actions/cache/save@v4 + with: + path: ${{ env.DOCKER_IMAGES_TAR }} + key: ${{ env.DOCKER_CACHE_KEY }} maven-cache: name: Cache Maven dependencies @@ -57,15 +63,15 @@ jobs: name: Test runs-on: ubuntu-latest needs: [ docker-cache, maven-cache] + env: + DOCKER_CACHE_KEY: docker-images-${{ env.IMG2VEC }}-${{ env.MINIO }}-${{ env.MODEL2VEC }} strategy: matrix: WEAVIATE_VERSION: ["1.32.0", "1.33.0"] steps: - uses: actions/checkout@v4 - - uses: actions/cache@v4 - env: - DOCKER_CACHE_KEY: docker-images-${{ env.IMG2VEC }}-${{ env.MINIO }}-${{ env.MODEL2VEC }} + - uses: actions/cache/restore@v4 with: path: ${{ env.DOCKER_IMAGES_TAR }} key: ${{ env.DOCKER_CACHE_KEY }} From 063faf2066adf93fcab5e2ca20179f76adce4a17 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Wed, 5 Nov 2025 23:57:08 +0100 Subject: [PATCH 48/59] ci(fix): move env definition --- .github/workflows/test.yaml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 9c95fcf66..6eea4c120 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -18,8 +18,6 @@ jobs: docker-cache: name: Cache shared Docker images runs-on: ubuntu-latest - env: - DOCKER_CACHE_KEY: docker-images-${{ env.IMG2VEC }}-${{ env.MINIO }}-${{ env.MODEL2VEC }} steps: - name: Login to Docker Hub if: ${{ !github.event.pull_request.head.repo.fork }} @@ -29,6 +27,8 @@ jobs: password: ${{ secrets.DOCKER_PASSWORD }} - id: cache-check uses: actions/cache/restore@v4 + env: + DOCKER_CACHE_KEY: docker-images-${{ env.IMG2VEC }}-${{ env.MINIO }}-${{ env.MODEL2VEC }} with: path: ${{ env.DOCKER_IMAGES_TAR }} key: ${{ env.DOCKER_CACHE_KEY }} @@ -43,6 +43,8 @@ jobs: - name: Cache images if: steps.cache-check.outputs.cache-hit != 'true' uses: actions/cache/save@v4 + env: + DOCKER_CACHE_KEY: docker-images-${{ env.IMG2VEC }}-${{ env.MINIO }}-${{ env.MODEL2VEC }} with: path: ${{ env.DOCKER_IMAGES_TAR }} key: ${{ env.DOCKER_CACHE_KEY }} @@ -63,8 +65,6 @@ jobs: name: Test runs-on: ubuntu-latest needs: [ docker-cache, maven-cache] - env: - DOCKER_CACHE_KEY: docker-images-${{ env.IMG2VEC }}-${{ env.MINIO }}-${{ env.MODEL2VEC }} strategy: matrix: WEAVIATE_VERSION: ["1.32.0", "1.33.0"] @@ -72,6 +72,8 @@ jobs: - uses: actions/checkout@v4 - uses: actions/cache/restore@v4 + env: + DOCKER_CACHE_KEY: docker-images-${{ env.IMG2VEC }}-${{ env.MINIO }}-${{ env.MODEL2VEC }} with: path: ${{ env.DOCKER_IMAGES_TAR }} key: ${{ env.DOCKER_CACHE_KEY }} From 37d8d7501d867dd908744c7392b8e16e8399cf50 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Thu, 6 Nov 2025 00:04:09 +0100 Subject: [PATCH 49/59] ci: disable fail-fast --- .github/workflows/test.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 6eea4c120..76a2ea2fc 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -66,6 +66,7 @@ jobs: runs-on: ubuntu-latest needs: [ docker-cache, maven-cache] strategy: + fail-fast: false matrix: WEAVIATE_VERSION: ["1.32.0", "1.33.0"] steps: From b3806ac0009ec2ecacc849a8313ce02a3a232657 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Thu, 6 Nov 2025 00:13:39 +0100 Subject: [PATCH 50/59] ci: skip GPG signing for tests job --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 76a2ea2fc..d3facfdee 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -98,4 +98,4 @@ jobs: AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} OPENAI_APIKEY: ${{ secrets.OPENAI_APIKEY }} WEAVIATE_VERSION: ${{ matrix.WEAVIATE_VERSION }} - run: mvn verify + run: mvn verify -Dgpg.skip From 9017e922bb4cd5d92f90a1740ec786294c6c76b8 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Thu, 6 Nov 2025 11:11:36 +0100 Subject: [PATCH 51/59] chore: skip tests that require a later version --- src/it/java/io/weaviate/ConcurrentTest.java | 24 +++++++++++++++++++ .../io/weaviate/integration/RbacITest.java | 17 ++++++++----- .../api/rbac/roles/WeaviateRolesClient.java | 15 ++++++++++++ 3 files changed, 50 insertions(+), 6 deletions(-) diff --git a/src/it/java/io/weaviate/ConcurrentTest.java b/src/it/java/io/weaviate/ConcurrentTest.java index 57584e047..83c4be098 100644 --- a/src/it/java/io/weaviate/ConcurrentTest.java +++ b/src/it/java/io/weaviate/ConcurrentTest.java @@ -10,9 +10,13 @@ import org.apache.commons.lang3.RandomStringUtils; import org.assertj.core.api.Assertions; +import org.assertj.core.api.Assumptions; import org.junit.Rule; import org.junit.rules.TestName; +import io.weaviate.client6.v1.internal.VersionSupport.SemanticVersion; +import io.weaviate.containers.Weaviate; + /** * ConcurrentTest is the base class for integration tests, which provides * utility methods to uniqualize collections and objects created in the @@ -110,4 +114,24 @@ public static void eventually(Callable cond, int intervalMillis, int ti throw new RuntimeException(ex); } } + + /** + * Skip the test if the version that the {@link Weaviate} + * container is running is older than the required one. + */ + public static void requireAtLeast(int major, int minor) { + var required = new SemanticVersion(major, minor); + var actual = SemanticVersion.of(Weaviate.VERSION); + Assumptions.assumeThat(actual) + .as("requires at least %s, but running %s", required, actual) + .isGreaterThanOrEqualTo(required); + } + + public static void requireAtLeast(int major, int minor, Runnable r) { + var required = new SemanticVersion(major, minor); + var actual = SemanticVersion.of(Weaviate.VERSION); + if (actual.compareTo(required) >= 0) { + r.run(); + } + } } diff --git a/src/it/java/io/weaviate/integration/RbacITest.java b/src/it/java/io/weaviate/integration/RbacITest.java index 9bdbed2e9..4e3729074 100644 --- a/src/it/java/io/weaviate/integration/RbacITest.java +++ b/src/it/java/io/weaviate/integration/RbacITest.java @@ -1,7 +1,7 @@ package io.weaviate.integration; import java.io.IOException; -import java.util.Arrays; +import java.util.List; import org.assertj.core.api.Assertions; import org.assertj.core.api.InstanceOfAssertFactories; @@ -64,7 +64,7 @@ public void test_roles_Lifecycle() throws IOException { var myCollection = "Things"; var nsRole = ns("VectorOwner"); - Permission[] permissions = new Permission[] { + List permissions = List.of( Permission.aliases("ThingsAlias", myCollection, AliasesPermission.Action.CREATE), Permission.backups(myCollection, BackupsPermission.Action.MANAGE), Permission.cluster(ClusterPermission.Action.READ), @@ -72,11 +72,14 @@ public void test_roles_Lifecycle() throws IOException { Permission.roles(VIEWER_ROLE, Scope.MATCH, RolesPermission.Action.CREATE), Permission.collections(myCollection, CollectionsPermission.Action.CREATE), Permission.data(myCollection, DataPermission.Action.UPDATE), - Permission.groups("my-group", GroupType.OIDC, GroupsPermission.Action.READ), Permission.tenants(myCollection, "my-tenant", TenantsPermission.Action.DELETE), Permission.users("my-user", UsersPermission.Action.READ), - Permission.replicate(myCollection, "my-shard", ReplicatePermission.Action.READ), - }; + Permission.replicate(myCollection, "my-shard", ReplicatePermission.Action.READ)); + + requireAtLeast(1, 33, () -> { + permissions.add( + Permission.groups("my-group", GroupType.OIDC, GroupsPermission.Action.READ)); + }); // Act: create role client.roles.create(nsRole, permissions); @@ -86,7 +89,7 @@ public void test_roles_Lifecycle() throws IOException { .as("created role") .returns(nsRole, Role::name) .extracting(Role::permissions, InstanceOfAssertFactories.list(Permission.class)) - .containsAll(Arrays.asList(permissions)); + .containsAll(permissions); // Act:: add extra permissions var extra = new Permission[] { @@ -150,6 +153,8 @@ public void test_roles_userAssignments() throws IOException { @Test public void test_groups() throws IOException { + requireAtLeast(1, 33); + var mediaGroup = "./media-group"; var friendGroup = "./friend-group"; diff --git a/src/main/java/io/weaviate/client6/v1/api/rbac/roles/WeaviateRolesClient.java b/src/main/java/io/weaviate/client6/v1/api/rbac/roles/WeaviateRolesClient.java index b1120465a..4cea55f8b 100644 --- a/src/main/java/io/weaviate/client6/v1/api/rbac/roles/WeaviateRolesClient.java +++ b/src/main/java/io/weaviate/client6/v1/api/rbac/roles/WeaviateRolesClient.java @@ -29,6 +29,21 @@ public WeaviateRolesClient(RestTransport restTransport) { * or the server being unavailable. */ public void create(String roleName, Permission... permissions) throws IOException { + create(roleName, Arrays.asList(permissions)); + } + + /** + * Create a new role. + * + * @param roleName Role name. + * @param permissions Permissions granted to the role. + * @throws WeaviateApiException in case the server returned with an + * error status code. + * @throws IOException in case the request was not sent successfully + * due to a malformed request, a networking error + * or the server being unavailable. + */ + public void create(String roleName, List permissions) throws IOException { var role = new Role(roleName, permissions); this.restTransport.performRequest(new CreateRoleRequest(role), CreateRoleRequest._ENDPOINT); } From 3be9085a56f61cf0b2f8c4f73c721a2307ebbcf1 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Thu, 6 Nov 2025 11:12:33 +0100 Subject: [PATCH 52/59] ci: expand test matrix --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index d3facfdee..852f40c6a 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -68,7 +68,7 @@ jobs: strategy: fail-fast: false matrix: - WEAVIATE_VERSION: ["1.32.0", "1.33.0"] + WEAVIATE_VERSION: ["1.30.0", "1.31.0", "1.32.0", "1.33.0"] steps: - uses: actions/checkout@v4 From 1e3256acd9bdbbe543e365e4e414ec6e00dd88b1 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Thu, 6 Nov 2025 11:28:39 +0100 Subject: [PATCH 53/59] ci: disable some tests for earlier versions --- src/it/java/io/weaviate/integration/AliasITest.java | 6 ++++++ src/it/java/io/weaviate/integration/BackupITest.java | 4 ++++ src/it/java/io/weaviate/integration/RbacITest.java | 5 ++++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/it/java/io/weaviate/integration/AliasITest.java b/src/it/java/io/weaviate/integration/AliasITest.java index ab180d6f0..7da98e3ae 100644 --- a/src/it/java/io/weaviate/integration/AliasITest.java +++ b/src/it/java/io/weaviate/integration/AliasITest.java @@ -4,6 +4,7 @@ import java.util.List; import org.assertj.core.api.Assertions; +import org.junit.BeforeClass; import org.junit.Test; import io.weaviate.ConcurrentTest; @@ -14,6 +15,11 @@ public class AliasITest extends ConcurrentTest { private static final WeaviateClient client = Container.WEAVIATE.getClient(); + @BeforeClass + public static void __() { + requireAtLeast(1, 32); + } + @Test public void test_aliasLifecycle() throws IOException { // Arrange diff --git a/src/it/java/io/weaviate/integration/BackupITest.java b/src/it/java/io/weaviate/integration/BackupITest.java index bf0997930..3e8c80a99 100644 --- a/src/it/java/io/weaviate/integration/BackupITest.java +++ b/src/it/java/io/weaviate/integration/BackupITest.java @@ -29,6 +29,8 @@ public class BackupITest extends ConcurrentTest { @Test public void test_lifecycle() throws IOException, TimeoutException { + requireAtLeast(1, 32); // List backups not implemented in earlier versions + // Arrange String nsA = ns("A"), nsB = ns("B"), nsC = ns("C"), nsBig = ns("Big"); String backup_1 = ns("backup_1").toLowerCase(); @@ -122,6 +124,8 @@ public void test_lifecycle() throws IOException, TimeoutException { @Test public void test_lifecycle_async() throws ExecutionException, InterruptedException, Exception { + requireAtLeast(1, 32); // List backups not implemented in earlier versions + // Arrange String nsA = ns("A"), nsB = ns("B"), nsC = ns("C"), nsBig = ns("Big"); String backup_1 = ns("backup_1").toLowerCase(); diff --git a/src/it/java/io/weaviate/integration/RbacITest.java b/src/it/java/io/weaviate/integration/RbacITest.java index 4e3729074..c948b1b1d 100644 --- a/src/it/java/io/weaviate/integration/RbacITest.java +++ b/src/it/java/io/weaviate/integration/RbacITest.java @@ -65,7 +65,6 @@ public void test_roles_Lifecycle() throws IOException { var nsRole = ns("VectorOwner"); List permissions = List.of( - Permission.aliases("ThingsAlias", myCollection, AliasesPermission.Action.CREATE), Permission.backups(myCollection, BackupsPermission.Action.MANAGE), Permission.cluster(ClusterPermission.Action.READ), Permission.nodes(myCollection, NodesPermission.Action.READ), @@ -76,6 +75,10 @@ public void test_roles_Lifecycle() throws IOException { Permission.users("my-user", UsersPermission.Action.READ), Permission.replicate(myCollection, "my-shard", ReplicatePermission.Action.READ)); + requireAtLeast(1, 32, () -> { + permissions.add( + Permission.aliases("ThingsAlias", myCollection, AliasesPermission.Action.CREATE)); + }); requireAtLeast(1, 33, () -> { permissions.add( Permission.groups("my-group", GroupType.OIDC, GroupsPermission.Action.READ)); From 6c0600c899e45fb79b572b6d996e944a2304c7ab Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Thu, 6 Nov 2025 11:46:45 +0100 Subject: [PATCH 54/59] ci: raise minimal required version to 1.32 Replication API's changed between 1.31 and 1.32 and is completely incompatible --- .github/workflows/test.yaml | 2 +- src/it/java/io/weaviate/ConcurrentTest.java | 12 +++++------- .../java/io/weaviate/containers/Weaviate.java | 18 +++++++++++++++++- .../io/weaviate/integration/AliasITest.java | 3 ++- .../io/weaviate/integration/BackupITest.java | 4 ++-- .../io/weaviate/integration/RbacITest.java | 4 ++-- .../client6/v1/internal/VersionSupport.java | 2 +- 7 files changed, 30 insertions(+), 15 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 852f40c6a..d3facfdee 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -68,7 +68,7 @@ jobs: strategy: fail-fast: false matrix: - WEAVIATE_VERSION: ["1.30.0", "1.31.0", "1.32.0", "1.33.0"] + WEAVIATE_VERSION: ["1.32.0", "1.33.0"] steps: - uses: actions/checkout@v4 diff --git a/src/it/java/io/weaviate/ConcurrentTest.java b/src/it/java/io/weaviate/ConcurrentTest.java index 83c4be098..6e783ff06 100644 --- a/src/it/java/io/weaviate/ConcurrentTest.java +++ b/src/it/java/io/weaviate/ConcurrentTest.java @@ -119,18 +119,16 @@ public static void eventually(Callable cond, int intervalMillis, int ti * Skip the test if the version that the {@link Weaviate} * container is running is older than the required one. */ - public static void requireAtLeast(int major, int minor) { - var required = new SemanticVersion(major, minor); + public static void requireAtLeast(Weaviate.Version required) { var actual = SemanticVersion.of(Weaviate.VERSION); Assumptions.assumeThat(actual) - .as("requires at least %s, but running %s", required, actual) - .isGreaterThanOrEqualTo(required); + .as("requires at least %s, but running %s", required.semver, actual) + .isGreaterThanOrEqualTo(required.semver); } - public static void requireAtLeast(int major, int minor, Runnable r) { - var required = new SemanticVersion(major, minor); + public static void requireAtLeast(Weaviate.Version required, Runnable r) { var actual = SemanticVersion.of(Weaviate.VERSION); - if (actual.compareTo(required) >= 0) { + if (actual.compareTo(required.semver) >= 0) { r.run(); } } diff --git a/src/it/java/io/weaviate/containers/Weaviate.java b/src/it/java/io/weaviate/containers/Weaviate.java index b0b9105b8..bfd60dcfd 100644 --- a/src/it/java/io/weaviate/containers/Weaviate.java +++ b/src/it/java/io/weaviate/containers/Weaviate.java @@ -16,9 +16,11 @@ import org.testcontainers.lifecycle.Startable; import org.testcontainers.weaviate.WeaviateContainer; +import io.weaviate.ConcurrentTest; import io.weaviate.client6.v1.api.Config; import io.weaviate.client6.v1.api.WeaviateClient; import io.weaviate.client6.v1.internal.ObjectBuilder; +import io.weaviate.client6.v1.internal.VersionSupport.SemanticVersion; public class Weaviate extends WeaviateContainer { public static final String DOCKER_IMAGE = "semitechnologies/weaviate"; @@ -28,12 +30,26 @@ public class Weaviate extends WeaviateContainer { static { VERSION = System.getenv().getOrDefault("WEAVIATE_VERSION", LATEST_VERSION); } - public static String OIDC_ISSUER = "https://auth.wcs.api.weaviate.io/auth/realms/SeMI"; private volatile SharedClient clientInstance; private final String containerName; + public enum Version { + V132(1, 32), + V133(1, 33); + + public final SemanticVersion semver; + + private Version(int major, int minor) { + this.semver = new SemanticVersion(major, minor); + } + + public void orSkip() { + ConcurrentTest.requireAtLeast(this); + } + } + /** * By default, testcontainer's name is only available after calling * {@link #start}. diff --git a/src/it/java/io/weaviate/integration/AliasITest.java b/src/it/java/io/weaviate/integration/AliasITest.java index 7da98e3ae..eb5bca8eb 100644 --- a/src/it/java/io/weaviate/integration/AliasITest.java +++ b/src/it/java/io/weaviate/integration/AliasITest.java @@ -11,13 +11,14 @@ import io.weaviate.client6.v1.api.WeaviateClient; import io.weaviate.client6.v1.api.alias.Alias; import io.weaviate.containers.Container; +import io.weaviate.containers.Weaviate; public class AliasITest extends ConcurrentTest { private static final WeaviateClient client = Container.WEAVIATE.getClient(); @BeforeClass public static void __() { - requireAtLeast(1, 32); + Weaviate.Version.V132.orSkip(); } @Test diff --git a/src/it/java/io/weaviate/integration/BackupITest.java b/src/it/java/io/weaviate/integration/BackupITest.java index 3e8c80a99..c540afaae 100644 --- a/src/it/java/io/weaviate/integration/BackupITest.java +++ b/src/it/java/io/weaviate/integration/BackupITest.java @@ -29,7 +29,7 @@ public class BackupITest extends ConcurrentTest { @Test public void test_lifecycle() throws IOException, TimeoutException { - requireAtLeast(1, 32); // List backups not implemented in earlier versions + Weaviate.Version.V132.orSkip(); // List backups not implemented in earlier versions // Arrange String nsA = ns("A"), nsB = ns("B"), nsC = ns("C"), nsBig = ns("Big"); @@ -124,7 +124,7 @@ public void test_lifecycle() throws IOException, TimeoutException { @Test public void test_lifecycle_async() throws ExecutionException, InterruptedException, Exception { - requireAtLeast(1, 32); // List backups not implemented in earlier versions + Weaviate.Version.V132.orSkip(); // List backups not implemented in earlier versions // Arrange String nsA = ns("A"), nsB = ns("B"), nsC = ns("C"), nsBig = ns("Big"); diff --git a/src/it/java/io/weaviate/integration/RbacITest.java b/src/it/java/io/weaviate/integration/RbacITest.java index c948b1b1d..1ba0e6470 100644 --- a/src/it/java/io/weaviate/integration/RbacITest.java +++ b/src/it/java/io/weaviate/integration/RbacITest.java @@ -75,11 +75,11 @@ public void test_roles_Lifecycle() throws IOException { Permission.users("my-user", UsersPermission.Action.READ), Permission.replicate(myCollection, "my-shard", ReplicatePermission.Action.READ)); - requireAtLeast(1, 32, () -> { + requireAtLeast(Weaviate.Version.V132, () -> { permissions.add( Permission.aliases("ThingsAlias", myCollection, AliasesPermission.Action.CREATE)); }); - requireAtLeast(1, 33, () -> { + requireAtLeast(Weaviate.Version.V133, () -> { permissions.add( Permission.groups("my-group", GroupType.OIDC, GroupsPermission.Action.READ)); }); diff --git a/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java b/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java index 6ba324630..05763677c 100644 --- a/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java +++ b/src/main/java/io/weaviate/client6/v1/internal/VersionSupport.java @@ -3,7 +3,7 @@ import java.util.Arrays; public final class VersionSupport { - public static final SemanticVersion MINIMAL_SUPPORTED_VERSION = new SemanticVersion(1, 31); + public static final SemanticVersion MINIMAL_SUPPORTED_VERSION = new SemanticVersion(1, 32); /** * Returns true if the {@code version} is the same as or older than the From 2392d505ef59d962856cab17d92b657e0d35ff30 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Thu, 6 Nov 2025 11:50:22 +0100 Subject: [PATCH 55/59] fix: use mutable list --- .../io/weaviate/integration/RbacITest.java | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/it/java/io/weaviate/integration/RbacITest.java b/src/it/java/io/weaviate/integration/RbacITest.java index 1ba0e6470..30f8ecfa0 100644 --- a/src/it/java/io/weaviate/integration/RbacITest.java +++ b/src/it/java/io/weaviate/integration/RbacITest.java @@ -1,6 +1,7 @@ package io.weaviate.integration; import java.io.IOException; +import java.util.ArrayList; import java.util.List; import org.assertj.core.api.Assertions; @@ -64,16 +65,19 @@ public void test_roles_Lifecycle() throws IOException { var myCollection = "Things"; var nsRole = ns("VectorOwner"); - List permissions = List.of( - Permission.backups(myCollection, BackupsPermission.Action.MANAGE), - Permission.cluster(ClusterPermission.Action.READ), - Permission.nodes(myCollection, NodesPermission.Action.READ), - Permission.roles(VIEWER_ROLE, Scope.MATCH, RolesPermission.Action.CREATE), - Permission.collections(myCollection, CollectionsPermission.Action.CREATE), - Permission.data(myCollection, DataPermission.Action.UPDATE), - Permission.tenants(myCollection, "my-tenant", TenantsPermission.Action.DELETE), - Permission.users("my-user", UsersPermission.Action.READ), - Permission.replicate(myCollection, "my-shard", ReplicatePermission.Action.READ)); + List permissions = new ArrayList<>() { + { + add(Permission.backups(myCollection, BackupsPermission.Action.MANAGE)); + add(Permission.cluster(ClusterPermission.Action.READ)); + add(Permission.nodes(myCollection, NodesPermission.Action.READ)); + add(Permission.roles(VIEWER_ROLE, Scope.MATCH, RolesPermission.Action.CREATE)); + add(Permission.collections(myCollection, CollectionsPermission.Action.CREATE)); + add(Permission.data(myCollection, DataPermission.Action.UPDATE)); + add(Permission.tenants(myCollection, "my-tenant", TenantsPermission.Action.DELETE)); + add(Permission.users("my-user", UsersPermission.Action.READ)); + add(Permission.replicate(myCollection, "my-shard", ReplicatePermission.Action.READ)); + } + }; requireAtLeast(Weaviate.Version.V132, () -> { permissions.add( From 46817cc496ec5aab23a1ea660d02c59079640f08 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Thu, 6 Nov 2025 11:57:19 +0100 Subject: [PATCH 56/59] test: fix skip syntax --- src/it/java/io/weaviate/integration/RbacITest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/it/java/io/weaviate/integration/RbacITest.java b/src/it/java/io/weaviate/integration/RbacITest.java index 30f8ecfa0..ea61b96e7 100644 --- a/src/it/java/io/weaviate/integration/RbacITest.java +++ b/src/it/java/io/weaviate/integration/RbacITest.java @@ -160,7 +160,7 @@ public void test_roles_userAssignments() throws IOException { @Test public void test_groups() throws IOException { - requireAtLeast(1, 33); + Weaviate.Version.V133.orSkip(); var mediaGroup = "./media-group"; var friendGroup = "./friend-group"; From 053e5866d762f54cb8f2527c99fc4a3289f41270 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Thu, 6 Nov 2025 12:05:43 +0100 Subject: [PATCH 57/59] build: drop Lombok dependency --- pom.xml | 73 --------------------------------------------------------- 1 file changed, 73 deletions(-) diff --git a/pom.xml b/pom.xml index 465e0195c..a28dee7eb 100644 --- a/pom.xml +++ b/pom.xml @@ -52,7 +52,6 @@ 17 17 17 - 1.18.42 2.13.2 5.5.1 3.19.0 @@ -112,11 +111,6 @@ httpclient5 ${httpclient.version} - - org.projectlombok - lombok - ${lombok.version} - com.google.code.gson gson @@ -240,52 +234,6 @@ balanced - - org.projectlombok - lombok-maven-plugin - 1.18.20.0 - - - delombok-sources - generate-sources - - delombok - - - src/main/java - ${project.build.directory}/delombok - false - UTF-8 - - - - - - org.projectlombok - lombok - ${lombok.version} - - - - - org.apache.maven.plugins - maven-antrun-plugin - 3.0.0 - - - generate-delomboked-sources-jar - package - - run - - - - - - - - - org.codehaus.mojo versions-maven-plugin @@ -308,22 +256,6 @@ build-helper-maven-plugin 3.2.0 - - attach-delomboked-sources-jar - package - - attach-artifact - - - - - ${project.build.directory}/${project.build.finalName}-sources.jar - jar - sources - - - - add-test-source generate-test-sources @@ -375,7 +307,6 @@ - ${project.build.directory}/delombok all,-missing @@ -503,10 +434,6 @@ - - org.projectlombok - lombok-maven-plugin - org.xolstice.maven.plugins protobuf-maven-plugin From 1ed70bde9d8399526b4b3a8757a07462623a6825 Mon Sep 17 00:00:00 2001 From: Ivan Despot <66276597+g-despot@users.noreply.github.com> Date: Fri, 21 Nov 2025 16:00:45 +0100 Subject: [PATCH 58/59] Update src/it/java/io/weaviate/containers/Weaviate.java Co-authored-by: dyma solovei <53943884+bevzzz@users.noreply.github.com> --- src/it/java/io/weaviate/containers/Weaviate.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/it/java/io/weaviate/containers/Weaviate.java b/src/it/java/io/weaviate/containers/Weaviate.java index 8f174dea1..4c063e0ad 100644 --- a/src/it/java/io/weaviate/containers/Weaviate.java +++ b/src/it/java/io/weaviate/containers/Weaviate.java @@ -24,7 +24,7 @@ public class Weaviate extends WeaviateContainer { public static final String DOCKER_IMAGE = "semitechnologies/weaviate"; - public static final String LATEST_VERSION = "1.34.0"; + public static final String LATEST_VERSION = Version.V134.semver.toString(); public static final String VERSION; static { From e42446dcd5ea9014ffd78235a911c766de59988d Mon Sep 17 00:00:00 2001 From: Ivan Despot <66276597+g-despot@users.noreply.github.com> Date: Fri, 21 Nov 2025 16:04:07 +0100 Subject: [PATCH 59/59] Update Double to Float --- src/main/java/io/weaviate/client6/v1/api/backup/Backup.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/io/weaviate/client6/v1/api/backup/Backup.java b/src/main/java/io/weaviate/client6/v1/api/backup/Backup.java index 9d02a0673..9fa1c1025 100644 --- a/src/main/java/io/weaviate/client6/v1/api/backup/Backup.java +++ b/src/main/java/io/weaviate/client6/v1/api/backup/Backup.java @@ -34,7 +34,7 @@ public record Backup( /** Time at which the backup was completed, successfully or otherwise. */ @SerializedName("completedAt") OffsetDateTime completedAt, /** Backup size in GiB. */ - @SerializedName("size") Double sizeGiB, + @SerializedName("size") Float sizeGiB, /** * This value indicates if a backup is being created or restored from. * For operations like LIST this value is null.