diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/db/DbCloneClient.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/db/DbCloneClient.java new file mode 100644 index 00000000..30272f55 --- /dev/null +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/db/DbCloneClient.java @@ -0,0 +1,158 @@ +package com.dtsx.astra.sdk.db; + +import com.dtsx.astra.sdk.AbstractApiClient; +import com.dtsx.astra.sdk.db.domain.Database; +import com.dtsx.astra.sdk.db.domain.DatabaseCloneStatus; +import com.dtsx.astra.sdk.utils.ApiLocator; +import com.dtsx.astra.sdk.utils.ApiResponseHttp; +import com.dtsx.astra.sdk.utils.Assert; +import com.dtsx.astra.sdk.utils.AstraEnvironment; +import com.dtsx.astra.sdk.utils.JsonUtils; + +import java.net.HttpURLConnection; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.stream.Stream; + +/** + * Delegate operation on DB cloning + */ +public class DbCloneClient extends AbstractApiClient { + + /** Clone path component, part I. */ + public static final String PATH_CLONE_1 = "/databases/"; + + /** Clone path component, part II. */ + public static final String PATH_CLONE_2 = "/cloneFrom/"; + + /** Get-clone-status path component, part I. */ + public static final String PATH_GETSTATUS_1 = "/databases/"; + + /** Get-clone-status path component, part II. */ + public static final String PATH_GETSTATUS_2 = "/cloneStatus/"; + + /** + * unique db identifier. + */ + private final Database db; + + /** + * As immutable object use builder to initiate the object. + * + * @param token + * authenticated token + * @param databaseId + * database identifier + */ + public DbCloneClient(String token, String databaseId) { + this(token, AstraEnvironment.PROD, databaseId); + } + + /** + * As immutable object use builder to initiate the object. + * + * @param env + * define target environment to be used + * @param token + * authenticated token + * @param databaseId + * database identifier + */ + public DbCloneClient(String token, AstraEnvironment env, String databaseId) { + super(token, env); + Assert.hasLength(databaseId, "databaseId"); + this.db = new DbOpsClient(token, env, databaseId).get(); + } + + /** {@inheritDoc} */ + @Override + public String getServiceName() { + return "db.clone"; + } + + /** + * Clone database from a source database using a snapshot. + * + * @param sourceDbId + * ID of the source database + * @param databaseSnapshotId + * ID of the snapshot to clone from + * @return clone status + */ + public DatabaseCloneStatus cloneFrom(String sourceDbId, String databaseSnapshotId) { + return cloneFrom(sourceDbId, databaseSnapshotId, null); + } + + /** + * Clone database from a source database using a snapshot. + * + * @param sourceDbId + * ID of the source database + * @param databaseSnapshotId + * ID of the snapshot to clone from + * @param sourceRegion + * Source region (optional) + * @return clone status + */ + public DatabaseCloneStatus cloneFrom(String sourceDbId, String databaseSnapshotId, String sourceRegion) { + Assert.hasLength(sourceDbId, "sourceDbId"); + Assert.hasLength(databaseSnapshotId, "databaseSnapshotId"); + + // Build URL with query parameters + String url = getEndpointCloneFrom(sourceDbId) + + "?snapshotID=" + URLEncoder.encode(databaseSnapshotId, StandardCharsets.UTF_8); + + if (sourceRegion != null && !sourceRegion.isEmpty()) { + url += "&sourceRegion=" + URLEncoder.encode(sourceRegion, StandardCharsets.UTF_8); + } + + // Fire POST request + ApiResponseHttp res = POST(url, getOperationName("cloneFrom")); + + // Parse and return response + return JsonUtils.unmarshallBean(res.getBody(), DatabaseCloneStatus.class); + } + + /** + * Get the status of a clone operation. + * + * @param operationId + * ID of the clone operation + * @return clone status + */ + public DatabaseCloneStatus getCloneStatus(String operationId) { + Assert.hasLength(operationId, "operationId"); + + // Build URL + String url = getEndpointGetCloneStatus(operationId); + + // Fire GET request + ApiResponseHttp res = GET(url, getOperationName("getCloneStatus")); + + // Parse and return response + return JsonUtils.unmarshallBean(res.getBody(), DatabaseCloneStatus.class); + } + + /** + * Endpoint to initiate DB clone + * + * @param sourceDbId + * ID of the source database + * @return request endpoint + */ + private String getEndpointCloneFrom(String sourceDbId) { + return ApiLocator.getApiDevopsEndpoint(environment) + PATH_CLONE_1 + db.getId() + PATH_CLONE_2 + sourceDbId; + } + + /** + * Endpoint to retrieve a DB-clone status (by operation ID) + * + * @param operationId + * ID of the clone operation (as obtained e.g. with a cloneFrom previous invocation) + * @return request endpoint + */ + private String getEndpointGetCloneStatus(String operationId) { + return ApiLocator.getApiDevopsEndpoint(environment) + PATH_GETSTATUS_1 + db.getId() + PATH_GETSTATUS_2 + operationId; + } + +} diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/db/DbOpsClient.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/db/DbOpsClient.java index 0117ea85..46b30c71 100644 --- a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/db/DbOpsClient.java +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/db/DbOpsClient.java @@ -409,6 +409,32 @@ public DbPrivateLinksClient privateLink() { return new DbPrivateLinksClient(token, environment, databaseId); } + // --------------------------------- + // ---- Clone ---- + // --------------------------------- + + /** + * Delegate clone operation in a dedicated class + * + * @return clone client + */ + public DbCloneClient clone() { + return new DbCloneClient(token, environment, databaseId); + } + + // --------------------------------- + // ---- Snapshots ---- + // --------------------------------- + + /** + * Delegate snapshots operation in a dedicated class + * + * @return snapshots client + */ + public DbSnapshotsClient snapshots() { + return new DbSnapshotsClient(token, environment, databaseId); + } + // --------------------------------- // ---- Utilities ---- // --------------------------------- diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/db/DbSnapshotsClient.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/db/DbSnapshotsClient.java new file mode 100644 index 00000000..4fb32f4d --- /dev/null +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/db/DbSnapshotsClient.java @@ -0,0 +1,130 @@ +package com.dtsx.astra.sdk.db; + +import com.dtsx.astra.sdk.AbstractApiClient; +import com.dtsx.astra.sdk.db.domain.Database; +import com.dtsx.astra.sdk.db.domain.DatabaseSnapshot; +import com.dtsx.astra.sdk.db.domain.DatabaseSnapshotsResponse; +import com.dtsx.astra.sdk.utils.ApiLocator; +import com.dtsx.astra.sdk.utils.ApiResponseHttp; +import com.dtsx.astra.sdk.utils.Assert; +import com.dtsx.astra.sdk.utils.AstraEnvironment; +import com.dtsx.astra.sdk.utils.JsonUtils; + +import java.net.HttpURLConnection; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.stream.Stream; + +/** + * Delegate operation on snapshots + */ +public class DbSnapshotsClient extends AbstractApiClient { + + /** Path for listing snapshots, part I. */ + public static final String PATH_SNAPSHOTS_1 = "/databases/"; + + /** Path for listing snapshots, part II. */ + public static final String PATH_SNAPSHOTS_2 = "/snapshots"; + + /** + * unique db identifier. + */ + private final Database db; + + /** + * As immutable object use builder to initiate the object. + * + * @param token + * authenticated token + * @param databaseId + * database identifier + */ + public DbSnapshotsClient(String token, String databaseId) { + this(token, AstraEnvironment.PROD, databaseId); + } + + /** + * As immutable object use builder to initiate the object. + * + * @param env + * define target environment to be used + * @param token + * authenticated token + * @param databaseId + * database identifier + */ + public DbSnapshotsClient(String token, AstraEnvironment env, String databaseId) { + super(token, env); + Assert.hasLength(databaseId, "databaseId"); + this.db = new DbOpsClient(token, env, databaseId).get(); + } + + /** {@inheritDoc} */ + @Override + public String getServiceName() { + return "db.snapshots"; + } + + /** + * Get snapshots with filters. + * + * @param from + * start time (ISO 8601 format) + * @param to + * end time (ISO 8601 format) + * @param region + * region name + * @return list of snapshots. + */ + public Stream find(String from, String to, String region) { + // Build URL with query parameters + StringBuilder url = new StringBuilder(getEndpointSnapshots()); + boolean hasParams = false; + + if (region != null) { + url.append("?sourceRegion=").append(URLEncoder.encode(region, StandardCharsets.UTF_8)); + hasParams = true; + } + + if (from != null) { + url.append(hasParams ? "&" : "?").append("from=").append(URLEncoder.encode(from, StandardCharsets.UTF_8)); + hasParams = true; + } + + if (to != null) { + url.append(hasParams ? "&" : "?").append("to=").append(URLEncoder.encode(to, StandardCharsets.UTF_8)); + } + + // Invoke endpoint + ApiResponseHttp res = GET(url.toString(), getOperationName("find")); + + // Handle response + if (HttpURLConnection.HTTP_NOT_FOUND == res.getCode()) { + return Stream.of(); + } else { + DatabaseSnapshotsResponse response = JsonUtils.unmarshallBean(res.getBody(), DatabaseSnapshotsResponse.class); + return response.getSnapshots() != null ? response.getSnapshots().stream() : Stream.of(); + } + } + + /** + * Get all snapshots. + * + * @return list of snapshots. + */ + public Stream findAll() { + return find(null, null, null); + } + + // TODO: add other overloads here + + /** + * Endpoint to access snapshots of a db + * + * @return database endpoint + */ + private String getEndpointSnapshots() { + return ApiLocator.getApiDevopsEndpoint(environment) + PATH_SNAPSHOTS_1 + db.getId() + PATH_SNAPSHOTS_2; + } + +} diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/db/domain/DatabaseCloneStatus.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/db/domain/DatabaseCloneStatus.java new file mode 100644 index 00000000..9aa7fc7e --- /dev/null +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/db/domain/DatabaseCloneStatus.java @@ -0,0 +1,257 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.dtsx.astra.sdk.db.domain; + +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +/** + * Represent a database clone status. + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class DatabaseCloneStatus implements Serializable { + + /** Serial. */ + private static final long serialVersionUID = 8242671294103939313L; + + /** unique identifier for the operation. */ + private String operationId; + + /** source database identifier. */ + private String sourceDbId; + + /** target database identifier. */ + private String targetDbId; + + /** current phase of the clone operation. */ + private String phase; + + /** status of the clone operation. */ + private String status; + + /** message with additional details. */ + private String message; + + /** snapshot identifier. */ + private String snapshotId; + + /** timestamp when the clone was created. */ + private String createdAt; + + /** source region for the clone operation. */ + private String sourceRegion; + + /** target region for the clone operation. */ + private String targetRegion; + + /** + * Default constructor. + */ + public DatabaseCloneStatus() {} + + /** + * Getter accessor for attribute 'operationId'. + * + * @return + * current value of 'operationId' + */ + public String getOperationId() { + return operationId; + } + + /** + * Setter accessor for attribute 'operationId'. + * @param operationId + * new value for 'operationId ' + */ + public void setOperationId(String operationId) { + this.operationId = operationId; + } + + /** + * Getter accessor for attribute 'sourceDbId'. + * + * @return + * current value of 'sourceDbId' + */ + public String getSourceDbId() { + return sourceDbId; + } + + /** + * Setter accessor for attribute 'sourceDbId'. + * @param sourceDbId + * new value for 'sourceDbId ' + */ + public void setSourceDbId(String sourceDbId) { + this.sourceDbId = sourceDbId; + } + + /** + * Getter accessor for attribute 'targetDbId'. + * + * @return + * current value of 'targetDbId' + */ + public String getTargetDbId() { + return targetDbId; + } + + /** + * Setter accessor for attribute 'targetDbId'. + * @param targetDbId + * new value for 'targetDbId ' + */ + public void setTargetDbId(String targetDbId) { + this.targetDbId = targetDbId; + } + + /** + * Getter accessor for attribute 'phase'. + * + * @return + * current value of 'phase' + */ + public String getPhase() { + return phase; + } + + /** + * Setter accessor for attribute 'phase'. + * @param phase + * new value for 'phase ' + */ + public void setPhase(String phase) { + this.phase = phase; + } + + /** + * Getter accessor for attribute 'status'. + * + * @return + * current value of 'status' + */ + public String getStatus() { + return status; + } + + /** + * Setter accessor for attribute 'status'. + * @param status + * new value for 'status ' + */ + public void setStatus(String status) { + this.status = status; + } + + /** + * Getter accessor for attribute 'message'. + * + * @return + * current value of 'message' + */ + public String getMessage() { + return message; + } + + /** + * Setter accessor for attribute 'message'. + * @param message + * new value for 'message ' + */ + public void setMessage(String message) { + this.message = message; + } + + /** + * Getter accessor for attribute 'snapshotId'. + * + * @return + * current value of 'snapshotId' + */ + public String getSnapshotId() { + return snapshotId; + } + + /** + * Setter accessor for attribute 'snapshotId'. + * @param snapshotId + * new value for 'snapshotId ' + */ + public void setSnapshotId(String snapshotId) { + this.snapshotId = snapshotId; + } + + /** + * Getter accessor for attribute 'createdAt'. + * + * @return + * current value of 'createdAt' + */ + public String getCreatedAt() { + return createdAt; + } + + /** + * Setter accessor for attribute 'createdAt'. + * @param createdAt + * new value for 'createdAt ' + */ + public void setCreatedAt(String createdAt) { + this.createdAt = createdAt; + } + + /** + * Getter accessor for attribute 'sourceRegion'. + * + * @return + * current value of 'sourceRegion' + */ + public String getSourceRegion() { + return sourceRegion; + } + + /** + * Setter accessor for attribute 'sourceRegion'. + * @param sourceRegion + * new value for 'sourceRegion ' + */ + public void setSourceRegion(String sourceRegion) { + this.sourceRegion = sourceRegion; + } + + /** + * Getter accessor for attribute 'targetRegion'. + * + * @return + * current value of 'targetRegion' + */ + public String getTargetRegion() { + return targetRegion; + } + + /** + * Setter accessor for attribute 'targetRegion'. + * @param targetRegion + * new value for 'targetRegion ' + */ + public void setTargetRegion(String targetRegion) { + this.targetRegion = targetRegion; + } + +} diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/db/domain/DatabaseSnapshot.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/db/domain/DatabaseSnapshot.java new file mode 100644 index 00000000..e8715470 --- /dev/null +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/db/domain/DatabaseSnapshot.java @@ -0,0 +1,81 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.dtsx.astra.sdk.db.domain; + +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +/** + * Represent a database snapshot. + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class DatabaseSnapshot implements Serializable { + + /** Serial. */ + private static final long serialVersionUID = 8242671294103939312L; + + /** unique identifier for the snapshot. */ + private String id; + + /** snapshot time. */ + private String time; + + /** + * Default constructor. + */ + public DatabaseSnapshot() {} + + /** + * Getter accessor for attribute 'id'. + * + * @return + * current value of 'id' + */ + public String getId() { + return id; + } + + /** + * Setter accessor for attribute 'id'. + * @param id + * new value for 'id ' + */ + public void setId(String id) { + this.id = id; + } + + /** + * Getter accessor for attribute 'time'. + * + * @return + * current value of 'time' + */ + public String getTime() { + return time; + } + + /** + * Setter accessor for attribute 'time'. + * @param time + * new value for 'time ' + */ + public void setTime(String time) { + this.time = time; + } + +} diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/db/domain/DatabaseSnapshotsResponse.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/db/domain/DatabaseSnapshotsResponse.java new file mode 100644 index 00000000..b184b21e --- /dev/null +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/db/domain/DatabaseSnapshotsResponse.java @@ -0,0 +1,60 @@ +/* + * Copyright DataStax, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.dtsx.astra.sdk.db.domain; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import java.io.Serializable; +import java.util.List; + +/** + * Response wrapper for database snapshots list. + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class DatabaseSnapshotsResponse implements Serializable { + + /** Serial. */ + private static final long serialVersionUID = 1L; + + /** list of snapshots. */ + private List snapshots; + + /** + * Default constructor. + */ + public DatabaseSnapshotsResponse() {} + + /** + * Getter accessor for attribute 'snapshots'. + * + * @return + * current value of 'snapshots' + */ + public List getSnapshots() { + return snapshots; + } + + /** + * Setter accessor for attribute 'snapshots'. + * @param snapshots + * new value for 'snapshots ' + */ + public void setSnapshots(List snapshots) { + this.snapshots = snapshots; + } + +} diff --git a/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/AbstractDevopsApiTest.java b/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/AbstractDevopsApiTest.java index 64607136..5916f3b3 100644 --- a/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/AbstractDevopsApiTest.java +++ b/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/AbstractDevopsApiTest.java @@ -4,6 +4,7 @@ import com.dtsx.astra.sdk.db.AstraDBOpsClient; import com.dtsx.astra.sdk.db.domain.DatabaseCreationRequest; import com.dtsx.astra.sdk.streaming.AstraStreamingClient; +import com.dtsx.astra.sdk.utils.AstraEnvironment; import com.dtsx.astra.sdk.utils.AstraRc; import com.dtsx.astra.sdk.utils.Utils; import org.junit.jupiter.api.Assertions; @@ -33,25 +34,30 @@ public abstract class AbstractDevopsApiTest { */ private static String token; + /** + * Hold reference to environment + */ + private static AstraEnvironment env; + /** * Reference to Databases Client. */ - private static AstraDBOpsClient databasesClient; + protected static AstraDBOpsClient databasesClient; /** * Reference to organization client. */ - private static AstraOpsClient apiDevopsClient; + protected static AstraOpsClient apiDevopsClient; /** * Working db. */ - private static DbOpsClient dbClient; + protected static DbOpsClient dbClient; /** * Reference to Databases Client. */ - private static AstraStreamingClient streamingClient; + protected static AstraStreamingClient streamingClient; /** * Access DB client. @@ -61,7 +67,7 @@ public abstract class AbstractDevopsApiTest { */ protected AstraOpsClient getApiDevopsClient() { if (apiDevopsClient == null) { - apiDevopsClient = new AstraOpsClient(getToken()); + apiDevopsClient = new AstraOpsClient(getToken(), getEnvironment()); } return apiDevopsClient; } @@ -70,11 +76,11 @@ protected AstraOpsClient getApiDevopsClient() { * Access DB client. * * @return - * client fot databases + * client for databases */ protected AstraDBOpsClient getDatabasesClient() { if (databasesClient == null) { - databasesClient = new AstraDBOpsClient(getToken()); + databasesClient = new AstraDBOpsClient(getToken(), getEnvironment()); } return databasesClient; } @@ -87,7 +93,7 @@ protected AstraDBOpsClient getDatabasesClient() { */ protected AstraStreamingClient getStreamingClient() { if (streamingClient == null) { - streamingClient = new AstraStreamingClient(getToken()); + streamingClient = new AstraStreamingClient(getToken(), getEnvironment()); } return streamingClient; } @@ -110,6 +116,31 @@ protected String getToken() { return token; } + /** + * Get the target Astra environment from ASTRA_ENV environment variable. + * Defaults to PROD if not set or invalid. + * + * @return + * target environment + */ + protected AstraEnvironment getEnvironment() { + String envStr = null; + if (env == null) { + if (AstraRc.isDefaultConfigFileExists()) { + envStr = new AstraRc() + .getSectionKey(AstraRc.ASTRARC_DEFAULT, AstraRc.ASTRA_ENV) + .orElse(null); + } + envStr = Utils.readEnvVariable(AstraRc.ASTRA_ENV).orElse(envStr); + if (envStr == null) { + env = AstraEnvironment.PROD; + } else { + env = AstraEnvironment.valueOf(envStr); + } + } + return env; + } + /** * Create DB if not exist * diff --git a/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/db/DatabaseClientTest.java b/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/db/DatabaseClientTest.java index 897a61ce..06004116 100644 --- a/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/db/DatabaseClientTest.java +++ b/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/db/DatabaseClientTest.java @@ -3,6 +3,8 @@ import com.dtsx.astra.sdk.AbstractDevopsApiTest; import com.dtsx.astra.sdk.db.domain.AccessListAddressRequest; import com.dtsx.astra.sdk.db.domain.CloudProviderType; +import com.dtsx.astra.sdk.db.domain.DatabaseCloneStatus; +import com.dtsx.astra.sdk.db.domain.DatabaseSnapshot; import com.dtsx.astra.sdk.db.domain.DatabaseStatusType; import com.dtsx.astra.sdk.db.domain.Datacenter; import com.dtsx.astra.sdk.db.exception.KeyspaceAlreadyExistException; @@ -273,4 +275,83 @@ public void shouldTerminateDbTest() { //Assert.assertEquals(0, getDatabasesClient().findByName(SDK_TEST_DB_NAME).count()); } + @Test + @Order(21) + @DisplayName("21. Should list snapshots") + public void shouldListSnapshotsTest() { + /* + TODOS: + // extract the region from the endpoint name + // automate environment selection for tests? (clone is still in dev probably?) + */ + final String CLONE_DEV_REGION = "northamerica-northeast2"; + final String CLONE_DEV_DB_ID = "6c446013-552d-4264-a0ee-74951d662722"; + DbOpsClient dbClient = getApiDevopsClient().db().database(CLONE_DEV_DB_ID); + + // TODO refine the various query patterns and overloads as they come + int filteredSnapshotCount = (dbClient.snapshots().find( + "2000-01-01T01:23:45.000Z", "2040-01-01T01:23:45.000Z", CLONE_DEV_REGION + )).toList().size(); + int fullSnapshotCount = (dbClient.snapshots().findAll()).toList().size(); + Assertions.assertTrue(filteredSnapshotCount <= fullSnapshotCount); + // This is to ensure something is actually parsed back successfully. + // The DB must be created more than ~1 h ago. Alternatively can trigger a manual snapshot through Autobot + Assertions.assertTrue(fullSnapshotCount > 0); + DatabaseSnapshot theSnapshot = dbClient.snapshots().findAll().findFirst().get(); + Assertions.assertNotNull(theSnapshot); + Assertions.assertNotNull(theSnapshot.getId()); + Assertions.assertNotNull(theSnapshot.getTime()); + } + + @Test + @Order(22) + @DisplayName("22. Should initiate a DB clone") + public void shouldInitiateCloneTest() { + /* + TODOS: + // Maybe some parsing from endpoints for IDs and the region. + // Actually this whole test will not be a test that one really runs regularly (?) + */ + final String CLONE_DEV_REGION = "northamerica-northeast2"; + final String CLONE_DEV_SOURCE_DB_ID = "6c446013-552d-4264-a0ee-74951d662722"; + final String CLONE_DEV_TARGET_DB_ID = "b19fd2ba-8ec6-4d18-b2a3-a4b404557748"; + DbOpsClient dbSourceClient = getApiDevopsClient().db().database(CLONE_DEV_SOURCE_DB_ID); + DbOpsClient dbTargetClient = getApiDevopsClient().db().database(CLONE_DEV_TARGET_DB_ID); + + DatabaseSnapshot theSnapshot = dbSourceClient.snapshots().findAll().findFirst().get(); + + DatabaseCloneStatus cloneStatus = dbTargetClient.clone().cloneFrom(dbSourceClient.getDatabaseId(), theSnapshot.getId()); + + Assertions.assertNotNull(cloneStatus); + Assertions.assertNotNull(cloneStatus.getOperationId()); + Assertions.assertEquals(cloneStatus.getSourceDbId(), CLONE_DEV_SOURCE_DB_ID); + Assertions.assertEquals(cloneStatus.getTargetDbId(), CLONE_DEV_TARGET_DB_ID); + Assertions.assertEquals(cloneStatus.getPhase(), "PreInit"); + } + + @Test + @Order(23) + @DisplayName("23. Should get a clone status by operation ID") + public void shouldGetCloneStatusByOperationId() { + /* + TODOS: + // Maybe some parsing from endpoints for the target db ID. + // Another test that might need to be scrapped away from here. + */ + final String CLONE_OPERATION_ID = "01d0c7c9-c23b-43db-a92f-881af93c1e18"; + final String CLONE_DEV_SOURCE_DB_ID = "6c446013-552d-4264-a0ee-74951d662722"; + final String CLONE_DEV_TARGET_DB_ID = "b19fd2ba-8ec6-4d18-b2a3-a4b404557748"; + final String CLONE_DEV_REGION = "northamerica-northeast2"; + DbOpsClient dbTargetClient = getApiDevopsClient().db().database(CLONE_DEV_TARGET_DB_ID); + + DatabaseCloneStatus cloneStatus = dbTargetClient.clone().getCloneStatus(CLONE_OPERATION_ID); + + Assertions.assertNotNull(cloneStatus); + Assertions.assertEquals(cloneStatus.getOperationId(), CLONE_OPERATION_ID); + Assertions.assertEquals(cloneStatus.getSourceDbId(), CLONE_DEV_SOURCE_DB_ID); + Assertions.assertEquals(cloneStatus.getTargetDbId(), CLONE_DEV_TARGET_DB_ID); + Assertions.assertEquals(cloneStatus.getSourceRegion(), CLONE_DEV_REGION); + Assertions.assertEquals(cloneStatus.getTargetRegion(), CLONE_DEV_REGION); + } + }