Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ jobs:
strategy:
fail-fast: false
matrix:
WEAVIATE_VERSION: ["1.32.24", "1.33.11", "1.34.7", "1.35.2"]
WEAVIATE_VERSION:
["1.32.24", "1.33.11", "1.34.7", "1.35.2", "1.36.0-rc.0"]
steps:
- uses: actions/checkout@v4

Expand Down
27 changes: 27 additions & 0 deletions src/it/java/io/weaviate/ConcurrentTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,37 @@ public static void requireAtLeast(Weaviate.Version required) {
.isGreaterThanOrEqualTo(required.semver);
}

@FunctionalInterface
public interface ThrowingRunnable {
void run() throws Exception;
}

/**
* Run a block of code only if the server version is recent enough.
*
* @param required Minimal required version.
* @param r Runnable.
*/
public static void requireAtLeast(Weaviate.Version required, Runnable r) {
var actual = SemanticVersion.of(Weaviate.VERSION);
if (actual.compareTo(required.semver) >= 0) {
r.run();
}
}

/**
* Wraps a {@link ThrowingRunnable} as {@link Runnable} that
* re-throws all exceptions as {@link RuntimeException}.
*
* @param tr Runnable which may throw a checked exception.
*/
public static Runnable throwing(ThrowingRunnable tr) {
return () -> {
try {
tr.run();
} catch (Exception e) {
throw new RuntimeException(e);
}
};
}
}
17 changes: 15 additions & 2 deletions src/it/java/io/weaviate/containers/Weaviate.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

public class Weaviate extends WeaviateContainer {
public static final String DOCKER_IMAGE = "semitechnologies/weaviate";
public static final String LATEST_VERSION = Version.V135.semver.toString();
public static final String LATEST_VERSION = Version.latest().semver.toString();
public static final String VERSION;

static {
Expand All @@ -41,17 +41,30 @@ public enum Version {
V132(1, 32, 24),
V133(1, 33, 11),
V134(1, 34, 7),
V135(1, 35, 2);
V135(1, 35, 2),
V136(1, 36, "0-rc.0");

public final SemanticVersion semver;

private Version(int major, int minor, int patch) {
this.semver = new SemanticVersion(major, minor, patch);
}

private Version(int major, int minor, String patch) {
this.semver = new SemanticVersion(major, minor, patch);
}

public void orSkip() {
ConcurrentTest.requireAtLeast(this);
}

public static Version latest() {
Version[] versions = Version.class.getEnumConstants();
if (versions == null) {
throw new IllegalStateException("No versions are defined");
}
return versions[versions.length - 1];
}
}

/**
Expand Down
26 changes: 17 additions & 9 deletions src/it/java/io/weaviate/integration/BackupITest.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
import org.assertj.core.api.InstanceOfAssertFactories;
import org.junit.Test;

import com.sun.nio.sctp.IllegalUnbindException;

import io.weaviate.ConcurrentTest;
import io.weaviate.client6.v1.api.WeaviateClient;
import io.weaviate.client6.v1.api.backup.Backup;
Expand Down Expand Up @@ -112,14 +114,22 @@ public void test_lifecycle() throws IOException, TimeoutException {

// Act: delete data and restore backup #1
client.collections.delete(nsA);
client.backup.restore(backup_1, backend, restore -> restore.includeCollections(nsA));
var restoreMe = client.backup.restore(backup_1, backend, restore -> restore.includeCollections(nsA));

// Assert: object inserted in the beginning of the test is present
var restore_1 = client.backup.getRestoreStatus(backup_1, backend)
.orElseThrow().waitForCompletion(client);
Assertions.assertThat(restore_1).as("restore backup #1")
restoreMe = restoreMe.waitForCompletion(client);
Assertions.assertThat(restoreMe).as("restore backup #1")
.returns(BackupStatus.SUCCESS, Backup::status);
Assertions.assertThat(collectionA.size()).as("after restore backup #1").isEqualTo(1);

// Act: restore and cancel
requireAtLeast(Weaviate.Version.V136, throwing(() -> {
var restore_2 = client.backup.restore(backup_2, backend);
client.backup.cancelRestore(backup_2, backend);
var canceledRestore = restore_2.waitForStatus(client, BackupStatus.CANCELED);
Assertions.assertThat(canceledRestore).as("cancel backup restore #2")
.returns(BackupStatus.CANCELED, Backup::status);
}));
}

@Test
Expand Down Expand Up @@ -215,13 +225,11 @@ public void test_lifecycle_async() throws ExecutionException, InterruptedExcepti

// Act: delete data and restore backup #1
async.collections.delete(nsA).join();
async.backup.restore(backup_1, backend, restore -> restore.includeCollections(nsA)).join();
var restoreMe = async.backup.restore(backup_1, backend, restore -> restore.includeCollections(nsA)).join();

// Assert: object inserted in the beginning of the test is present
var restore_1 = async.backup.getRestoreStatus(backup_1, backend)
.thenCompose(bak -> bak.orElseThrow().waitForCompletion(async))
.join();
Assertions.assertThat(restore_1).as("restore backup #1")
restoreMe = restoreMe.waitForCompletion(async).join();
Assertions.assertThat(restoreMe).as("restore backup #1")
.returns(BackupStatus.SUCCESS, Backup::status);
Assertions.assertThat(collectionA.size().join()).as("after restore backup #1").isEqualTo(1);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ public enum BackupStatus {
TRANSFERRING,
/**
* Cancellation has been claimed by a coordinator.
* Used as a distributed lock to prevent race conditions when multiple coordinators
* attempt to cancel the same restore.
* Used as a distributed lock to prevent race conditions when multiple
* coordinators attempt to cancel the same restore.
*/
@SerializedName("CANCELLING")
CANCELLING,
Expand All @@ -28,10 +28,7 @@ public enum BackupStatus {
/** Backup creation / restoration failed. */
@SerializedName("FAILED")
FAILED,
/**
* Backup creation canceled.
* This status is never returned for backup restorations.
*/
/** Backup creation canceled. */
@SerializedName("CANCELED")
CANCELED;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package io.weaviate.client6.v1.api.backup;

import java.util.Collections;

import io.weaviate.client6.v1.internal.rest.Endpoint;
import io.weaviate.client6.v1.internal.rest.SimpleEndpoint;

public record CancelBackupRestoreRequest(String backupId, String backend) {

public static Endpoint<CancelBackupRestoreRequest, Void> _ENDPOINT = SimpleEndpoint.sideEffect(
request -> "DELETE",
request -> "/backups/" + request.backend + "/" + request.backupId + "/restore",
request -> Collections.emptyMap());
}
Original file line number Diff line number Diff line change
Expand Up @@ -179,18 +179,49 @@ public List<Backup> list(String backend, Function<ListBackupsRequest.Builder, Ob
/**
* Cancel in-progress backup.
*
* <p>
* This method cannot be called cancel backup restore.
*
* @param backupId Backup ID.
* @param backend Backup storage backend.
* @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.
* @deprecated This method forwards to {@link #cancelCreate}. Prefer using the
* latter, as it is less ambiguous.
*/
@Deprecated
public void cancel(String backupId, String backend) throws IOException {
cancelCreate(backupId, backend);
}

/**
* Cancel in-progress backup creation.
*
* @param backupId Backup ID.
* @param backend Backup storage backend.
* @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 cancelCreate(String backupId, String backend) throws IOException {
this.restTransport.performRequest(new CancelBackupRequest(backupId, backend), CancelBackupRequest._ENDPOINT);
}

/**
* Cancel in-progress backup restore.
*
* @param backupId Backup ID.
* @param backend Backup storage backend.
* @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 cancelRestore(String backupId, String backend) throws IOException {
this.restTransport.performRequest(new CancelBackupRestoreRequest(backupId, backend),
CancelBackupRestoreRequest._ENDPOINT);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -124,16 +124,37 @@ public CompletableFuture<List<Backup>> list(String backend,
}

/**
* Cancel in-progress backup.
*
* <p>
* This method cannot be called cancel backup restore.
* Cancel in-progress backup creation.
*
* @param backupId Backup ID.
* @param backend Backup storage backend.
* @deprecated This method forwards to {@link #cancelCreate}. Prefer using the
* latter, as it is less ambiguous.
*/
@Deprecated
public CompletableFuture<Void> cancel(String backupId, String backend) {
return cancelCreate(backupId, backend);
}

/**
* Cancel in-progress backup creation.
*
* @param backupId Backup ID.
* @param backend Backup storage backend.
*/
public CompletableFuture<Void> cancelCreate(String backupId, String backend) {
return this.restTransport.performRequestAsync(new CancelBackupRequest(backupId, backend),
CancelBackupRequest._ENDPOINT);
}

/**
* Cancel in-progress backup restore.
*
* @param backupId Backup ID.
* @param backend Backup storage backend.
*/
public CompletableFuture<Void> cancelRestore(String backupId, String backend) {
return this.restTransport.performRequestAsync(new CancelBackupRestoreRequest(backupId, backend),
CancelBackupRestoreRequest._ENDPOINT);
}
}