Repository: GoogleCloudPlatform/cloud-bigtable-client
Pull request #2040 (2019-01-07 13:55:43)

Admin interface as GAX admin client
## What changes it contains:

Adding interface for admin method. Considered all operations present in [grpc.BigtableTableAdminClient](https://github.com/GoogleCloudPlatform/cloud-bigtable-client/blob/master/bigtable-client-core-parent/bigtable-client-core/src/main/java/com/google/cloud/bigtable/grpc/BigtableTableAdminClient.java) to update to equivalent [v2.BigtableTableAdminClient](https://github.com/rahulKQL/google-cloud-java/blob/master/google-cloud-clients/google-cloud-bigtable-admin/src/main/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClient.java#L95).
 
 Would consider two step migration to [v2.BigtableTableAdminClient](https://github.com/rahulKQL/google-cloud-java/blob/master/google-cloud-clients/google-cloud-bigtable-admin/src/main/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClient.java#L95):
  1. Update all implementation to adapt to gax models.
  2. Update async methods to adapt to ApiFuture.
  


Patch:
diff --git a/bigtable-client-core-parent/bigtable-client-core/src/main/java/com/google/cloud/bigtable/core/IBigtableTableAdminClient.java b/bigtable-client-core-parent/bigtable-client-core/src/main/java/com/google/cloud/bigtable/core/IBigtableTableAdminClient.java
new file mode 100644
index 000000000..36afb558f
--- /dev/null
+++ b/bigtable-client-core-parent/bigtable-client-core/src/main/java/com/google/cloud/bigtable/core/IBigtableTableAdminClient.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2019 Google LLC. All Rights Reserved.
+ *
+ * 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.google.cloud.bigtable.core;
+
+import com.google.cloud.bigtable.admin.v2.models.CreateTableRequest;
+import com.google.cloud.bigtable.admin.v2.models.ModifyColumnFamiliesRequest;
+import com.google.cloud.bigtable.admin.v2.models.Table;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.List;
+
+/**
+ * Interface to wrap {@link com.google.cloud.bigtable.grpc.BigtableTableAdminClient} with
+ * Google-Cloud-java's models.
+ */
+public interface IBigtableTableAdminClient {
+
+  /**
+   * Creates a new table. The table can be created with a full set of initial column families,
+   * specified in the request.
+   * @param request a {@link CreateTableRequest} object.
+   */
+  Table createTable(CreateTableRequest request);
+
+  /**
+   * Creates a new table asynchronously. The table can be created with a full set of initial column
+   * families, specified in the request.
+   *
+   * @param request a {@link CreateTableRequest} object.
+   */
+  //TODO(rahulkql): Once it is adapted to v2.models, change the return type to ApiFuture.
+  ListenableFuture<Table> createTableAsync(CreateTableRequest request);
+
+  /**
+   * Gets the details of a table.
+   *
+   * @param tableId a String object.
+   * @return a {@link Table} object.
+   */
+  Table getTable(String tableId);
+
+  /**
+   * Gets the details of a table asynchronously.
+   *
+   * @return a {@link ListenableFuture} that returns a {@link Table} object.
+   */
+  //TODO(rahulkql): Once it is adapted to v2.models, change the return type to ApiFuture.
+  ListenableFuture<Table> getTableAsync(String tableId);
+
+  /**
+   * Lists the names of all tables in an instance.
+   *
+   * @return an immutable {@link List} object containing tableId.
+   */
+  List<String> listTables();
+
+  /**
+   * Lists the names of all tables in an instance asynchronously.
+   *
+   * @return a {@link ListenableFuture} of type {@link Void} will be set when request is
+   *   successful otherwise exception will be thrown.
+   */
+  //TODO(rahulkql): Once it is adapted to v2.models, change the return type to ApiFuture.
+  ListenableFuture<List<String>> listTablesAsync();
+
+  /**
+   * Permanently deletes a specified table and all of its data.
+   *
+   */
+  void deleteTable(String tableId);
+
+  /**
+   * Permanently deletes a specified table and all of its data.
+   *
+   * @return a {@link ListenableFuture} of type {@link Void} will be set when request is
+   *  successful otherwise exception will be thrown.
+   */
+  //TODO(rahulkql): Once it is adapted to v2.models, change the return type to ApiFuture.
+  ListenableFuture<Void> deleteTableAsync(String tableId);
+
+  /**
+   * Creates, modifies or deletes a new column family within a specified table.
+   *
+   * @param request a {@link ModifyColumnFamiliesRequest} object.
+   * @return return {@link Table} object  that contains the updated table structure.
+   */
+  Table modifyFamilies(ModifyColumnFamiliesRequest request);
+
+  /**
+   * Creates, modifies or deletes a new column family within a specified table.
+   *
+   * @param request a {@link ModifyColumnFamiliesRequest} object.
+   * @return a {@link ListenableFuture} that returns {@link Table} object that contains
+   *  the updated table structure.
+   */
+  //TODO(rahulkql): Once it is adapted to v2.models, change the return type to ApiFuture.
+  ListenableFuture<Table> modifyFamiliesAsync(ModifyColumnFamiliesRequest request);
+
+  /**
+   * Permanently deletes all rows in a range.
+   *
+   * @param tableId
+   * @param rowKeyPrefix
+   */
+  void dropRowRange(String tableId, String rowKeyPrefix);
+
+  /**
+   * Permanently deletes all rows in a range.
+   *
+   * @param tableId
+   * @param rowKeyPrefix
+   * @return a {@link ListenableFuture} that returns {@link Void} object.
+   */
+  //TODO(rahulkql): Once it is adapted to v2.models, change the return type to ApiFuture.
+  ListenableFuture<Void> dropRowRangeAsync(String tableId, String rowKeyPrefix);
+}
diff --git a/bigtable-client-core-parent/bigtable-client-core/src/main/java/com/google/cloud/bigtable/grpc/BigtableTableAdminClientWrapper.java b/bigtable-client-core-parent/bigtable-client-core/src/main/java/com/google/cloud/bigtable/grpc/BigtableTableAdminClientWrapper.java
new file mode 100644
index 000000000..8d61273d6
--- /dev/null
+++ b/bigtable-client-core-parent/bigtable-client-core/src/main/java/com/google/cloud/bigtable/grpc/BigtableTableAdminClientWrapper.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2019 Google LLC. All Rights Reserved.
+ *
+ * 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.google.cloud.bigtable.grpc;
+
+import com.google.bigtable.admin.v2.DeleteTableRequest;
+import com.google.bigtable.admin.v2.DropRowRangeRequest;
+import com.google.bigtable.admin.v2.GetTableRequest;
+import com.google.bigtable.admin.v2.ListTablesRequest;
+import com.google.bigtable.admin.v2.ListTablesResponse;
+import com.google.cloud.bigtable.admin.v2.models.CreateTableRequest;
+import com.google.cloud.bigtable.admin.v2.models.ModifyColumnFamiliesRequest;
+import com.google.cloud.bigtable.admin.v2.models.Table;
+import com.google.cloud.bigtable.config.BigtableOptions;
+import com.google.cloud.bigtable.core.IBigtableTableAdminClient;
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.google.protobuf.ByteString;
+import com.google.protobuf.Empty;
+import java.util.List;
+import javax.annotation.Nonnull;
+
+/**
+ * This class implements the {@link IBigtableTableAdminClient} interface and wraps
+ * {@link BigtableTableAdminClient} with Google-cloud-java's models.
+ */
+public class BigtableTableAdminClientWrapper implements IBigtableTableAdminClient {
+
+  private final BigtableTableAdminClient adminClient;
+  private final BigtableInstanceName instanceName;
+
+  public BigtableTableAdminClientWrapper(@Nonnull BigtableTableAdminClient adminClient,
+      @Nonnull BigtableOptions options){
+    Preconditions.checkNotNull(adminClient);
+    Preconditions.checkNotNull(options);
+    this.adminClient = adminClient;
+    this.instanceName = new BigtableInstanceName(options.getProjectId(),
+        options.getInstanceId());
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public Table createTable(CreateTableRequest request) {
+    com.google.bigtable.admin.v2.CreateTableRequest requestProto =
+        request.toProto(instanceName.toAdminInstanceName());
+    adminClient.createTable(requestProto);
+
+    return getTable(requestProto.getTableId());
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public ListenableFuture<Table> createTableAsync(CreateTableRequest request) {
+    com.google.bigtable.admin.v2.CreateTableRequest requestProto =
+        request.toProto(instanceName.toAdminInstanceName());
+
+    return Futures.transform(adminClient.createTableAsync(requestProto),
+        new Function<com.google.bigtable.admin.v2.Table, Table>() {
+          @Override
+          public Table apply(com.google.bigtable.admin.v2.Table tableProto) {
+            return Table.fromProto(tableProto);
+          }
+        }, MoreExecutors.directExecutor());
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public Table getTable(String tableId) {
+    GetTableRequest requestProto = GetTableRequest.newBuilder()
+        .setName(instanceName.toTableNameStr(tableId))
+        .build();
+
+    return Table.fromProto(adminClient.getTable(requestProto));
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public ListenableFuture<Table> getTableAsync(String tableId) {
+    GetTableRequest requestProto = GetTableRequest.newBuilder()
+        .setName(instanceName.toTableNameStr(tableId))
+        .build();
+
+    return Futures.transform(adminClient.getTableAsync(requestProto),
+        new Function<com.google.bigtable.admin.v2.Table, Table>() {
+          @Override
+          public Table apply(com.google.bigtable.admin.v2.Table tableProto) {
+            return Table.fromProto(tableProto);
+          }
+        }, MoreExecutors.directExecutor());
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public List<String> listTables() {
+    ListTablesRequest requestProto = ListTablesRequest.newBuilder()
+        .setParent(instanceName.toString())
+        .build();
+
+    ListTablesResponse response = adminClient.listTables(requestProto);
+
+    ImmutableList.Builder<String> tableIdsBuilder =
+        ImmutableList.builderWithExpectedSize(response.getTablesList().size());
+    for(com.google.bigtable.admin.v2.Table tableProto : response.getTablesList()){
+      tableIdsBuilder.add(instanceName.toTableId(tableProto.getName()));
+    }
+
+    return tableIdsBuilder.build();
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public ListenableFuture<List<String>> listTablesAsync() {
+    ListTablesRequest request = ListTablesRequest.newBuilder()
+        .setParent(instanceName.toString())
+        .build();
+    ListenableFuture<ListTablesResponse> response = adminClient.listTablesAsync(request);
+
+    return Futures.transform(response, new Function<ListTablesResponse, List<String>>() {
+      @Override
+      public List<String> apply(ListTablesResponse input) {
+        ImmutableList.Builder<String> tableIdsBuilder =
+            ImmutableList.builderWithExpectedSize(input.getTablesList().size());
+        for(com.google.bigtable.admin.v2.Table tableProto : input.getTablesList()){
+          tableIdsBuilder.add(instanceName.toTableId(tableProto.getName()));
+        }
+
+        return tableIdsBuilder.build();
+      }
+    }, MoreExecutors.directExecutor());
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public void deleteTable(String tableId) {
+    DeleteTableRequest request = DeleteTableRequest.newBuilder()
+        .setName(instanceName.toTableNameStr(tableId))
+        .build();
+
+    adminClient.deleteTable(request);
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public ListenableFuture<Void> deleteTableAsync(String tableId) {
+    DeleteTableRequest request = DeleteTableRequest.newBuilder()
+        .setName(instanceName.toTableNameStr(tableId))
+        .build();
+
+    return Futures.transform(adminClient.deleteTableAsync(request), new Function<Empty, Void>() {
+      @Override
+      public Void apply(Empty empty) {
+        return null;
+      }
+    }, MoreExecutors.directExecutor());
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public Table modifyFamilies(ModifyColumnFamiliesRequest request) {
+    com.google.bigtable.admin.v2.ModifyColumnFamiliesRequest modifyColumnRequestProto =
+        request.toProto(instanceName.toAdminInstanceName());
+
+    return Table.fromProto(adminClient.modifyColumnFamily(modifyColumnRequestProto));
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public ListenableFuture<Table> modifyFamiliesAsync(ModifyColumnFamiliesRequest request) {
+    com.google.bigtable.admin.v2.ModifyColumnFamiliesRequest modifyColumnRequestProto =
+        request.toProto(instanceName.toAdminInstanceName());
+
+    return Futures.transform(adminClient.modifyColumnFamilyAsync(modifyColumnRequestProto),
+        new Function<com.google.bigtable.admin.v2.Table, Table>() {
+      @Override
+      public Table apply(com.google.bigtable.admin.v2.Table tableProto) {
+        return Table.fromProto(tableProto);
+      }
+    }, MoreExecutors.directExecutor());
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public void dropRowRange(String tableId, String rowKeyPrefix) {
+    DropRowRangeRequest requestProto = DropRowRangeRequest.newBuilder()
+        .setName(instanceName.toTableNameStr(tableId))
+        .setRowKeyPrefix(ByteString.copyFromUtf8(rowKeyPrefix))
+        .build();
+
+    adminClient.dropRowRange(requestProto);
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public ListenableFuture<Void> dropRowRangeAsync(String tableId, String rowKeyPrefix) {
+    DropRowRangeRequest requestProto = DropRowRangeRequest.newBuilder()
+        .setName(instanceName.toTableNameStr(tableId))
+        .setRowKeyPrefix(ByteString.copyFromUtf8(rowKeyPrefix))
+        .build();
+
+    return Futures.transform(adminClient.dropRowRangeAsync(requestProto), new Function<Empty, Void>() {
+      @Override
+      public Void apply(Empty empty) {
+          return null;
+      }
+    }, MoreExecutors.directExecutor());
+  }
+}


Test patch:
diff --git a/bigtable-client-core-parent/bigtable-client-core/src/test/java/com/google/cloud/bigtable/grpc/TestBigtableTableAdminClientWrapper.java b/bigtable-client-core-parent/bigtable-client-core/src/test/java/com/google/cloud/bigtable/grpc/TestBigtableTableAdminClientWrapper.java
new file mode 100644
index 000000000..f6a4d08fb
--- /dev/null
+++ b/bigtable-client-core-parent/bigtable-client-core/src/test/java/com/google/cloud/bigtable/grpc/TestBigtableTableAdminClientWrapper.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright 2019 Google LLC. All Rights Reserved.
+ *
+ * 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.google.cloud.bigtable.grpc;
+
+import static com.google.cloud.bigtable.admin.v2.models.GCRules.GCRULES;
+import static com.google.common.util.concurrent.Futures.immediateFuture;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import com.google.bigtable.admin.v2.ColumnFamily;
+import com.google.bigtable.admin.v2.DeleteTableRequest;
+import com.google.bigtable.admin.v2.DropRowRangeRequest;
+import com.google.bigtable.admin.v2.GetTableRequest;
+import com.google.bigtable.admin.v2.ListTablesRequest;
+import com.google.bigtable.admin.v2.ListTablesResponse;
+import com.google.cloud.bigtable.admin.v2.models.CreateTableRequest;
+import com.google.cloud.bigtable.admin.v2.models.GCRules;
+import com.google.cloud.bigtable.admin.v2.models.ModifyColumnFamiliesRequest;
+import com.google.cloud.bigtable.admin.v2.models.Table;
+import com.google.cloud.bigtable.config.BigtableOptions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.protobuf.ByteString;
+import com.google.protobuf.Empty;
+import java.util.List;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mockito;
+
+@RunWith(JUnit4.class)
+public class TestBigtableTableAdminClientWrapper {
+  private static final String PROJECT_ID = "projectId";
+  private static final String INSTANCE_ID = "instanceId";
+  private static final String TABLE_ID = "tableId";
+  private static final String APP_PROFILE_ID = "appProfileId";
+  private static final String COLUMN_FAMILY = "myColumnFamily";
+  private static final String ROW_KEY_PREFIX = "row-key-val";
+  private static final String UPDATE_FAMILY = "update-family";
+  private static final String TEST_TABLE_ID_1 = "test-table-1";
+  private static final String TEST_TABLE_ID_2 = "test-table-2";
+  private static final String TEST_TABLE_ID_3 = "test-table-3";
+
+  private BigtableOptions options = BigtableOptions.builder()
+      .setProjectId(PROJECT_ID)
+      .setInstanceId(INSTANCE_ID)
+      .setAppProfileId(APP_PROFILE_ID)
+      .build();
+  private static final BigtableInstanceName INSTANCE_NAME = new BigtableInstanceName(PROJECT_ID,
+      INSTANCE_ID);
+  private static final String TABLE_NAME = INSTANCE_NAME.toTableNameStr(TABLE_ID);
+
+  private BigtableTableAdminClient mockAdminClient;
+
+  private BigtableTableAdminClientWrapper clientWrapper;
+
+
+  @Before
+  public void setUp(){
+    mockAdminClient = Mockito.mock(BigtableTableAdminClient.class);
+    clientWrapper = new BigtableTableAdminClientWrapper(mockAdminClient, options);
+  }
+
+  @Test
+  public void testCreateTable(){
+    CreateTableRequest request = CreateTableRequest.of(TABLE_ID);
+    GetTableRequest getTableRequest = GetTableRequest.newBuilder().setName(TABLE_NAME).build();
+
+    doNothing().when(mockAdminClient).createTable(request.toProto(INSTANCE_NAME.toAdminInstanceName()));
+    when(mockAdminClient.getTable(getTableRequest)).thenReturn(createTableData());
+    Table response = clientWrapper.createTable(request);
+
+    assertEquals(Table.fromProto(createTableData()), response);
+    verify(mockAdminClient).createTable(request.toProto(INSTANCE_NAME.toAdminInstanceName()));
+    verify(mockAdminClient).getTable(getTableRequest);
+  }
+
+  @Test
+  public void testCreateTableAsync() throws Exception{
+    CreateTableRequest request = CreateTableRequest.of(TABLE_ID);
+
+    when(mockAdminClient.createTableAsync(request.toProto(INSTANCE_NAME.toAdminInstanceName())))
+        .thenReturn(immediateFuture(createTableData()));
+    ListenableFuture<Table> response = clientWrapper.createTableAsync(request);
+
+    assertEquals(Table.fromProto(createTableData()), response.get());
+    verify(mockAdminClient).createTableAsync(request.toProto(INSTANCE_NAME.toAdminInstanceName()));
+  }
+
+  @Test
+  public void testGetTable(){
+    GetTableRequest request = GetTableRequest.newBuilder().setName(TABLE_NAME).build();
+
+    when(mockAdminClient.getTable(request)).thenReturn(createTableData());
+    Table response = clientWrapper.getTable(TABLE_ID);
+
+    assertEquals(Table.fromProto(createTableData()), response);
+    verify(mockAdminClient).getTable(request);
+  }
+
+  @Test
+  public void testGetTableAsync() throws Exception{
+    GetTableRequest request = GetTableRequest.newBuilder().setName(TABLE_NAME).build();
+
+    when(mockAdminClient.getTableAsync(request))
+        .thenReturn(immediateFuture(createTableData()));
+    ListenableFuture<Table> response = clientWrapper.getTableAsync(TABLE_ID);
+
+    assertEquals(Table.fromProto(createTableData()), response.get());
+    verify(mockAdminClient).getTableAsync(request);
+  }
+
+  @Test
+  public void testListTables(){
+    ImmutableList<String> tableIdList = ImmutableList.of(TEST_TABLE_ID_1, TEST_TABLE_ID_2,
+        TEST_TABLE_ID_3);
+    ListTablesRequest request =
+        ListTablesRequest.newBuilder().setParent(INSTANCE_NAME.toString()).build();
+    ListTablesResponse.Builder builder = ListTablesResponse.newBuilder();
+    builder.addTablesBuilder().setName(INSTANCE_NAME.toTableNameStr(TEST_TABLE_ID_1)).build();
+    builder.addTablesBuilder().setName(INSTANCE_NAME.toTableNameStr(TEST_TABLE_ID_2)).build();
+    builder.addTablesBuilder().setName(INSTANCE_NAME.toTableNameStr(TEST_TABLE_ID_3)).build();
+
+    when(mockAdminClient.listTables(request)).thenReturn(builder.build());
+    List<String> actualResponse = clientWrapper.listTables();
+
+    assertEquals(tableIdList, actualResponse);
+    verify(mockAdminClient).listTables(request);
+  }
+
+  @Test
+  public void testListTablesAsync() throws Exception{
+    ImmutableList<String> tableIdList = ImmutableList.of(TEST_TABLE_ID_1, TEST_TABLE_ID_2,
+        TEST_TABLE_ID_3);
+    ListTablesRequest request =
+        ListTablesRequest.newBuilder().setParent(INSTANCE_NAME.toString()).build();
+    ListTablesResponse.Builder builder = ListTablesResponse.newBuilder();
+    builder.addTablesBuilder().setName(INSTANCE_NAME.toTableNameStr(TEST_TABLE_ID_1)).build();
+    builder.addTablesBuilder().setName(INSTANCE_NAME.toTableNameStr(TEST_TABLE_ID_2)).build();
+    builder.addTablesBuilder().setName(INSTANCE_NAME.toTableNameStr(TEST_TABLE_ID_3)).build();
+
+    when(mockAdminClient.listTablesAsync(request)).thenReturn(immediateFuture(builder.build()));
+    ListenableFuture<List<String>> actualResponse = clientWrapper.listTablesAsync();
+
+    assertEquals(tableIdList, actualResponse.get());
+    verify(mockAdminClient).listTablesAsync(request);
+  }
+
+  @Test
+  public void testDeleteTable(){
+    DeleteTableRequest request = DeleteTableRequest.newBuilder().setName(TABLE_NAME).build();
+
+    doNothing().when(mockAdminClient).deleteTable(request);
+    clientWrapper.deleteTable(TABLE_ID);
+
+    verify(mockAdminClient).deleteTable(request);
+  }
+
+  @Test
+  public void testDeleteTableAsync(){
+    DeleteTableRequest request = DeleteTableRequest.newBuilder().setName(TABLE_NAME).build();
+
+    when(mockAdminClient.deleteTableAsync(request))
+        .thenReturn(immediateFuture(Empty.newBuilder().build()));
+    clientWrapper.deleteTableAsync(TABLE_ID);
+
+    verify(mockAdminClient).deleteTableAsync(request);
+  }
+
+  @Test
+  public void testModifyFamilies(){
+    ModifyColumnFamiliesRequest request =
+        ModifyColumnFamiliesRequest
+            .of(TABLE_ID)
+            .addFamily(COLUMN_FAMILY, GCRULES.maxVersions(1))
+            .updateFamily(UPDATE_FAMILY, GCRULES.defaultRule());
+
+    when(mockAdminClient.modifyColumnFamily(request.toProto(INSTANCE_NAME.toAdminInstanceName())))
+        .thenReturn(createTableData());
+    Table response = clientWrapper.modifyFamilies(request);
+
+    assertEquals(Table.fromProto(createTableData()), response);
+    verify(mockAdminClient).modifyColumnFamily(request.toProto(INSTANCE_NAME.toAdminInstanceName()));
+  }
+
+  @Test
+  public void testModifyFamiliesAsync() throws Exception{
+    ModifyColumnFamiliesRequest request =
+        ModifyColumnFamiliesRequest
+            .of(TABLE_ID)
+            .addFamily(COLUMN_FAMILY, GCRULES.maxVersions(1))
+            .updateFamily(UPDATE_FAMILY, GCRULES.defaultRule());
+
+    when(mockAdminClient.modifyColumnFamilyAsync(request.toProto(INSTANCE_NAME.toAdminInstanceName())))
+        .thenReturn(immediateFuture(createTableData()));
+    ListenableFuture<Table> response = clientWrapper.modifyFamiliesAsync(request);
+
+    assertEquals(Table.fromProto(createTableData()), response.get());
+    verify(mockAdminClient).modifyColumnFamilyAsync(request.toProto(INSTANCE_NAME.toAdminInstanceName()));
+  }
+
+  @Test
+  public void dropRowRange(){
+    DropRowRangeRequest request = DropRowRangeRequest.newBuilder()
+        .setName(TABLE_NAME)
+        .setRowKeyPrefix(ByteString.copyFromUtf8(ROW_KEY_PREFIX))
+        .build();
+
+    doNothing().when(mockAdminClient).dropRowRange(request);
+    clientWrapper.dropRowRange(TABLE_ID, ROW_KEY_PREFIX);
+
+    verify(mockAdminClient).dropRowRange(request);
+  }
+
+  @Test
+  public void dropRowRangeAsync(){
+    DropRowRangeRequest request = DropRowRangeRequest.newBuilder()
+        .setName(TABLE_NAME)
+        .setRowKeyPrefix(ByteString.copyFromUtf8(ROW_KEY_PREFIX))
+        .build();
+
+    when(mockAdminClient.dropRowRangeAsync(request))
+        .thenReturn(immediateFuture(Empty.newBuilder().build()));
+    clientWrapper.dropRowRangeAsync(TABLE_ID, ROW_KEY_PREFIX);
+
+    verify(mockAdminClient).dropRowRangeAsync(request);
+  }
+
+  private static com.google.bigtable.admin.v2.Table createTableData(){
+    GCRules.GCRule gcRule = GCRULES.maxVersions(1);
+    ColumnFamily columnFamily = ColumnFamily.newBuilder()
+        .setGcRule(gcRule.toProto()).build();
+
+    return com.google.bigtable.admin.v2.Table.newBuilder()
+        .setName(TABLE_NAME)
+        .putColumnFamilies(COLUMN_FAMILY, columnFamily)
+        .build();
+  }
+}