From 675ace7601e2c09474ce986d5d2223af5cb15f28 Mon Sep 17 00:00:00 2001 From: Sudharshan Pollapally <33074200+spollapally@users.noreply.github.com> Date: Mon, 25 Jun 2018 21:13:33 -0400 Subject: [PATCH] bigtable: Fluent DSL TableAdmin client (#3395) --- .../handwritten_files.lst | 8 + .../bigtable/admin/v2/TableAdminClient.java | 755 ++++++++++++++++++ .../bigtable/admin/v2/models/GCRules.java | 288 +++++++ .../admin/v2/models/TableAdminRequests.java | 213 +++++ .../admin/v2/models/TableAdminResponses.java | 321 ++++++++ .../admin/v2/TableAdminClientTest.java | 304 +++++++ .../admin/v2/it/TableAdminClientIT.java | 222 +++++ .../bigtable/admin/v2/models/GCRulesTest.java | 294 +++++++ .../v2/models/TableAdminRequestsTest.java | 124 +++ .../v2/models/TableAdminResponsesTest.java | 229 ++++++ 10 files changed, 2758 insertions(+) create mode 100644 google-cloud-clients/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/TableAdminClient.java create mode 100644 google-cloud-clients/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/models/GCRules.java create mode 100644 google-cloud-clients/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/models/TableAdminRequests.java create mode 100644 google-cloud-clients/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/models/TableAdminResponses.java create mode 100644 google-cloud-clients/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/TableAdminClientTest.java create mode 100644 google-cloud-clients/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/it/TableAdminClientIT.java create mode 100644 google-cloud-clients/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/models/GCRulesTest.java create mode 100644 google-cloud-clients/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/models/TableAdminRequestsTest.java create mode 100644 google-cloud-clients/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/models/TableAdminResponsesTest.java diff --git a/google-cloud-clients/google-cloud-bigtable/handwritten_files.lst b/google-cloud-clients/google-cloud-bigtable/handwritten_files.lst index acf082236813..7d385c98eb25 100644 --- a/google-cloud-clients/google-cloud-bigtable/handwritten_files.lst +++ b/google-cloud-clients/google-cloud-bigtable/handwritten_files.lst @@ -74,3 +74,11 @@ src/main/java/com/google/cloud/bigtable/data/v2/internal/ByteStringComparator.ja src/main/java/com/google/cloud/bigtable/data/v2/internal/DummyBatchingDescriptor.java src/main/java/com/google/cloud/bigtable/data/v2/internal/RequestContext.java src/main/java/com/google/cloud/bigtable/data/v2/internal/RegexUtil.java +src/main/java/com/google/cloud/bigtable/admin/v2/TableAdminClient.java +src/main/java/com/google/cloud/bigtable/admin/v2/models/GCRules.java +src/main/java/com/google/cloud/bigtable/admin/v2/models/TableAdminRequests.java +src/main/java/com/google/cloud/bigtable/admin/v2/models/TableAdminResponses.java +src/test/java/com/google/cloud/bigtable/admin/v2/TableAdminClientTest.java +src/test/java/com/google/cloud/bigtable/admin/v2/it/TableAdminClientIT.java +src/test/java/com/google/cloud/bigtable/admin/v2/models/TableAdminRequestsTest.java +src/test/java/com/google/cloud/bigtable/admin/v2/models/TableAdminResponsesTest.java diff --git a/google-cloud-clients/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/TableAdminClient.java b/google-cloud-clients/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/TableAdminClient.java new file mode 100644 index 000000000000..3351fc09bce4 --- /dev/null +++ b/google-cloud-clients/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/TableAdminClient.java @@ -0,0 +1,755 @@ +/* + * Copyright 2018 Google LLC + * + * 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 + * + * https://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.google.cloud.bigtable.admin.v2; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import com.google.api.core.ApiFunction; +import com.google.api.core.ApiFuture; +import com.google.api.core.ApiFutures; +import com.google.api.core.BetaApi; +import com.google.bigtable.admin.v2.CheckConsistencyResponse; +import com.google.bigtable.admin.v2.DeleteTableRequest; +import com.google.bigtable.admin.v2.DropRowRangeRequest; +import com.google.bigtable.admin.v2.DropRowRangeRequest.Builder; +import com.google.bigtable.admin.v2.GenerateConsistencyTokenRequest; +import com.google.bigtable.admin.v2.GenerateConsistencyTokenResponse; +import com.google.bigtable.admin.v2.GetTableRequest; +import com.google.bigtable.admin.v2.InstanceName; +import com.google.bigtable.admin.v2.ListTablesRequest; +import com.google.bigtable.admin.v2.ListTablesResponse; +import com.google.bigtable.admin.v2.ModifyColumnFamiliesRequest; +import com.google.bigtable.admin.v2.TableName; +import com.google.cloud.bigtable.admin.v2.models.TableAdminRequests.CreateTable; +import com.google.cloud.bigtable.admin.v2.models.TableAdminRequests.ModifyFamilies; +import com.google.cloud.bigtable.admin.v2.models.TableAdminResponses; +import com.google.cloud.bigtable.admin.v2.models.TableAdminResponses.ConsistencyToken; +import com.google.cloud.bigtable.admin.v2.models.TableAdminResponses.Table; +import com.google.cloud.bigtable.admin.v2.stub.BigtableTableAdminStub; +import com.google.cloud.bigtable.admin.v2.stub.BigtableTableAdminStubSettings; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Preconditions; +import com.google.protobuf.ByteString; +import com.google.protobuf.Empty; + +/** + * Client for creating, configuring, and deleting Cloud Bigtable tables + * + *

Provides access to the table schemas only, not the data stored within the tables. + * + *

See the individual methods for example code. + * + *

Sample code to get started: + * + *

{@code
+ * try(TableAdminClient client =  TableAdminClient.create(InstanceName.of("[PROJECT]", "[INSTANCE]"))) {
+ *   CreateTable createTableReq =
+ *     TableAdminRequests.createTable("tableId")
+ *       .addFamily("cf1")
+ *       .addFamily("cf2", GCRULES.maxVersions(10))
+ *       .addSplit(ByteString.copyFromUtf8("b"))
+ *       .addSplit(ByteString.copyFromUtf8("q"));
+ *   client.createTable(createTableReq);
+ *  }
+ *  }
+ * + *

Note: close() needs to be called on the bigtableTableAdminClient object to clean up resources + * such as threads. In the example above, try-with-resources is used, which automatically calls + * close(). + * + *

This class can be customized by passing in a custom instance of BigtableTableAdminSettings to + * create(). For example: + * + *

To customize credentials: + * + *

{@code
+ * BigtableTableAdminSettings bigtableTableAdminSettings =
+ *   BigtableTableAdminSettings.newBuilder()
+ *   .setCredentialsProvider(FixedCredentialsProvider.create(myCredentials))
+ *   .build();
+ * TableAdminClient client =
+ *   TableAdminClient.create(InstanceName.of("[PROJECT]", "[INSTANCE]"), bigtableTableAdminSettings);
+ * }
+ * + * To customize the endpoint: + * + *
{@code
+ * BigtableTableAdminSettings bigtableTableAdminSettings =
+ *     BigtableTableAdminSettings.newBuilder().setEndpoint(myEndpoint).build();
+ * TableAdminClient client =
+ *   TableAdminClient.create(InstanceName.of("[PROJECT]", "[INSTANCE]"), bigtableTableAdminSettings);
+ * }
+ */ +@BetaApi +public class TableAdminClient implements AutoCloseable { + private final BigtableTableAdminStub stub; + private final InstanceName instanceName; + + /** + * Constructs an instance of TableAdminClient with the given instanceName + * + * @param instanceName + * @throws IOException + */ + public static TableAdminClient create(InstanceName instanceName) throws IOException { + return new TableAdminClient(instanceName, BigtableTableAdminSettings.newBuilder().build()); + } + + /** + * Constructs an instance of TableAdminClient with the given instanceName and + * bigtableTableAdminSettings + * + * @param instanceName + * @param adminSettings + * @throws IOException + */ + public static TableAdminClient create( + InstanceName instanceName, BigtableTableAdminSettings adminSettings) throws IOException { + return new TableAdminClient(instanceName, adminSettings); + } + + /** + * Constructs an instance of TableAdminClient with the given instanceName and + * bigtableTableAdminStub + * + * @param instanceName + * @param stub + * @throws IOException + */ + public static TableAdminClient create(InstanceName instanceName, BigtableTableAdminStub stub) + throws IOException { + return new TableAdminClient(instanceName, stub); + } + + private TableAdminClient(InstanceName instanceName, BigtableTableAdminSettings adminSettings) + throws IOException { + this( + instanceName, + ((BigtableTableAdminStubSettings) adminSettings.getStubSettings()).createStub()); + } + + private TableAdminClient(InstanceName instanceName, BigtableTableAdminStub stub) + throws IOException { + Preconditions.checkNotNull(instanceName); + Preconditions.checkNotNull(stub); + this.instanceName = instanceName; + this.stub = stub; + } + + /** + * Gets the instanceName this client is associated to + * + * @return InstanceName + */ + public InstanceName getInstanceName() { + return instanceName; + } + + @Override + public void close() { + stub.close(); + } + + /** + * Creates a new table with the specified configuration + * + *

Sample code: + * + *

{@code
+   * try(TableAdminClient client =  TableAdminClient.create(InstanceName.of("[PROJECT]", "[INSTANCE]"))) {
+   *   CreateTable createTableReq =
+   *     TableAdminRequests.createTable("tableId")
+   *       .addFamily("cf2", GCRULES.maxVersions(10))
+   *   client.createTable(createTableReq);
+   * }
+   * }
+ * + * @param createTable + * @return Table - the newly created table + * @see CreateTable for createTable configurations + */ + public Table createTable(CreateTable createTable) { + com.google.bigtable.admin.v2.Table table = + this.stub.createTableCallable().call(createTable.toProto(instanceName)); + return TableAdminResponses.convertTable(table); + } + + /** + * Creates a new table with the specified configuration asynchronously + * + *

Sample code: + * + *

{@code
+   *  try(TableAdminClient client =  TableAdminClient.create(InstanceName.of("[PROJECT]", "[INSTANCE]"))) {
+   *    CreateTable createTableReq =
+   *      TableAdminRequests.createTable("tableId")
+   *        .addFamily("cf2", GCRULES.maxVersions(10))
+   *    client.createTableAsync(createTableReq);
+   *  }
+   *  }
+ * + * @param createTable + * @return ApiFuture - the newly created table + * @see CreateTable for createTable configurations + */ + public ApiFuture
createTableAsync(CreateTable createTable) { + return transformToTableResponse( + this.stub.createTableCallable().futureCall(createTable.toProto(instanceName))); + } + + /** + * Creates, Updates and drops ColumnFamilies as per the request. + * + *

Sample code: + * + *

{@code
+   * try(TableAdminClient client =  TableAdminClient.create(InstanceName.of("[PROJECT]", "[INSTANCE]"))) {
+   *   ModifyFamilies modifyFamiliesReq = TableAdminRequests.modifyFamilies(tableId)
+   *     .addFamily("mf1")
+   *     .addFamily(
+   *       "mf2", GCRULES.maxAge(Duration.ofSeconds(1000, 20000)))
+   *     .updateFamily(
+   *       "mf1",
+   *          GCRULES
+   *            .union()
+   *              .rule(GCRULES.maxAge(Duration.ofSeconds(100)))
+   *              .rule(GCRULES.maxVersions(1)))
+   *     .addFamily(
+   *       "mf3",
+   *         GCRULES
+   *           .intersection()
+   *           .rule(GCRULES.maxAge(Duration.ofSeconds(2000)))
+   *           .rule(GCRULES.maxVersions(10)))
+   *     .dropFamily("mf1")
+   *    client.modifyFamilies(modifyFamiliesReq);
+   * }
+   * }
+ * + * @param modifyFamily + * @return Table - Modified table + * @see ModifyFamilies for modifyFamily options + */ + public Table modifyFamilies(ModifyFamilies modifyFamily) { + ModifyColumnFamiliesRequest modReq = modifyFamily.toProto(instanceName); + com.google.bigtable.admin.v2.Table table = + this.stub.modifyColumnFamiliesCallable().call(modReq); + return TableAdminResponses.convertTable(table); + } + + /** + * Creates, Updates and drops ColumnFamilies as per the request asynchronously + * + *

Sample code: + * + *

{@code
+   * try(TableAdminClient client =  TableAdminClient.create(InstanceName.of("[PROJECT]", "[INSTANCE]"))) {
+   *   ModifyFamilies modifyFamiliesReq = TableAdminRequests.modifyFamilies(tableId)
+   *     .addFamily("mf1")
+   *     .addFamily(
+   *       "mf2", GCRULES.maxAge(Duration.ofSeconds(1000, 20000)))
+   *     .updateFamily(
+   *       "mf1",
+   *          GCRULES
+   *            .union()
+   *              .rule(GCRULES.maxAge(Duration.ofSeconds(100)))
+   *              .rule(GCRULES.maxVersions(1)))
+   *     .addFamily(
+   *       "mf3",
+   *         GCRULES
+   *           .intersection()
+   *           .rule(GCRULES.maxAge(Duration.ofSeconds(2000)))
+   *           .rule(GCRULES.maxVersions(10)))
+   *     .dropFamily("mf1")
+   *    client.modifyFamilies(modifyFamiliesReq);
+   * }
+   * }
+ * + * @param modifyFamily + * @return ApiFuture
- Modified table + * @see ModifyFamilies for modifyFamily options + */ + public ApiFuture
modifyFamiliesAsync(ModifyFamilies modifyFamily) { + ModifyColumnFamiliesRequest modReq = modifyFamily.toProto(instanceName); + return transformToTableResponse(this.stub.modifyColumnFamiliesCallable().futureCall(modReq)); + } + + /** + * Deletes the specified tableId + * + *

Sample code: + * + *

{@code
+   * try(TableAdminClient client =  TableAdminClient.create(InstanceName.of("[PROJECT]", "[INSTANCE]"))) {
+   *   client.deleteTable("tableId");
+   * }
+   * }
+ * + * @param tableId + */ + public void deleteTable(String tableId) { + this.stub.deleteTableCallable().call(composeDeleteTableRequest(tableId)); + } + + /** + * Deletes the specified tableId asynchronously + * + *

Sample code: + * + *

{@code
+   * try(TableAdminClient client =  TableAdminClient.create(InstanceName.of("[PROJECT]", "[INSTANCE]"))) {
+   *   client.deleteTableAsync("tableId");
+   * }
+   * }
+ * + * @param tableId + */ + public ApiFuture deleteTableAsync(String tableId) { + return transformToVoid( + this.stub.deleteTableCallable().futureCall(composeDeleteTableRequest(tableId))); + } + + /** + * Gets the Table by tableId + * + *

Sample code: + * + *

{@code
+   * try(TableAdminClient client =  TableAdminClient.create(InstanceName.of("[PROJECT]", "[INSTANCE]"))) {
+   *   client.getTable("tableId");
+   * }
+   * }
+ * + * @param tableId + * @return Table + */ + public Table getTable(String tableId) { + com.google.bigtable.admin.v2.Table table = + this.stub.getTableCallable().call(composeGetTableRequest(tableId)); + return TableAdminResponses.convertTable(table); + } + + /** + * Gets the Table by tableId + * + *

Sample code: + * + *

{@code
+   * try(TableAdminClient client =  TableAdminClient.create(InstanceName.of("[PROJECT]", "[INSTANCE]"))) {
+   *   client.getTableAsync("tableId");
+   * }
+   * }
+ * + * @param tableId + * @return ApiFuture
+ */ + public ApiFuture
getTableAsync(String tableId) { + return transformToTableResponse( + this.stub.getTableCallable().futureCall(composeGetTableRequest(tableId))); + } + + /** + * Lists all TableNames in the instance. + * + *

Sample code: + * + *

{@code
+   * try(TableAdminClient client =  TableAdminClient.create(InstanceName.of("[PROJECT]", "[INSTANCE]"))) {
+   *   client.listTables();
+   * }
+   * }
+ * + * @param tableId + * @return List + */ + public List listTables() { + ListTablesResponse listResp = this.stub.listTablesCallable().call(composeListTableRequest()); + return convertToTableNames(listResp); + } + + /** + * Lists all TableNames in the instance asynchronously + * + *

Sample code: + * + *

{@code
+   * try(TableAdminClient client =  TableAdminClient.create(InstanceName.of("[PROJECT]", "[INSTANCE]"))) {
+   *   client.listTablesAsync();
+   * }
+   * }
+ * + * @param tableId + * @return List + */ + public ApiFuture> listTablesAsync() { + ApiFuture listResp = + this.stub.listTablesCallable().futureCall(composeListTableRequest()); + + return ApiFutures.transform( + listResp, + new ApiFunction>() { + @Override + public List apply(ListTablesResponse input) { + return convertToTableNames(input); + } + }); + } + + /** + * Drops rows by the specified key prefix and tableId + * + *

Sample code: + * + *

{@code
+   * try(TableAdminClient client =  TableAdminClient.create(InstanceName.of("[PROJECT]", "[INSTANCE]"))) {
+   *   client.dropRowRange("tableId");
+   * }
+   * }
+ * + * @param tableId + * @param rowKeyPrefix + */ + public void dropRowRange(String tableId, String rowKeyPrefix) { + dropRowRange(tableId, ByteString.copyFromUtf8(rowKeyPrefix)); + } + + /** + * Drops rows by the specified key prefix and tableId asynchronously + * + *

Sample code: + * + *

{@code
+   * try(TableAdminClient client =  TableAdminClient.create(InstanceName.of("[PROJECT]", "[INSTANCE]"))) {
+   *   client.dropRowRangeAsync("tableId");
+   * }
+   * }
+ * + * @param tableId + * @param rowKeyPrefix + */ + public ApiFuture dropRowRangeAsync(String tableId, String rowKeyPrefix) { + return dropRowRangeAsync(tableId, ByteString.copyFromUtf8(rowKeyPrefix)); + } + + /** + * Drops rows by the specified key prefix and tableId + * + *

Sample code: + * + *

{@code
+   * try(TableAdminClient client =  TableAdminClient.create(InstanceName.of("[PROJECT]", "[INSTANCE]"))) {
+   *   client.dropRowRange("tableId");
+   * }
+   * }
+ * + * @param tableId + * @param rowKeyPrefix + */ + public void dropRowRange(String tableId, ByteString rowKeyPrefix) { + this.stub.dropRowRangeCallable().call(composeDropRowRangeRequest(tableId, rowKeyPrefix, false)); + } + + /** + * Drops rows by the specified key prefix and tableId + * + *

Sample code: + * + *

{@code
+   * try(TableAdminClient client =  TableAdminClient.create(InstanceName.of("[PROJECT]", "[INSTANCE]"))) {
+   *   client.dropRowRangeAsync("tableId");
+   * }
+   * }
+ * + * @param tableId + * @param rowKeyPrefix + */ + public ApiFuture dropRowRangeAsync(String tableId, ByteString rowKeyPrefix) { + return transformToVoid( + this.stub + .dropRowRangeCallable() + .futureCall(composeDropRowRangeRequest(tableId, rowKeyPrefix, false))); + } + + /** + * Drops all data in the table + * + *

Sample code: + * + *

{@code
+   * try(TableAdminClient client =  TableAdminClient.create(InstanceName.of("[PROJECT]", "[INSTANCE]"))) {
+   *   client.dropAllRows("tableId");
+   * }
+   * }
+ * + * @param tableId + */ + public void dropAllRows(String tableId) { + this.stub.dropRowRangeCallable().call(composeDropRowRangeRequest(tableId, null, true)); + } + + /** + * Drops all data in the table asynchronously + * + *

Sample code: + * + *

{@code
+   * try(TableAdminClient client =  TableAdminClient.create(InstanceName.of("[PROJECT]", "[INSTANCE]"))) {
+   *   client.dropAllRowsAsync("tableId");
+   * }
+   * }
+ * + * @param tableId + * @return ApiFuture + */ + public ApiFuture dropAllRowsAsync(String tableId) { + return transformToVoid( + this.stub + .dropRowRangeCallable() + .futureCall(composeDropRowRangeRequest(tableId, null, true))); + } + + /** + * Generates a token to verify the replication status of table mutations invoked before this call. + * Token expires in 90 days + * + *

Sample code: + * + *

{@code
+   * try(TableAdminClient client =  TableAdminClient.create(InstanceName.of("[PROJECT]", "[INSTANCE]"))) {
+   *   ConsistencyToken consistencyToken = client.generateConsistencyToken("tableId");
+   * }
+   * }
+ * + * @param tableId + * @return ConsistencyToken + */ + public ConsistencyToken generateConsistencyToken(String tableId) { + return TableAdminResponses.convertTokenResponse( + this.stub + .generateConsistencyTokenCallable() + .call(composeGenerateConsistencyTokenRequest(tableId))); + } + + /** + * Generates a token to verify the replication status of table mutations invoked before this call + * asynchronously Token expires in 90 days + * + *

Sample code: + * + *

{@code
+   * try(TableAdminClient client =  TableAdminClient.create(InstanceName.of("[PROJECT]", "[INSTANCE]"))) {
+   *   ConsistencyToken consistencyToken = client.generateConsistencyToken("tableId");
+   * }
+   * }
+ * + * @param tableId + * @return ApiFuture + */ + public ApiFuture generateConsistencyTokenAsync(String tableId) { + ApiFuture tokenResp = + this.stub + .generateConsistencyTokenCallable() + .futureCall(composeGenerateConsistencyTokenRequest(tableId)); + + return ApiFutures.transform( + tokenResp, + new ApiFunction() { + @Override + public ConsistencyToken apply(GenerateConsistencyTokenResponse input) { + return TableAdminResponses.convertTokenResponse(input); + } + }); + } + + /** + * Checks replication consistency for the specified token consistency token + * + *

Sample code: + * + *

{@code
+   * try(TableAdminClient client =  TableAdminClient.create(InstanceName.of("[PROJECT]", "[INSTANCE]"))) {
+   *   boolean consistent = client.isConsistent("tableId", token);
+   * }
+   * }
+ * + * @param tableId + * @param token + * @return boolean + */ + public boolean isConsistent(String tableId, ConsistencyToken token) { + return stub.checkConsistencyCallable() + .call(token.toProto(getTableName(tableId))) + .getConsistent(); + } + + /** + * Checks replication consistency for the specified token consistency token asynchronously + * + *

Sample code: + * + *

{@code
+   * try(TableAdminClient client =  TableAdminClient.create(InstanceName.of("[PROJECT]", "[INSTANCE]"))) {
+   *   boolean consistent = client.isConsistentAsync("tableId", token);
+   * }
+   * }
+ * + * @param tableId + * @param token + * @return ApiFuture + */ + public ApiFuture isConsistentAsync(String tableId, ConsistencyToken token) { + ApiFuture checkConsResp = + stub.checkConsistencyCallable().futureCall(token.toProto(getTableName(tableId))); + + return ApiFutures.transform( + checkConsResp, + new ApiFunction() { + @Override + public Boolean apply(CheckConsistencyResponse input) { + return input.getConsistent(); + } + }); + } + + /** + * Helper method to construct the table name in format: + * projects/{project}/instances/{instance}/tables/{tableId} + * + * @param tableId + * @return String - unique table name + */ + @VisibleForTesting + String getTableName(String tableId) { + return TableName.of(instanceName.getProject(), instanceName.getInstance(), tableId).toString(); + } + + /** + * Helper method to build an instance of ListTablesRequest + * + * @return ListTablesRequest + */ + @VisibleForTesting + ListTablesRequest composeListTableRequest() { + return ListTablesRequest.newBuilder().setParent(instanceName.toString()).build(); + } + + /** + * Helper method to build an instance of GetTableRequest + * + * @param tableId + * @return GetTableRequest + */ + @VisibleForTesting + GetTableRequest composeGetTableRequest(String tableId) { + return GetTableRequest.newBuilder().setName(getTableName(tableId)).build(); + } + + /** + * Helper method to build an instance of DeleteTableRequest + * + * @param tableId + * @return DeleteTableRequest + */ + @VisibleForTesting + DeleteTableRequest composeDeleteTableRequest(String tableId) { + return DeleteTableRequest.newBuilder().setName(getTableName(tableId)).build(); + } + + /** + * Helper method to build an instance of DropRowRangeRequest + * + * @param tableId + * @param rowKeyPrefix + * @param boolean dropAll + * @return DropRowRangeRequest + */ + @VisibleForTesting + DropRowRangeRequest composeDropRowRangeRequest( + String tableId, ByteString rowKeyPrefix, boolean dropAll) { + Builder dropRowReq = DropRowRangeRequest.newBuilder().setName(getTableName(tableId)); + + if (dropAll) { + dropRowReq.setDeleteAllDataFromTable(true); + } else { + dropRowReq.setRowKeyPrefix(rowKeyPrefix); + } + return dropRowReq.build(); + } + + /** + * Helper method to build an instance of GenerateConsistencyTokenRequest + * + * @param tableId + * @return GenerateConsistencyTokenRequest + */ + @VisibleForTesting + GenerateConsistencyTokenRequest composeGenerateConsistencyTokenRequest(String tableId) { + return GenerateConsistencyTokenRequest.newBuilder().setName(getTableName(tableId)).build(); + } + + /** + * Helper method to convert ListTablesResponse to List + * + * @param listTablesResponse + * @return List + */ + @VisibleForTesting + static List convertToTableNames(ListTablesResponse listTablesResponse) { + List tableNames = new ArrayList<>(); + + for (com.google.bigtable.admin.v2.Table table : listTablesResponse.getTablesList()) { + tableNames.add(TableName.parse(table.getName())); + } + return tableNames; + } + + /** + * Helper method to transform ApiFuture to ApiFuture
+ * + * @param future + * @return ApiFuture
+ */ + @VisibleForTesting + static ApiFuture
transformToTableResponse( + ApiFuture future) { + return ApiFutures.transform( + future, + new ApiFunction() { + @Override + public Table apply(com.google.bigtable.admin.v2.Table table) { + return TableAdminResponses.convertTable(table); + } + }); + } + + /** + * Helper method to transform ApiFuture to ApiFuture + * + * @param future + * @return ApiFuture + */ + @VisibleForTesting + static ApiFuture transformToVoid(ApiFuture future) { + return ApiFutures.transform( + future, + new ApiFunction() { + @Override + public Void apply(Empty empty) { + return null; + } + }); + } +} diff --git a/google-cloud-clients/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/models/GCRules.java b/google-cloud-clients/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/models/GCRules.java new file mode 100644 index 000000000000..624f91781a78 --- /dev/null +++ b/google-cloud-clients/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/models/GCRules.java @@ -0,0 +1,288 @@ +/* + * Copyright 2018 Google LLC + * + * 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 + * + * https://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.google.cloud.bigtable.admin.v2.models; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; +import javax.annotation.Nonnull; +import org.threeten.bp.Duration; +import com.google.api.core.BetaApi; +import com.google.api.core.InternalApi; +import com.google.bigtable.admin.v2.GcRule; +import com.google.bigtable.admin.v2.GcRule.Intersection; +import com.google.bigtable.admin.v2.GcRule.Union; +import com.google.common.base.MoreObjects; + +/** Wraps {@link GcRule} protocol buffer object and exposes a simpler Fluent DSL model */ +@BetaApi +public final class GCRules { + /** Factory method to create GCRules - entry point into the DSL. */ + public static final GCRules GCRULES = new GCRules(); + + private GCRules() {} + + /** + * Creates a new instance of the IntersectionRule + * + * @return IntersectionRule + */ + public IntersectionRule intersection() { + return new IntersectionRule(); + } + + /** + * Creates a new instance of the IntersectionRule + * + * @return UnionRule + */ + public UnionRule union() { + return new UnionRule(); + } + + /** + * Creates a new instance of the VersionRule + * + * @param maxVersion - maximum number of cell versions to keep + * @return VersionRule + */ + public VersionRule maxVersions(int maxVersion) { + return new VersionRule(maxVersion); + } + + /** + * Creates a new instance of the DurationRule + * + * @param maxAge - maximum age of the cell to keep + * @param timeUnit - timeunit for the age + * @return DurationRule + */ + public DurationRule maxAge(long maxAge, TimeUnit timeUnit) { + return maxAge(Duration.ofNanos(TimeUnit.NANOSECONDS.convert(maxAge, timeUnit))); + } + + /** + * Creates a new instance of the DurationRule + * + * @param duration - age expressed as duration + * @return DurationRule + */ + public DurationRule maxAge(Duration duration) { + return new DurationRule(duration); + } + + /** + * Creates an empty default rule + * + * @return DefaultRule + */ + public DefaultRule defaultRule() { + return new DefaultRule(); + } + + /** + * Fluent wrapper for {@link Intersection} rule. Allows far adding an hierarchy of rules with + * intersection as the root + */ + public static final class IntersectionRule implements GCRule { + private final List rulesList; + + private IntersectionRule() { + rulesList = new ArrayList<>(); + } + + /** + * Adds a new GCRule + * + * @param rule + * @return IntersectionRule + */ + public IntersectionRule rule(@Nonnull GCRule rule) { + rulesList.add(rule); + return this; + } + + /** + * Gets the list of child rules + * + * @return List + */ + public List getRulesList() { + return rulesList; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this).add("rulesList", rulesList).toString(); + } + + @InternalApi + @Override + public GcRule toProto() { + switch (rulesList.size()) { + case 0: + return GcRule.newBuilder().build(); + case 1: + return rulesList.get(0).toProto(); + default: + return GcRule.newBuilder() + .setIntersection(Intersection.newBuilder().addAllRules(convertToGcRules(rulesList))) + .build(); + } + } + } + + /** + * Fluent wrapper for {@link Union} rule. Allows far adding an hierarchy of rules with union as + * the root + */ + public static final class UnionRule implements GCRule { + private final List rulesList; + + private UnionRule() { + rulesList = new ArrayList<>(); + } + + /** + * Adds a new GCRule + * + * @param rule + * @return UnionRule + */ + public UnionRule rule(@Nonnull GCRule rule) { + rulesList.add(rule); + return this; + } + + /** + * Gets the list of child rules + * + * @return List + */ + public List getRulesList() { + return rulesList; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this).add("rulesList", rulesList).toString(); + } + + @InternalApi + @Override + public GcRule toProto() { + switch (rulesList.size()) { + case 0: + return GcRule.newBuilder().build(); + case 1: + return rulesList.get(0).toProto(); + default: + return GcRule.newBuilder() + .setUnion(Union.newBuilder().addAllRules(convertToGcRules(rulesList))) + .build(); + } + } + } + + /** Wrapper for building max versions rule */ + public static final class VersionRule implements GCRule { + private final GcRule.Builder builder; + + private VersionRule(int maxVersion) { + this.builder = GcRule.newBuilder(); + builder.setMaxNumVersions(maxVersion); + } + + /** Gets the configured maximum versions */ + public int getMaxVersions() { + return builder.getMaxNumVersions(); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this).add("maxNumVersions", getMaxVersions()).toString(); + } + + @InternalApi + @Override + public GcRule toProto() { + return builder.build(); + } + } + + /** Wrapper for building max duration rule */ + public static final class DurationRule implements GCRule { + private final com.google.protobuf.Duration.Builder builder; + + private DurationRule(Duration duration) { + this.builder = + com.google.protobuf.Duration.newBuilder() + .setSeconds(duration.getSeconds()) + .setNanos(duration.getNano()); + } + + /** + * Gets the configured maximum age + * + * @return Duration + */ + public Duration getMaxAge() { + return Duration.ofSeconds(builder.getSeconds(), builder.getNanos()); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this).add("maxAge", getMaxAge()).toString(); + } + + @InternalApi + @Override + public GcRule toProto() { + return GcRule.newBuilder().setMaxAge(builder.build()).build(); + } + } + + /** Wrapper for building a empty rule */ + public static final class DefaultRule implements GCRule { + private DefaultRule() {} + + @InternalApi + @Override + public GcRule toProto() { + return GcRule.getDefaultInstance(); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this).toString(); + } + } + + /** interface for fluent GcRule wrappers */ + public interface GCRule { + @InternalApi + GcRule toProto(); + } + + private static List convertToGcRules(List rules) { + List gcRules = new ArrayList<>(rules.size()); + + for (GCRule rule : rules) { + gcRules.add(rule.toProto()); + } + return gcRules; + } +} diff --git a/google-cloud-clients/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/models/TableAdminRequests.java b/google-cloud-clients/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/models/TableAdminRequests.java new file mode 100644 index 000000000000..ed4197069099 --- /dev/null +++ b/google-cloud-clients/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/models/TableAdminRequests.java @@ -0,0 +1,213 @@ +/* + * Copyright 2018 Google LLC + * + * 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 + * + * https://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.google.cloud.bigtable.admin.v2.models; + +import com.google.api.core.BetaApi; +import com.google.api.core.InternalApi; +import com.google.bigtable.admin.v2.ColumnFamily; +import com.google.bigtable.admin.v2.CreateTableRequest; +import com.google.bigtable.admin.v2.CreateTableRequest.Split; +import com.google.bigtable.admin.v2.InstanceName; +import com.google.bigtable.admin.v2.ModifyColumnFamiliesRequest; +import com.google.bigtable.admin.v2.ModifyColumnFamiliesRequest.Modification; +import com.google.bigtable.admin.v2.Table; +import com.google.bigtable.admin.v2.TableName; +import com.google.cloud.bigtable.admin.v2.models.GCRules.GCRule; +import com.google.common.base.Preconditions; +import com.google.protobuf.ByteString; + +/** Fluent DSL models to build Bigtable Table admin requests */ +@BetaApi +public final class TableAdminRequests { + private TableAdminRequests() {} + + /** + * Factory method to get an instance of CreateTable + * + * @param tableId - the id of the table to create + * @return CreateTable + */ + public static CreateTable createTable(String tableId) { + return new CreateTable(tableId); + } + + /** + * Factory method to get an instance of ModifyFamilies + * + * @param tableId - the id of the table to create + * @return ModifyFamilies + */ + public static ModifyFamilies modifyFamilies(String tableId) { + return new ModifyFamilies(tableId); + } + + /** + * Fluent wrapper for {@link CreateTableRequest} + * + *

Allows for creating table with: + * + *

    + *
  • optional columnFamilies, including optional {@link GCRule} + *
  • optional granularity + *
  • and optional split points + *
+ */ + public static final class CreateTable { + private final CreateTableRequest.Builder createTableRequest = CreateTableRequest.newBuilder(); + private final Table.Builder tableRequest = Table.newBuilder(); + + /** + * Configures table with the specified id + * + * @param tableId + */ + private CreateTable(String tableId) { + createTableRequest.setTableId(tableId); + } + + /** + * Adds a new columnFamily to the configuration + * + * @param familyId + */ + public CreateTable addFamily(String familyId) { + Preconditions.checkNotNull(familyId); + tableRequest.putColumnFamilies(familyId, ColumnFamily.newBuilder().build()); + return this; + } + + /** + * Adds a new columnFamily with {@link GCRule} to the configuration + * + * @param familyId + * @param gcRule + */ + public CreateTable addFamily(String familyId, GCRule gcRule) { + Preconditions.checkNotNull(familyId); + tableRequest.putColumnFamilies( + familyId, ColumnFamily.newBuilder().setGcRule(gcRule.toProto()).build()); + return this; + } + + /** + * Adds split at the specified key to the configuration + * + * @param key + */ + public CreateTable addSplit(ByteString key) { + Preconditions.checkNotNull(key); + createTableRequest.addInitialSplits(Split.newBuilder().setKey(key).build()); + return this; + } + + @InternalApi + public CreateTableRequest toProto(InstanceName instanceName) { + Preconditions.checkNotNull(instanceName); + return createTableRequest + .setParent(instanceName.toString()) + .setTable(tableRequest.build()) + .build(); + } + } + + /** + * Fluent wrapper for {@link ModifyColumnFamiliesRequest} + * + *

Allows for the following ColumnFamily modifications: + * + *

    + *
  • create family, optionally with {@link GCRule} + *
  • update existing family {@link GCRule} + *
  • drop an existing family + *
+ */ + public static final class ModifyFamilies { + private final ModifyColumnFamiliesRequest.Builder modFamilyRequest = + ModifyColumnFamiliesRequest.newBuilder(); + private final String tableId; + + /** + * Configures the tableId to execute the modifications + * + * @param tableId + */ + private ModifyFamilies(String tableId) { + Preconditions.checkNotNull(tableId); + this.tableId = tableId; + } + + /** + * Configures the name of the new ColumnFamily to be created + * + * @param familyId + * @return + */ + public ModifyFamilies addFamily(String familyId) { + return addFamily(familyId, GCRules.GCRULES.defaultRule()); + } + + /** + * Configures the name and GcRule of the new ColumnFamily to be created + * + * @param familyId + * @param gcRule + * @return + */ + public ModifyFamilies addFamily(String familyId, GCRule gcRule) { + Modification.Builder modification = Modification.newBuilder().setId(familyId); + Preconditions.checkNotNull(gcRule); + modification.setCreate(ColumnFamily.newBuilder().setGcRule(gcRule.toProto())); + modFamilyRequest.addModifications(modification.build()); + return this; + } + + /** + * Updates the GCRule of existing ColumnFamily + * + * @param familyId + * @param gcRule + * @return + */ + public ModifyFamilies updateFamily(String familyId, GCRule gcRule) { + Modification.Builder modification = Modification.newBuilder().setId(familyId); + Preconditions.checkNotNull(gcRule); + modification.setUpdate(ColumnFamily.newBuilder().setGcRule(gcRule.toProto())); + modFamilyRequest.addModifications(modification.build()); + return this; + } + + /** + * Drops the specified ColumnFamily + * + * @param familyId + * @return + */ + public ModifyFamilies dropFamily(String familyId) { + Modification.Builder modification = Modification.newBuilder().setId(familyId); + modification.setId(familyId).setDrop(true); + modFamilyRequest.addModifications(modification.build()); + return this; + } + + @InternalApi + public ModifyColumnFamiliesRequest toProto(InstanceName instanceName) { + Preconditions.checkNotNull(instanceName); + String tableName = + TableName.of(instanceName.getProject(), instanceName.getInstance(), tableId).toString(); + return modFamilyRequest.setName(tableName).build(); + } + } +} diff --git a/google-cloud-clients/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/models/TableAdminResponses.java b/google-cloud-clients/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/models/TableAdminResponses.java new file mode 100644 index 000000000000..82edc5184419 --- /dev/null +++ b/google-cloud-clients/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/models/TableAdminResponses.java @@ -0,0 +1,321 @@ +/* + * Copyright 2018 Google LLC + * + * 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 + * + * https://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.google.cloud.bigtable.admin.v2.models; + +import static com.google.cloud.bigtable.admin.v2.models.GCRules.GCRULES; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import org.threeten.bp.Duration; +import com.google.api.core.BetaApi; +import com.google.api.core.InternalApi; +import com.google.bigtable.admin.v2.CheckConsistencyRequest; +import com.google.bigtable.admin.v2.GcRule; +import com.google.bigtable.admin.v2.GcRule.RuleCase; +import com.google.bigtable.admin.v2.GenerateConsistencyTokenResponse; +import com.google.bigtable.admin.v2.Table.ClusterState.ReplicationState; +import com.google.bigtable.admin.v2.TableName; +import com.google.cloud.bigtable.admin.v2.TableAdminClient; +import com.google.cloud.bigtable.admin.v2.models.GCRules.GCRule; +import com.google.cloud.bigtable.admin.v2.models.GCRules.IntersectionRule; +import com.google.cloud.bigtable.admin.v2.models.GCRules.UnionRule; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.MoreObjects; +import com.google.common.base.Preconditions; + +/** Bigtable Table admin response wrappers */ +@BetaApi +public class TableAdminResponses { + private TableAdminResponses() {} + + /** + * Converts the protocol buffer table to a simpler Table model with only the required elements + * + * @param table - Protobuf table + * @return Table - Table response wrapper + */ + @InternalApi + public static Table convertTable(com.google.bigtable.admin.v2.Table table) { + return new Table(table); + } + + /** + * Converts the protocol buffer response to a simpler ConsistencyToken which can be passed back as + * is. + * + * @param tokenResponse - Protobuf ConsistencyTokenResponse + * @return ConsistencyToken - ConsistencyToken response wrapper + */ + @InternalApi + public static ConsistencyToken convertTokenResponse( + GenerateConsistencyTokenResponse tokenResponse) { + return new ConsistencyToken(tokenResponse); + } + + /** + * Converts the protocol buffer response to a simpler ClusterState model with only required + * elements + * + * @param clusterStatesMap - Protobuf clusterStatesMap + * @return Map + */ + @InternalApi + public static Map convertClusterStates( + Map clusterStatesMap) { + Map clusterStates = new HashMap<>(); + + for (Entry entry : + clusterStatesMap.entrySet()) { + clusterStates.put(entry.getKey(), new ClusterState(entry.getKey(), entry.getValue())); + } + return clusterStates; + } + + /** + * Converts the protocol buffer response to a simpler ColumnFamily model with only required + * elements + * + * @param columnFamiliesMap - Protobuf columnFamiliesMap + * @return Map + */ + @InternalApi + public static Map convertColumnFamilies( + Map columnFamiliesMap) { + Map columnFamilies = new HashMap<>(); + + for (Entry entry : + columnFamiliesMap.entrySet()) { + columnFamilies.put(entry.getKey(), new ColumnFamily(entry.getKey(), entry.getValue())); + } + return columnFamilies; + } + + /** Wrapper for {@link Table} protocol buffer object */ + public static final class Table { + private final TableName tableName; + private final Map clusterStates; + private final Map columnFamilies; + + private Table(com.google.bigtable.admin.v2.Table table) { + Preconditions.checkNotNull(table); + this.tableName = TableName.parse(table.getName()); + this.clusterStates = convertClusterStates(table.getClusterStatesMap()); + this.columnFamilies = convertColumnFamilies(table.getColumnFamiliesMap()); + } + + /** + * Gets the unique name of the table in the format: + * projects/{project}/instances/{instance}/tables/{tableId} + * + * @return TableName + */ + public TableName getTableName() { + return tableName; + } + + /** + * Returns state of the table by clusters in the instance as map of clusterId and {@link + * ClusterState} + * + * @return Map + */ + public Map getClusterStatesMap() { + return clusterStates; + } + + /** + * Returns a map of columfamilies in the table keyed by columnfamily and name + * + * @return Map + */ + public Map getColumnFamiliesMap() { + return columnFamilies; + } + + /** + * Returns state of the table by clusters in the instance as a Collection + * + * @return Collection + */ + public Collection getClusterStates() { + return clusterStates.values(); + } + + /** + * Returns all columnfamilies in the table as a Collection + * + * @return + */ + public Collection getColumnFamiles() { + return columnFamilies.values(); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("tableName", tableName) + .add("clusterStates", getClusterStates()) + .add("columnFamiles", getColumnFamiles()) + .toString(); + } + } + + /** Wrapper for {@link ClusterState} protocol buffer object */ + public static final class ClusterState { + private final String id; + private final ReplicationState replicationState; + + private ClusterState(String id, com.google.bigtable.admin.v2.Table.ClusterState clusterState) { + this.id = id; + replicationState = clusterState.getReplicationState(); + } + + /** + * Gets the cluster Id + * + * @return String + */ + public String getId() { + return id; + } + + /** + * Gets the ReplicationState of the table for this cluster + * + * @return ReplicationState + */ + public ReplicationState getReplicationState() { + return replicationState; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("is", id) + .add("replicationState", replicationState) + .toString(); + } + } + + /** Wrapper for {@link ColumnFamily} protocol buffer object */ + public static final class ColumnFamily { + private final String id; + private GCRule gCRule = GCRULES.defaultRule(); + + private ColumnFamily(String id, com.google.bigtable.admin.v2.ColumnFamily cf) { + Preconditions.checkNotNull(id); + Preconditions.checkNotNull(cf); + this.id = id; + + if (cf.getGcRule() != null) { + this.gCRule = convertGcRule(cf.getGcRule()); + } + } + + /** + * Gets the columnfamily name + * + * @return String + */ + public String getId() { + return id; + } + + /** + * Get's the GCRule configured for the columnfamily + * + * @return GCRule + */ + public GCRule getGCRule() { + return gCRule; + } + + /** + * Returns true if a GCRule has been configured for the family + * + * @return + */ + public boolean hasGcRule() { + return !RuleCase.RULE_NOT_SET.equals(gCRule.toProto().getRuleCase()); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this).add("id", id).add("gCRule", gCRule).toString(); + } + + private GCRule convertGcRule(GcRule source) { + switch (source.getRuleCase()) { + case MAX_AGE: + return GCRULES.maxAge( + Duration.ofSeconds(source.getMaxAge().getSeconds(), source.getMaxAge().getNanos())); + + case MAX_NUM_VERSIONS: + return GCRULES.maxVersions(source.getMaxNumVersions()); + + case INTERSECTION: + IntersectionRule intersection = GCRules.GCRULES.intersection(); + for (GcRule rule : source.getIntersection().getRulesList()) { + intersection.rule(convertGcRule(rule)); + } + return intersection; + + case UNION: + UnionRule union = GCRules.GCRULES.union(); + for (GcRule rule : source.getUnion().getRulesList()) { + union.rule(convertGcRule(rule)); + } + return union; + + default: + return GCRULES.defaultRule(); + } + } + } + + /** + * Wrapper for {@link GenerateConsistencyTokenResponse#getConsistencyToken()} + * + *

Cannot be created. They are obtained by invoking {@link + * TableAdminClient#generateConsistencyToken(String)} + */ + public static final class ConsistencyToken { + private final String token; + + private ConsistencyToken(GenerateConsistencyTokenResponse resp) { + this.token = resp.getConsistencyToken(); + } + + @InternalApi + public CheckConsistencyRequest toProto(String tableName) { + return CheckConsistencyRequest.newBuilder() + .setName(tableName) + .setConsistencyToken(token) + .build(); + } + + @VisibleForTesting + String getToken() { + return token; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this).add("token", token).toString(); + } + } +} diff --git a/google-cloud-clients/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/TableAdminClientTest.java b/google-cloud-clients/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/TableAdminClientTest.java new file mode 100644 index 000000000000..0c0b60b8f2dd --- /dev/null +++ b/google-cloud-clients/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/TableAdminClientTest.java @@ -0,0 +1,304 @@ +/* + * Copyright 2018 Google LLC + * + * 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 + * + * https://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.google.cloud.bigtable.admin.v2; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.any; +import java.util.List; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; +import com.google.api.core.ApiFuture; +import com.google.api.core.ApiFutures; +import com.google.api.gax.rpc.UnaryCallable; +import com.google.bigtable.admin.v2.CheckConsistencyRequest; +import com.google.bigtable.admin.v2.CheckConsistencyResponse; +import com.google.bigtable.admin.v2.CreateTableRequest; +import com.google.bigtable.admin.v2.DeleteTableRequest; +import com.google.bigtable.admin.v2.DropRowRangeRequest; +import com.google.bigtable.admin.v2.GenerateConsistencyTokenRequest; +import com.google.bigtable.admin.v2.GenerateConsistencyTokenResponse; +import com.google.bigtable.admin.v2.GetTableRequest; +import com.google.bigtable.admin.v2.InstanceName; +import com.google.bigtable.admin.v2.ListTablesRequest; +import com.google.bigtable.admin.v2.ListTablesResponse; +import com.google.bigtable.admin.v2.ModifyColumnFamiliesRequest; +import com.google.bigtable.admin.v2.Table; +import com.google.bigtable.admin.v2.TableName; +import com.google.cloud.bigtable.admin.v2.models.TableAdminRequests; +import com.google.cloud.bigtable.admin.v2.models.TableAdminRequests.CreateTable; +import com.google.cloud.bigtable.admin.v2.models.TableAdminRequests.ModifyFamilies; +import com.google.cloud.bigtable.admin.v2.models.TableAdminResponses.ConsistencyToken; +import com.google.cloud.bigtable.admin.v2.stub.BigtableTableAdminStub; +import com.google.protobuf.ByteString; +import com.google.protobuf.Empty; + +@RunWith(MockitoJUnitRunner.class) +public class TableAdminClientTest { + private TableAdminClient adminClient; + @Mock private BigtableTableAdminStub mockStub; + + @Mock private UnaryCallable mockCreateTableCallable; + @Mock private UnaryCallable mockModifyTableCallable; + @Mock private UnaryCallable mockDeleteTableCallable; + @Mock private UnaryCallable mockGetTableCallable; + @Mock private UnaryCallable mockListTableCallable; + @Mock private UnaryCallable mockDropRowRangeCallable; + + @Mock + private UnaryCallable + mockGenerateConsistencyTokenCallable; + + @Mock + private UnaryCallable + mockCheckConsistencyCallable; + + @Before + public void setUp() throws Exception { + adminClient = TableAdminClient.create(InstanceName.of("[PROJECT]", "[INSTANCE]"), mockStub); + + Mockito.when(mockStub.createTableCallable()).thenReturn(mockCreateTableCallable); + Mockito.when(mockStub.modifyColumnFamiliesCallable()).thenReturn(mockModifyTableCallable); + Mockito.when(mockStub.deleteTableCallable()).thenReturn(mockDeleteTableCallable); + Mockito.when(mockStub.getTableCallable()).thenReturn(mockGetTableCallable); + Mockito.when(mockStub.listTablesCallable()).thenReturn(mockListTableCallable); + Mockito.when(mockStub.dropRowRangeCallable()).thenReturn(mockDropRowRangeCallable); + Mockito.when(mockStub.generateConsistencyTokenCallable()) + .thenReturn(mockGenerateConsistencyTokenCallable); + Mockito.when(mockStub.checkConsistencyCallable()).thenReturn(mockCheckConsistencyCallable); + + Table table = Table.newBuilder().build(); + ApiFuture

futureTable = ApiFutures.immediateFuture(table); + Mockito.when(mockCreateTableCallable.call(any(CreateTableRequest.class))).thenReturn(table); + Mockito.when(mockCreateTableCallable.futureCall(any(CreateTableRequest.class))) + .thenReturn(futureTable); + Mockito.when(mockModifyTableCallable.call(any(ModifyColumnFamiliesRequest.class))) + .thenReturn(table); + Mockito.when(mockModifyTableCallable.futureCall(any(ModifyColumnFamiliesRequest.class))) + .thenReturn(futureTable); + Mockito.when(mockGetTableCallable.call(any(GetTableRequest.class))).thenReturn(table); + Mockito.when(mockGetTableCallable.futureCall(any(GetTableRequest.class))) + .thenReturn(futureTable); + } + + @Test + public void close() throws Exception { + adminClient.close(); + Mockito.verify(mockStub).close(); + } + + @Test + public void createTable() { + CreateTable createTableReq = TableAdminRequests.createTable("tableId"); + adminClient.createTable(createTableReq); + Mockito.verify(mockCreateTableCallable) + .call(createTableReq.toProto(adminClient.getInstanceName())); + } + + @Test + public void createTableAsync() { + CreateTable createTableReq = TableAdminRequests.createTable("tableId"); + adminClient.createTableAsync(createTableReq); + Mockito.verify(mockCreateTableCallable) + .futureCall(createTableReq.toProto(adminClient.getInstanceName())); + } + + @Test + public void modifyFamilies() { + ModifyFamilies modifyFamReq = TableAdminRequests.modifyFamilies("tableId"); + adminClient.modifyFamilies(modifyFamReq); + Mockito.verify(mockModifyTableCallable) + .call(modifyFamReq.toProto(adminClient.getInstanceName())); + } + + @Test + public void modifyFamiliesAsync() { + ModifyFamilies modifyFamReq = TableAdminRequests.modifyFamilies("tableId"); + adminClient.modifyFamiliesAsync(modifyFamReq); + Mockito.verify(mockModifyTableCallable) + .futureCall(modifyFamReq.toProto(adminClient.getInstanceName())); + } + + @Test + public void deleteTable() { + adminClient.deleteTable("tableId"); + Mockito.verify(mockDeleteTableCallable).call(adminClient.composeDeleteTableRequest("tableId")); + } + + @Test + public void deleteTableAsync() { + ApiFuture empty = ApiFutures.immediateFuture(Empty.newBuilder().build()); + Mockito.when(mockDeleteTableCallable.futureCall(any(DeleteTableRequest.class))) + .thenReturn(empty); + + adminClient.deleteTableAsync("tableId"); + Mockito.verify(mockDeleteTableCallable) + .futureCall(adminClient.composeDeleteTableRequest("tableId")); + } + + @Test + public void getTable() { + adminClient.getTable("tableId"); + Mockito.verify(mockGetTableCallable).call(adminClient.composeGetTableRequest("tableId")); + } + + @Test + public void getTableAsync() { + adminClient.getTableAsync("tableId"); + Mockito.verify(mockGetTableCallable).futureCall(adminClient.composeGetTableRequest("tableId")); + } + + @Test + public void listTables() { + ListTablesResponse listTablesResponse = ListTablesResponse.newBuilder().build(); + Mockito.when(mockListTableCallable.call(adminClient.composeListTableRequest())) + .thenReturn(listTablesResponse); + + adminClient.listTables(); + Mockito.verify(mockListTableCallable).call(adminClient.composeListTableRequest()); + } + + @Test + public void listTablesAsync() { + ApiFuture listTablesResponse = + ApiFutures.immediateFuture(ListTablesResponse.newBuilder().build()); + Mockito.when(mockListTableCallable.futureCall(adminClient.composeListTableRequest())) + .thenReturn(listTablesResponse); + + adminClient.listTablesAsync(); + Mockito.verify(mockListTableCallable).futureCall(adminClient.composeListTableRequest()); + } + + @Test + public void dropRowRange() { + adminClient.dropRowRange("tableId", "rowKeyPrefix"); + Mockito.verify(mockDropRowRangeCallable) + .call( + adminClient.composeDropRowRangeRequest( + "tableId", ByteString.copyFromUtf8("rowKeyPrefix"), false)); + } + + @Test + public void getDropRowRangeRequest() { + DropRowRangeRequest actual = + adminClient.composeDropRowRangeRequest( + "tableId", ByteString.copyFromUtf8("rowKeyPrefix"), false); + + DropRowRangeRequest expected = + DropRowRangeRequest.newBuilder() + .setName(adminClient.getTableName("tableId")) + .setRowKeyPrefix(ByteString.copyFromUtf8("rowKeyPrefix")) + .build(); + + assertThat(actual).isEqualTo(expected); + } + + @Test + public void getDropRowRangeRequestDropAllData() { + DropRowRangeRequest actual = adminClient.composeDropRowRangeRequest("tableId", null, true); + + DropRowRangeRequest expected = + DropRowRangeRequest.newBuilder() + .setName(adminClient.getTableName("tableId")) + .setDeleteAllDataFromTable(true) + .build(); + + assertThat(actual).isEqualTo(expected); + } + + @Test + public void dropRowRangeAsync() { + ApiFuture empty = ApiFutures.immediateFuture(Empty.newBuilder().build()); + Mockito.when(mockDropRowRangeCallable.futureCall(any(DropRowRangeRequest.class))) + .thenReturn(empty); + + adminClient.dropRowRangeAsync("tableId", "rowKeyPrefix"); + Mockito.verify(mockDropRowRangeCallable) + .futureCall( + adminClient.composeDropRowRangeRequest( + "tableId", ByteString.copyFromUtf8("rowKeyPrefix"), false)); + } + + @Test + public void generateAndCheckConsistency() { + GenerateConsistencyTokenResponse genResp = + GenerateConsistencyTokenResponse.newBuilder().build(); + Mockito.when( + mockGenerateConsistencyTokenCallable.call( + adminClient.composeGenerateConsistencyTokenRequest("tableId"))) + .thenReturn(genResp); + + ConsistencyToken consistencyToken = adminClient.generateConsistencyToken("tableId"); + Mockito.verify(mockGenerateConsistencyTokenCallable) + .call(adminClient.composeGenerateConsistencyTokenRequest("tableId")); + + ArgumentCaptor requestCaptor = + ArgumentCaptor.forClass(CheckConsistencyRequest.class); + CheckConsistencyResponse consistencyResp = CheckConsistencyResponse.newBuilder().build(); + Mockito.when(mockCheckConsistencyCallable.call(any(CheckConsistencyRequest.class))) + .thenReturn(consistencyResp); + + adminClient.isConsistent("tableId", consistencyToken); + Mockito.verify(mockCheckConsistencyCallable).call(requestCaptor.capture()); + } + + @Test + public void generateAndCheckConsistencyAsync() throws Exception { + ApiFuture genResp = + ApiFutures.immediateFuture(GenerateConsistencyTokenResponse.newBuilder().build()); + Mockito.when( + mockGenerateConsistencyTokenCallable.futureCall( + adminClient.composeGenerateConsistencyTokenRequest("tableId"))) + .thenReturn(genResp); + + ApiFuture consistencyTokenFuture = + adminClient.generateConsistencyTokenAsync("tableId"); + Mockito.verify(mockGenerateConsistencyTokenCallable) + .futureCall(adminClient.composeGenerateConsistencyTokenRequest("tableId")); + + ArgumentCaptor requestCaptor = + ArgumentCaptor.forClass(CheckConsistencyRequest.class); + ApiFuture consistencyResp = + ApiFutures.immediateFuture(CheckConsistencyResponse.newBuilder().build()); + Mockito.when(mockCheckConsistencyCallable.futureCall(any(CheckConsistencyRequest.class))) + .thenReturn(consistencyResp); + + adminClient.isConsistentAsync("tableId", consistencyTokenFuture.get()); + Mockito.verify(mockCheckConsistencyCallable).futureCall(requestCaptor.capture()); + } + + @Test + public void convertToTableNames() { + ListTablesResponse listTablesResponse = + ListTablesResponse.newBuilder() + .addTables(Table.newBuilder().setName("projects/p/instances/i/tables/t1")) + .addTables(Table.newBuilder().setName("projects/p/instances/i/tables/t2")) + .build(); + + List tableNames = TableAdminClient.convertToTableNames(listTablesResponse); + assertEquals(2, tableNames.size()); + assertEquals("projects/p/instances/i/tables/t1", tableNames.get(0).toString()); + assertEquals("projects/p/instances/i/tables/t2", tableNames.get(1).toString()); + + listTablesResponse = ListTablesResponse.newBuilder().build(); + assertEquals(0, TableAdminClient.convertToTableNames(listTablesResponse).size()); + } +} diff --git a/google-cloud-clients/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/it/TableAdminClientIT.java b/google-cloud-clients/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/it/TableAdminClientIT.java new file mode 100644 index 000000000000..7cd8bff9854e --- /dev/null +++ b/google-cloud-clients/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/it/TableAdminClientIT.java @@ -0,0 +1,222 @@ +/* + * Copyright 2018 Google LLC + * + * 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 + * + * https://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.google.cloud.bigtable.admin.v2.it; + +import static com.google.cloud.bigtable.admin.v2.models.GCRules.GCRULES; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import java.io.IOException; +import java.util.List; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.threeten.bp.Duration; +import com.google.bigtable.admin.v2.InstanceName; +import com.google.bigtable.admin.v2.TableName; +import com.google.cloud.bigtable.admin.v2.TableAdminClient; +import com.google.cloud.bigtable.admin.v2.models.GCRules.DurationRule; +import com.google.cloud.bigtable.admin.v2.models.GCRules.IntersectionRule; +import com.google.cloud.bigtable.admin.v2.models.GCRules.UnionRule; +import com.google.cloud.bigtable.admin.v2.models.GCRules.VersionRule; +import com.google.cloud.bigtable.admin.v2.models.TableAdminRequests; +import com.google.cloud.bigtable.admin.v2.models.TableAdminRequests.CreateTable; +import com.google.cloud.bigtable.admin.v2.models.TableAdminRequests.ModifyFamilies; +import com.google.cloud.bigtable.admin.v2.models.TableAdminResponses.ConsistencyToken; +import com.google.cloud.bigtable.admin.v2.models.TableAdminResponses.Table; +import com.google.protobuf.ByteString; + +public class TableAdminClientIT { + static TableAdminClient tableAdmin; + + @BeforeClass + public static void createClient() throws IOException { + tableAdmin = TableAdminClient.create(InstanceName.of("sduskis-hello-shakespear", "beam-test")); + } + + @AfterClass + public static void closeClient() throws Exception { + tableAdmin.close(); + } + + @Test + public void createTable() throws Exception { + String tableId = "adminCreateTest"; + CreateTable createTableReq = + TableAdminRequests.createTable(tableId) + .addFamily("cf1") + .addFamily("cf2", GCRULES.maxVersions(10)) + .addSplit(ByteString.copyFromUtf8("b")) + .addSplit(ByteString.copyFromUtf8("q")); + + try { + Table tableResponse = tableAdmin.createTable(createTableReq); + assertNotNull(tableResponse); + assertEquals(tableId, tableResponse.getTableName().getTable()); + assertEquals(2, tableResponse.getColumnFamiles().size()); + assertFalse(tableResponse.getColumnFamiliesMap().get("cf1").hasGcRule()); + assertTrue(tableResponse.getColumnFamiliesMap().get("cf2").hasGcRule()); + assertEquals( + 10, + ((VersionRule) tableResponse.getColumnFamiliesMap().get("cf2").getGCRule()) + .getMaxVersions()); + } finally { + tableAdmin.deleteTable(tableId); + } + } + + @Test + public void modifyFamilies() { + String tableId = "adminModifyFamTest"; + ModifyFamilies modifyFamiliesReq = TableAdminRequests.modifyFamilies(tableId); + Duration.ofSeconds(1000); + modifyFamiliesReq + .addFamily("mf1") + .addFamily("mf2", GCRULES.maxAge(Duration.ofSeconds(1000, 20000))) + .updateFamily( + "mf1", + GCRULES + .union() + .rule(GCRULES.maxAge(Duration.ofSeconds(100))) + .rule(GCRULES.maxVersions(1))) + .addFamily( + "mf3", + GCRULES + .intersection() + .rule(GCRULES.maxAge(Duration.ofSeconds(2000))) + .rule(GCRULES.maxVersions(10))) + .addFamily("mf4", GCRULES.intersection().rule(GCRULES.maxAge(Duration.ofSeconds(360)))) + .addFamily("mf5") + .addFamily("mf6") + .dropFamily("mf5") + .dropFamily("mf6") + .addFamily("mf7"); + + try { + tableAdmin.createTable(TableAdminRequests.createTable(tableId)); + Table tableResponse = tableAdmin.modifyFamilies(modifyFamiliesReq); + assertEquals(5, tableResponse.getColumnFamiles().size()); + assertNotNull(tableResponse.getColumnFamiliesMap().get("mf1")); + assertNotNull(tableResponse.getColumnFamiliesMap().get("mf2")); + assertEquals( + 2, + ((UnionRule) tableResponse.getColumnFamiliesMap().get("mf1").getGCRule()) + .getRulesList() + .size()); + assertEquals( + 1000, + ((DurationRule) tableResponse.getColumnFamiliesMap().get("mf2").getGCRule()) + .getMaxAge() + .getSeconds()); + assertEquals( + 20000, + ((DurationRule) tableResponse.getColumnFamiliesMap().get("mf2").getGCRule()) + .getMaxAge() + .getNano()); + assertEquals( + 2, + ((IntersectionRule) tableResponse.getColumnFamiliesMap().get("mf3").getGCRule()) + .getRulesList() + .size()); + assertEquals( + 360, + ((DurationRule) tableResponse.getColumnFamiliesMap().get("mf4").getGCRule()) + .getMaxAge() + .getSeconds()); + assertNotNull(tableResponse.getColumnFamiliesMap().get("mf7")); + } finally { + tableAdmin.deleteTable(tableId); + } + } + + @Test + public void deleteTable() { + String tableId = "adminDeleteTest"; + tableAdmin.createTable(TableAdminRequests.createTable(tableId)); + tableAdmin.deleteTable(tableId); + } + + @Test + public void getTable() { + String tableId = "adminGetTest"; + + try { + tableAdmin.createTable(TableAdminRequests.createTable(tableId)); + Table tableResponse = tableAdmin.getTable(tableId); + assertNotNull(tableResponse); + assertEquals(tableId, tableResponse.getTableName().getTable()); + } finally { + tableAdmin.deleteTable(tableId); + } + } + + @Test + public void listTables() { + String tableId = "adminListTest"; + + try { + tableAdmin.createTable(TableAdminRequests.createTable(tableId)); + List tables = tableAdmin.listTables(); + assertNotNull(tables); + assertEquals(1, tables.size()); + } finally { + tableAdmin.deleteTable(tableId); + } + } + + @Test + public void listTablesAsync() throws Exception { + String tableId = "adminListTest"; + + try { + tableAdmin.createTable(TableAdminRequests.createTable(tableId)); + List tables = tableAdmin.listTablesAsync().get(); + assertNotNull(tables); + assertEquals(1, tables.size()); + } finally { + tableAdmin.deleteTable(tableId); + } + } + + @Test + public void dropRowRange() { + String tableId = "adminDropRowrangeTest"; + + try { + tableAdmin.createTable(TableAdminRequests.createTable(tableId)); + tableAdmin.dropRowRange(tableId, "rowPrefix"); + tableAdmin.dropAllRows(tableId); + } finally { + tableAdmin.deleteTable(tableId); + } + } + + @Test + public void checkConsistency() { + String tableId = "adminConsistencyTest"; + + try { + tableAdmin.createTable(TableAdminRequests.createTable(tableId)); + ConsistencyToken consistencyToken = tableAdmin.generateConsistencyToken(tableId); + assertNotNull(consistencyToken); + boolean consistent = tableAdmin.isConsistent(tableId, consistencyToken); + assertTrue(consistent); + } finally { + tableAdmin.deleteTable(tableId); + } + } +} diff --git a/google-cloud-clients/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/models/GCRulesTest.java b/google-cloud-clients/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/models/GCRulesTest.java new file mode 100644 index 000000000000..690128dfd816 --- /dev/null +++ b/google-cloud-clients/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/models/GCRulesTest.java @@ -0,0 +1,294 @@ +/* + * Copyright 2018 Google LLC + * + * 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 + * + * https://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.google.cloud.bigtable.admin.v2.models; + +import static com.google.cloud.bigtable.admin.v2.models.GCRules.GCRULES; +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import java.util.concurrent.TimeUnit; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.threeten.bp.Duration; +import com.google.bigtable.admin.v2.GcRule; +import com.google.bigtable.admin.v2.GcRule.Intersection; +import com.google.bigtable.admin.v2.GcRule.Union; +import com.google.cloud.bigtable.admin.v2.models.GCRules.DurationRule; +import com.google.cloud.bigtable.admin.v2.models.GCRules.IntersectionRule; +import com.google.cloud.bigtable.admin.v2.models.GCRules.UnionRule; +import com.google.cloud.bigtable.admin.v2.models.GCRules.VersionRule; + +@RunWith(JUnit4.class) +public class GCRulesTest { + + @Test + public void duration() { + DurationRule actual = GCRULES.maxAge(Duration.ofSeconds(61, 9)); + GcRule expected = buildAgeRule(61, 9); + assertNotNull(actual.getMaxAge()); + assertThat(actual.toProto()).isEqualTo(expected); + } + + @Test + public void durationSeconds() { + GcRule actual = GCRULES.maxAge(Duration.ofSeconds(1)).toProto(); + GcRule expected = buildAgeRule(1, 0); + assertThat(actual).isEqualTo(expected); + } + + @Test + public void durationNanos() { + GcRule actual = GCRULES.maxAge(Duration.ofNanos(11)).toProto(); + GcRule expected = buildAgeRule(0, 11); + assertThat(actual).isEqualTo(expected); + } + + @Test + public void durationTimeUnitSeconds() { + GcRule actual = GCRULES.maxAge(1, TimeUnit.DAYS).toProto(); + GcRule expected = buildAgeRule(3600 * 24, 0); + assertThat(actual).isEqualTo(expected); + } + + @Test + public void durationTimeUnitMinutes() { + GcRule actual = GCRULES.maxAge(1, TimeUnit.MINUTES).toProto(); + GcRule expected = buildAgeRule(60, 0); + assertThat(actual).isEqualTo(expected); + } + + @Test + public void durationTimeUnitNanos() { + GcRule actual = GCRULES.maxAge(1, TimeUnit.NANOSECONDS).toProto(); + GcRule expected = buildAgeRule(0, 1); + assertThat(actual).isEqualTo(expected); + } + + @Test + public void durationTimeUnitNegative() { + GcRule actual = GCRULES.maxAge(-1, TimeUnit.MINUTES).toProto(); + GcRule expected = buildAgeRule(-60, 0); + assertThat(actual).isEqualTo(expected); + } + + @Test + public void versions() { + VersionRule actual = GCRULES.maxVersions(10); + GcRule expected = buildVersionsRule(10); + assertNotNull(actual.getMaxVersions()); + assertThat(actual.toProto()).isEqualTo(expected); + } + + @Test + public void unionEmpty() { + GcRule actual = GCRULES.union().toProto(); + GcRule expected = GcRule.newBuilder().build(); + assertThat(actual).isEqualTo(expected); + } + + @Test + public void unionOne() { + GcRule actual = GCRULES.union().rule(GCRULES.maxVersions(1)).toProto(); + GcRule expected = buildVersionsRule(1); + assertThat(actual).isEqualTo(expected); + } + + @Test + public void unionTwo() { + GcRule actual = + GCRULES + .union() + .rule(GCRULES.maxVersions(1)) + .rule(GCRULES.maxAge(Duration.ofSeconds(1))) + .toProto(); + + GcRule expected = + GcRule.newBuilder() + .setUnion( + Union.newBuilder().addRules(buildVersionsRule(1)).addRules(buildAgeRule(1, 0))) + .build(); + + assertThat(actual).isEqualTo(expected); + } + + @Test + public void unionThree() { + GcRule actual = + GCRULES + .union() + .rule(GCRULES.maxVersions(1)) + .rule(GCRULES.maxAge(Duration.ofSeconds(1))) + .rule(GCRULES.maxAge(Duration.ofNanos(1))) + .toProto(); + + GcRule expected = + GcRule.newBuilder() + .setUnion( + Union.newBuilder() + .addRules(buildVersionsRule(1)) + .addRules(buildAgeRule(1, 0)) + .addRules(buildAgeRule(0, 1))) + .build(); + + assertThat(actual).isEqualTo(expected); + } + + @Test + public void intersectionEmpty() { + GcRule actual = GCRULES.intersection().toProto(); + GcRule expected = GcRule.newBuilder().build(); + assertThat(actual).isEqualTo(expected); + } + + @Test + public void intersectionOne() { + GcRule actual = GCRULES.intersection().rule(GCRULES.maxVersions(1)).toProto(); + GcRule expected = buildVersionsRule(1); + assertThat(actual).isEqualTo(expected); + } + + @Test + public void intersectionTwo() { + GcRule actual = + GCRULES + .intersection() + .rule(GCRULES.maxVersions(1)) + .rule(GCRULES.maxAge(Duration.ofSeconds(1))) + .toProto(); + + GcRule expected = + GcRule.newBuilder() + .setIntersection( + Intersection.newBuilder() + .addRules(buildVersionsRule(1)) + .addRules(buildAgeRule(1, 0))) + .build(); + + assertThat(actual).isEqualTo(expected); + } + + @Test + public void intersectionThree() { + GcRule actual = + GCRULES + .intersection() + .rule(GCRULES.maxVersions(1)) + .rule(GCRULES.maxAge(Duration.ofSeconds(1))) + .rule(GCRULES.maxAge(Duration.ofNanos(1))) + .toProto(); + + GcRule expected = + GcRule.newBuilder() + .setIntersection( + Intersection.newBuilder() + .addRules(buildVersionsRule(1)) + .addRules(buildAgeRule(1, 0)) + .addRules(buildAgeRule(0, 1))) + .build(); + + assertThat(actual).isEqualTo(expected); + } + + @Test + public void unionOfIntersections() { + UnionRule actual = + GCRULES + .union() + .rule( + GCRULES + .intersection() + .rule(GCRULES.maxVersions(1)) + .rule(GCRULES.maxAge(Duration.ofSeconds(1)))) + .rule( + GCRULES + .intersection() + .rule(GCRULES.maxVersions(1)) + .rule(GCRULES.maxAge(Duration.ofSeconds(1)))); + + GcRule expected = + GcRule.newBuilder() + .setUnion( + Union.newBuilder() + .addRules( + GcRule.newBuilder() + .setIntersection( + Intersection.newBuilder() + .addRules(buildVersionsRule(1)) + .addRules(buildAgeRule(1, 0)))) + .addRules( + GcRule.newBuilder() + .setIntersection( + Intersection.newBuilder() + .addRules(buildVersionsRule(1)) + .addRules(buildAgeRule(1, 0))))) + .build(); + + assertEquals(2, actual.getRulesList().size()); + assertThat(actual.toProto()).isEqualTo(expected); + } + + @Test + public void intersectionOfUnions() { + IntersectionRule actual = + GCRULES + .intersection() + .rule( + GCRULES + .union() + .rule(GCRULES.maxVersions(1)) + .rule(GCRULES.maxAge(Duration.ofSeconds(1)))) + .rule( + GCRULES + .union() + .rule(GCRULES.maxVersions(1)) + .rule(GCRULES.maxAge(Duration.ofSeconds(1)))); + + GcRule expected = + GcRule.newBuilder() + .setIntersection( + Intersection.newBuilder() + .addRules( + GcRule.newBuilder() + .setUnion( + Union.newBuilder() + .addRules(buildVersionsRule(1)) + .addRules(buildAgeRule(1, 0)))) + .addRules( + GcRule.newBuilder() + .setUnion( + Union.newBuilder() + .addRules(buildVersionsRule(1)) + .addRules(buildAgeRule(1, 0))))) + .build(); + + assertEquals(2, actual.getRulesList().size()); + assertThat(actual.toProto()).isEqualTo(expected); + } + + public static GcRule buildAgeRule(long seconds, int nanos) { + com.google.protobuf.Duration.Builder duartionBuilder = + com.google.protobuf.Duration.newBuilder(); + duartionBuilder.setSeconds(seconds); + duartionBuilder.setNanos(nanos); + + return GcRule.newBuilder().setMaxAge(duartionBuilder).build(); + } + + public static GcRule buildVersionsRule(int maxVer) { + return GcRule.newBuilder().setMaxNumVersions(maxVer).build(); + } +} diff --git a/google-cloud-clients/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/models/TableAdminRequestsTest.java b/google-cloud-clients/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/models/TableAdminRequestsTest.java new file mode 100644 index 000000000000..d33940e18f0a --- /dev/null +++ b/google-cloud-clients/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/models/TableAdminRequestsTest.java @@ -0,0 +1,124 @@ +/* + * Copyright 2018 Google LLC + * + * 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 + * + * https://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.google.cloud.bigtable.admin.v2.models; + +import static com.google.common.truth.Truth.assertThat; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import com.google.bigtable.admin.v2.ColumnFamily; +import com.google.bigtable.admin.v2.CreateTableRequest; +import com.google.bigtable.admin.v2.GcRule; +import com.google.bigtable.admin.v2.Table; +import com.google.bigtable.admin.v2.TableName; +import com.google.bigtable.admin.v2.CreateTableRequest.Split; +import com.google.bigtable.admin.v2.InstanceName; +import com.google.bigtable.admin.v2.ModifyColumnFamiliesRequest; +import com.google.bigtable.admin.v2.ModifyColumnFamiliesRequest.Modification; +import com.google.protobuf.ByteString; + +@RunWith(JUnit4.class) +public class TableAdminRequestsTest { + private final InstanceName instanceName = InstanceName.of("project", "instance"); + + @Test + public void createTable() { + CreateTableRequest actual = + TableAdminRequests.createTable("tableId") + .addFamily("cf1") + .addFamily("cf2", GCRules.GCRULES.maxVersions(1)) + .addSplit(ByteString.copyFromUtf8("c")) + .toProto(instanceName); + + CreateTableRequest expected = + CreateTableRequest.newBuilder() + .setTableId("tableId") + .setParent(InstanceName.of("project", "instance").toString()) + .addInitialSplits(Split.newBuilder().setKey(ByteString.copyFromUtf8("c"))) + .setTable( + Table.newBuilder() + .putColumnFamilies("cf1", ColumnFamily.newBuilder().build()) + .putColumnFamilies( + "cf2", + ColumnFamily.newBuilder() + .setGcRule(GCRules.GCRULES.maxVersions(1).toProto()) + .build())) + .build(); + + assertThat(actual).isEqualTo(expected); + } + + @Test(expected = NullPointerException.class) + public void createTableRequiredTableId() { + TableAdminRequests.createTable(null).toProto(instanceName); + } + + @Test(expected = NullPointerException.class) + public void createTableRequiredParent() { + TableAdminRequests.createTable("tableId").toProto(null); + } + + @Test + public void modifyFamilies() { + ModifyColumnFamiliesRequest actual = + TableAdminRequests.modifyFamilies("tableId") + .addFamily("cf1") + .addFamily("cf2", GCRules.GCRULES.maxVersions(1)) + .addFamily("cf3") + .updateFamily("cf1", GCRules.GCRULES.maxVersions(5)) + .dropFamily("cf3") + .toProto(instanceName); + + ModifyColumnFamiliesRequest expected = + ModifyColumnFamiliesRequest.newBuilder() + .setName( + TableName.of(instanceName.getProject(), instanceName.getInstance(), "tableId") + .toString()) + .addModifications( + Modification.newBuilder() + .setId("cf1") + .setCreate(ColumnFamily.newBuilder().setGcRule(GcRule.getDefaultInstance()))) + .addModifications( + Modification.newBuilder() + .setId("cf2") + .setCreate( + ColumnFamily.newBuilder() + .setGcRule(GCRules.GCRULES.maxVersions(1).toProto()))) + .addModifications( + Modification.newBuilder() + .setId("cf3") + .setCreate(ColumnFamily.newBuilder().setGcRule(GcRule.getDefaultInstance()))) + .addModifications( + Modification.newBuilder() + .setId("cf1") + .setUpdate( + ColumnFamily.newBuilder() + .setGcRule(GCRules.GCRULES.maxVersions(5).toProto()))) + .addModifications(Modification.newBuilder().setId("cf3").setDrop(true)) + .build(); + assertThat(actual).isEqualTo(expected); + } + + @Test(expected = NullPointerException.class) + public void modifyFamiliesRequiredTableId() { + TableAdminRequests.modifyFamilies(null).toProto(instanceName); + } + + @Test(expected = NullPointerException.class) + public void modifyFamiliesRequiredParent() { + TableAdminRequests.modifyFamilies("tableId").toProto(null); + } +} diff --git a/google-cloud-clients/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/models/TableAdminResponsesTest.java b/google-cloud-clients/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/models/TableAdminResponsesTest.java new file mode 100644 index 000000000000..3b759e2f2954 --- /dev/null +++ b/google-cloud-clients/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/models/TableAdminResponsesTest.java @@ -0,0 +1,229 @@ +/* + * Copyright 2018 Google LLC + * + * 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 + * + * https://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.google.cloud.bigtable.admin.v2.models; + +import static org.junit.Assert.*; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.threeten.bp.Duration; +import com.google.bigtable.admin.v2.ColumnFamily; +import com.google.bigtable.admin.v2.GcRule; +import com.google.bigtable.admin.v2.Table.ClusterState; +import com.google.bigtable.admin.v2.Table.ClusterState.ReplicationState; +import com.google.bigtable.admin.v2.Table.TimestampGranularity; +import com.google.bigtable.admin.v2.TableName; +import com.google.cloud.bigtable.admin.v2.models.GCRules.DurationRule; +import com.google.cloud.bigtable.admin.v2.models.GCRules.IntersectionRule; +import com.google.cloud.bigtable.admin.v2.models.GCRules.UnionRule; +import com.google.cloud.bigtable.admin.v2.models.GCRules.VersionRule; +import com.google.cloud.bigtable.admin.v2.models.TableAdminResponses.ConsistencyToken; +import com.google.cloud.bigtable.admin.v2.models.TableAdminResponses.Table; +import com.google.bigtable.admin.v2.GcRule.Intersection; +import com.google.bigtable.admin.v2.GcRule.Union; +import com.google.bigtable.admin.v2.GenerateConsistencyTokenResponse; +import static com.google.cloud.bigtable.admin.v2.models.GCRules.GCRULES; +import static com.google.common.truth.Truth.assertThat; + +@RunWith(JUnit4.class) +public class TableAdminResponsesTest { + + @Test + public void convertTable() { + TableName testName = TableName.of("p", "i", "testTable"); + com.google.bigtable.admin.v2.Table table = + com.google.bigtable.admin.v2.Table.newBuilder() + .setName(testName.toString()) + .setGranularity(TimestampGranularity.MILLIS) + .putClusterStates( + "test", + ClusterState.newBuilder().setReplicationState(ReplicationState.READY).build()) + .putClusterStates( + "prod", + ClusterState.newBuilder() + .setReplicationState(ReplicationState.INITIALIZING) + .build()) + .putColumnFamilies("cf1", ColumnFamily.newBuilder().build()) + .putColumnFamilies( + "cf2", + ColumnFamily.newBuilder() + .setGcRule(GcRule.newBuilder().setMaxNumVersions(1)) + .build()) + .putColumnFamilies( + "cf3", + ColumnFamily.newBuilder() + .setGcRule( + GcRule.newBuilder() + .setMaxAge( + com.google.protobuf.Duration.newBuilder() + .setSeconds(1) + .setNanos(99))) + .build()) + .build(); + + Table tableResponse = TableAdminResponses.convertTable(table); + assertNotNull(tableResponse); + assertEquals(testName, tableResponse.getTableName()); + assertEquals(2, tableResponse.getClusterStates().size()); + assertEquals( + ReplicationState.READY, + tableResponse.getClusterStatesMap().get("test").getReplicationState()); + assertEquals( + ReplicationState.INITIALIZING, + tableResponse.getClusterStatesMap().get("prod").getReplicationState()); + assertEquals(3, tableResponse.getColumnFamiles().size()); + assertNotNull("cf1", tableResponse.getColumnFamiliesMap().get("cf1").getId()); + assertFalse(tableResponse.getColumnFamiliesMap().get("cf1").hasGcRule()); + + assertThat(GCRULES.defaultRule().toProto()) + .isEqualTo(tableResponse.getColumnFamiliesMap().get("cf1").getGCRule().toProto()); + assertThat(GCRULES.maxVersions(1).toProto()) + .isEqualTo(tableResponse.getColumnFamiliesMap().get("cf2").getGCRule().toProto()); + assertThat(GCRULES.maxAge(Duration.ofSeconds(1, 99)).toProto()) + .isEqualTo(tableResponse.getColumnFamiliesMap().get("cf3").getGCRule().toProto()); + } + + @Test + public void convertTableUnionOfIntersections() { + GcRule expected = + GcRule.newBuilder() + .setUnion( + Union.newBuilder() + .addRules( + GcRule.newBuilder() + .setIntersection( + Intersection.newBuilder() + .addRules(GCRulesTest.buildVersionsRule(1)) + .addRules(GCRulesTest.buildAgeRule(1, 0)))) + .addRules( + GcRule.newBuilder() + .setIntersection( + Intersection.newBuilder() + .addRules(GCRulesTest.buildVersionsRule(1)) + .addRules(GCRulesTest.buildAgeRule(1, 0))))) + .build(); + + GcRule actual = + GCRULES + .union() + .rule( + GCRULES + .intersection() + .rule(GCRULES.maxVersions(1)) + .rule(GCRULES.maxAge(Duration.ofSeconds(1)))) + .rule( + GCRULES + .intersection() + .rule(GCRULES.maxVersions(1)) + .rule(GCRULES.maxAge(Duration.ofSeconds(1)))) + .toProto(); + + com.google.bigtable.admin.v2.Table table = + com.google.bigtable.admin.v2.Table.newBuilder() + .putColumnFamilies("cf3", ColumnFamily.newBuilder().setGcRule(expected).build()) + .build(); + + Table tableResponse = TableAdminResponses.convertTable(table); + assertThat(actual) + .isEqualTo(tableResponse.getColumnFamiliesMap().get("cf3").getGCRule().toProto()); + assertTrue(tableResponse.getColumnFamiliesMap().get("cf3").hasGcRule()); + + UnionRule parentUnion = + ((UnionRule) tableResponse.getColumnFamiliesMap().get("cf3").getGCRule()); + assertEquals(2, parentUnion.getRulesList().size()); + + IntersectionRule intersectionRule = ((IntersectionRule) parentUnion.getRulesList().get(0)); + assertEquals(2, intersectionRule.getRulesList().size()); + assertEquals(1, ((VersionRule) intersectionRule.getRulesList().get(0)).getMaxVersions()); + assertEquals( + Duration.ofSeconds(1, 0), + ((DurationRule) intersectionRule.getRulesList().get(1)).getMaxAge()); + + intersectionRule = ((IntersectionRule) parentUnion.getRulesList().get(1)); + assertEquals(2, intersectionRule.getRulesList().size()); + assertEquals(1, ((VersionRule) intersectionRule.getRulesList().get(0)).getMaxVersions()); + assertEquals( + Duration.ofSeconds(1, 0), + ((DurationRule) intersectionRule.getRulesList().get(1)).getMaxAge()); + } + + @Test + public void convertTableIntersectionOfUnions() { + GcRule actual = + GcRule.newBuilder() + .setIntersection( + Intersection.newBuilder() + .addRules( + GcRule.newBuilder() + .setUnion( + Union.newBuilder() + .addRules(GCRulesTest.buildVersionsRule(1)) + .addRules(GCRulesTest.buildAgeRule(1, 0)))) + .addRules( + GcRule.newBuilder() + .setUnion( + Union.newBuilder() + .addRules(GCRulesTest.buildVersionsRule(1)) + .addRules(GCRulesTest.buildAgeRule(1, 0))))) + .build(); + + GcRule expected = + GCRULES + .intersection() + .rule( + GCRULES + .union() + .rule(GCRULES.maxVersions(1)) + .rule(GCRULES.maxAge(Duration.ofSeconds(1)))) + .rule( + GCRULES + .union() + .rule(GCRULES.maxVersions(1)) + .rule(GCRULES.maxAge(Duration.ofSeconds(1)))) + .toProto(); + + com.google.bigtable.admin.v2.Table table = + com.google.bigtable.admin.v2.Table.newBuilder() + .putColumnFamilies("cf3", ColumnFamily.newBuilder().setGcRule(expected).build()) + .build(); + + Table tableResponse = TableAdminResponses.convertTable(table); + assertThat(actual) + .isEqualTo(tableResponse.getColumnFamiliesMap().get("cf3").getGCRule().toProto()); + } + + @Test + public void convertTableEmpty() { + Table tableResponse = + TableAdminResponses.convertTable(com.google.bigtable.admin.v2.Table.newBuilder().build()); + + assertNotNull(tableResponse); + assertEquals(0, tableResponse.getClusterStates().size()); + assertEquals(0, tableResponse.getColumnFamiles().size()); + } + + @Test + public void convertTokenResponse() { + ConsistencyToken tokenResponse = + TableAdminResponses.convertTokenResponse( + GenerateConsistencyTokenResponse.newBuilder() + .setConsistencyToken("87282hgwd8yg") + .build()); + + assertNotNull(tokenResponse); + assertEquals("87282hgwd8yg", tokenResponse.getToken()); + } +}