Skip to content
Permalink
Browse files
feat: app profile multi cluster routing support with specified cluste…
…r ids (#961)

* feat: app profile multi cluster routing support with specified cluster ids

* fix mocked tests

* add additional ITs
  • Loading branch information
kolea2 committed Oct 20, 2021
1 parent 39622f3 commit f4c5c32c05d244a9ce7c3a4386ba9396c65f227e
@@ -22,6 +22,8 @@
import com.google.common.base.Preconditions;
import com.google.common.base.Verify;
import com.google.common.base.VerifyException;
import com.google.common.collect.ImmutableSet;
import java.util.Set;
import javax.annotation.Nonnull;

/**
@@ -64,7 +66,8 @@ private AppProfile(@Nonnull com.google.bigtable.admin.v2.AppProfile proto) {
@SuppressWarnings("WeakerAccess")
public RoutingPolicy getPolicy() {
if (proto.hasMultiClusterRoutingUseAny()) {
return MultiClusterRoutingPolicy.of();
return MultiClusterRoutingPolicy.of(
ImmutableSet.copyOf(proto.getMultiClusterRoutingUseAny().getClusterIdsList()));
} else if (proto.hasSingleClusterRouting()) {
return new SingleClusterRoutingPolicy(proto.getSingleClusterRouting());
} else {
@@ -226,15 +229,42 @@ public int hashCode() {
* available cluster.
*/
public static class MultiClusterRoutingPolicy implements RoutingPolicy {
private static final MultiClusterRoutingUseAny proto =
MultiClusterRoutingUseAny.getDefaultInstance();
private final MultiClusterRoutingUseAny proto;

/** Creates a new instance of {@link MultiClusterRoutingPolicy}. */
public static MultiClusterRoutingPolicy of() {
return new MultiClusterRoutingPolicy();
return new MultiClusterRoutingPolicy(MultiClusterRoutingUseAny.getDefaultInstance());
}

private MultiClusterRoutingPolicy() {}
/**
* Creates a new instance of {@link MultiClusterRoutingPolicy} with specified cluster ids to
* route to.
*/
public static MultiClusterRoutingPolicy of(String... clusterIds) {
return of(ImmutableSet.copyOf(clusterIds));
}

/**
* Creates a new instance of {@link MultiClusterRoutingPolicy} with specified cluster ids to
* route to.
*/
public static MultiClusterRoutingPolicy of(Set<String> clusterIds) {
return new MultiClusterRoutingPolicy(
MultiClusterRoutingUseAny.newBuilder().addAllClusterIds(clusterIds).build());
}

/*
* Returns the set of clusters to route to. The order is ignored; clusters will be
* tried in order of distance. If empty, all clusters are eligible.
*/
public Set<String> getClusterIds() {
return ImmutableSet.copyOf(proto.getClusterIdsList());
}

private MultiClusterRoutingPolicy(
com.google.bigtable.admin.v2.AppProfile.MultiClusterRoutingUseAny proto) {
this.proto = proto;
}

/**
* Creates the request protobuf. This method is considered an internal implementation detail and
@@ -253,8 +283,8 @@ public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) {
return false;
}

return true;
MultiClusterRoutingPolicy that = (MultiClusterRoutingPolicy) o;
return Objects.equal(proto, that.proto);
}

@Override
@@ -50,6 +50,7 @@
import com.google.cloud.bigtable.admin.v2.models.UpdateAppProfileRequest;
import com.google.cloud.bigtable.admin.v2.models.UpdateInstanceRequest;
import com.google.cloud.bigtable.admin.v2.stub.BigtableInstanceAdminStub;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.io.BaseEncoding;
import com.google.protobuf.ByteString;
@@ -617,6 +618,131 @@ public void testCreateAppProfile() {
assertThat(actualResult).isEqualTo(AppProfile.fromProto(expectedResponse));
}

@Test
public void testCreateAppProfileAddSingleClusterId() {
// Setup
Mockito.when(mockStub.createAppProfileCallable()).thenReturn(mockCreateAppProfileCallable);

com.google.bigtable.admin.v2.CreateAppProfileRequest expectedRequest =
com.google.bigtable.admin.v2.CreateAppProfileRequest.newBuilder()
.setParent(NameUtil.formatInstanceName(PROJECT_ID, INSTANCE_ID))
.setAppProfileId(APP_PROFILE_ID)
.setAppProfile(
com.google.bigtable.admin.v2.AppProfile.newBuilder()
.setDescription("my description")
.setMultiClusterRoutingUseAny(
com.google.bigtable.admin.v2.AppProfile.MultiClusterRoutingUseAny
.newBuilder()
.addClusterIds("cluster-id-1")))
.build();

com.google.bigtable.admin.v2.AppProfile expectedResponse =
com.google.bigtable.admin.v2.AppProfile.newBuilder()
.setName(APP_PROFILE_NAME)
.setDescription("my description")
.setMultiClusterRoutingUseAny(
com.google.bigtable.admin.v2.AppProfile.MultiClusterRoutingUseAny.newBuilder()
.addClusterIds("cluster-id-1"))
.build();

Mockito.when(mockCreateAppProfileCallable.futureCall(expectedRequest))
.thenReturn(ApiFutures.immediateFuture(expectedResponse));

// Execute
AppProfile actualResult =
adminClient.createAppProfile(
CreateAppProfileRequest.of(INSTANCE_ID, APP_PROFILE_ID)
.setDescription("my description")
.setRoutingPolicy(MultiClusterRoutingPolicy.of("cluster-id-1")));

// Verify
assertThat(actualResult).isEqualTo(AppProfile.fromProto(expectedResponse));
}

@Test
public void testCreateAppProfileAddMultipleClusterIds() {
// Setup
Mockito.when(mockStub.createAppProfileCallable()).thenReturn(mockCreateAppProfileCallable);

com.google.bigtable.admin.v2.CreateAppProfileRequest expectedRequest =
com.google.bigtable.admin.v2.CreateAppProfileRequest.newBuilder()
.setParent(NameUtil.formatInstanceName(PROJECT_ID, INSTANCE_ID))
.setAppProfileId(APP_PROFILE_ID)
.setAppProfile(
com.google.bigtable.admin.v2.AppProfile.newBuilder()
.setDescription("my description")
.setMultiClusterRoutingUseAny(
com.google.bigtable.admin.v2.AppProfile.MultiClusterRoutingUseAny
.newBuilder()
.addClusterIds("cluster-id-1")
.addClusterIds("cluster-id-2")))
.build();

com.google.bigtable.admin.v2.AppProfile expectedResponse =
com.google.bigtable.admin.v2.AppProfile.newBuilder()
.setName(APP_PROFILE_NAME)
.setDescription("my description")
.setMultiClusterRoutingUseAny(
com.google.bigtable.admin.v2.AppProfile.MultiClusterRoutingUseAny.newBuilder()
.addClusterIds("cluster-id-1")
.addClusterIds("cluster-id-2"))
.build();

Mockito.when(mockCreateAppProfileCallable.futureCall(expectedRequest))
.thenReturn(ApiFutures.immediateFuture(expectedResponse));

// Execute
AppProfile actualResult =
adminClient.createAppProfile(
CreateAppProfileRequest.of(INSTANCE_ID, APP_PROFILE_ID)
.setDescription("my description")
.setRoutingPolicy(MultiClusterRoutingPolicy.of("cluster-id-1", "cluster-id-2")));

// Verify
assertThat(actualResult).isEqualTo(AppProfile.fromProto(expectedResponse));
}

@Test
public void testCreateAppProfileAddMultipleClusterIdsWithList() {
// Setup
Mockito.when(mockStub.createAppProfileCallable()).thenReturn(mockCreateAppProfileCallable);

com.google.bigtable.admin.v2.CreateAppProfileRequest expectedRequest =
com.google.bigtable.admin.v2.CreateAppProfileRequest.newBuilder()
.setParent(NameUtil.formatInstanceName(PROJECT_ID, INSTANCE_ID))
.setAppProfileId(APP_PROFILE_ID)
.setAppProfile(
com.google.bigtable.admin.v2.AppProfile.newBuilder()
.setDescription("my description")
.setMultiClusterRoutingUseAny(
com.google.bigtable.admin.v2.AppProfile.MultiClusterRoutingUseAny
.newBuilder()
.addAllClusterIds(ImmutableList.of("cluster-id-1", "cluster-id-2"))))
.build();

com.google.bigtable.admin.v2.AppProfile expectedResponse =
com.google.bigtable.admin.v2.AppProfile.newBuilder()
.setName(APP_PROFILE_NAME)
.setDescription("my description")
.setMultiClusterRoutingUseAny(
com.google.bigtable.admin.v2.AppProfile.MultiClusterRoutingUseAny.newBuilder()
.addAllClusterIds(ImmutableList.of("cluster-id-1", "cluster-id-2")))
.build();

Mockito.when(mockCreateAppProfileCallable.futureCall(expectedRequest))
.thenReturn(ApiFutures.immediateFuture(expectedResponse));

// Execute
AppProfile actualResult =
adminClient.createAppProfile(
CreateAppProfileRequest.of(INSTANCE_ID, APP_PROFILE_ID)
.setDescription("my description")
.setRoutingPolicy(MultiClusterRoutingPolicy.of("cluster-id-1", "cluster-id-2")));

// Verify
assertThat(actualResult).isEqualTo(AppProfile.fromProto(expectedResponse));
}

@Test
public void testGetAppProfile() {
// Setup
@@ -96,6 +96,99 @@ public void appProfileTest() {
assertThat(actualEx).isNull();
}

@Test
public void appProfileTestMultiClusterWithIds() {
String newInstanceId = prefixGenerator.newPrefix();
String newClusterId = newInstanceId + "-c1";
String newClusterId2 = newInstanceId + "-c2";

client.createInstance(
CreateInstanceRequest.of(newInstanceId)
.addCluster(newClusterId, testEnvRule.env().getPrimaryZone(), 1, StorageType.SSD)
.addCluster(newClusterId2, testEnvRule.env().getSecondaryZone(), 1, StorageType.SSD)
.setDisplayName("Multi-Cluster-Instance-Test")
.addLabel("state", "readytodelete")
.setType(Type.PRODUCTION));

try {
assertThat(client.exists(newInstanceId)).isTrue();

String testAppProfile = "test-app-profile";

CreateAppProfileRequest request =
CreateAppProfileRequest.of(newInstanceId, testAppProfile)
.setRoutingPolicy(AppProfile.MultiClusterRoutingPolicy.of(newClusterId))
.setDescription("This is to test app profile");

AppProfile newlyCreatedAppProfile = client.createAppProfile(request);

AppProfile updated =
client.updateAppProfile(
UpdateAppProfileRequest.of(newlyCreatedAppProfile).setDescription("new description"));

AppProfile freshAppProfile = client.getAppProfile(newInstanceId, testAppProfile);
assertThat(freshAppProfile.getDescription()).isEqualTo(updated.getDescription());

AppProfile.MultiClusterRoutingPolicy freshAppProfilePolicy =
(AppProfile.MultiClusterRoutingPolicy) freshAppProfile.getPolicy();
AppProfile.MultiClusterRoutingPolicy updatedAppProfilePolicy =
(AppProfile.MultiClusterRoutingPolicy) updated.getPolicy();

assertThat(freshAppProfilePolicy.getClusterIds()).containsExactly(newClusterId);
assertThat(freshAppProfilePolicy.getClusterIds())
.isEqualTo(updatedAppProfilePolicy.getClusterIds());
assertThat(freshAppProfilePolicy).isEqualTo(updatedAppProfilePolicy);

assertThat(client.listAppProfiles(newInstanceId)).contains(freshAppProfile);

// update again with routing policy
AppProfile updated2 =
client.updateAppProfile(
UpdateAppProfileRequest.of(updated)
.setRoutingPolicy(AppProfile.MultiClusterRoutingPolicy.of(newClusterId2)));

AppProfile freshAppProfile2 = client.getAppProfile(newInstanceId, testAppProfile);
assertThat(freshAppProfile2.getDescription()).isEqualTo(updated2.getDescription());

AppProfile.MultiClusterRoutingPolicy freshAppProfilePolicy2 =
(AppProfile.MultiClusterRoutingPolicy) freshAppProfile2.getPolicy();
AppProfile.MultiClusterRoutingPolicy updatedAppProfilePolicy2 =
(AppProfile.MultiClusterRoutingPolicy) updated2.getPolicy();

assertThat(freshAppProfilePolicy2.getClusterIds()).containsExactly(newClusterId2);
assertThat(freshAppProfilePolicy2.getClusterIds())
.isEqualTo(updatedAppProfilePolicy2.getClusterIds());
assertThat(freshAppProfilePolicy2).isEqualTo(updatedAppProfilePolicy2);

assertThat(client.listAppProfiles(newInstanceId)).contains(freshAppProfile2);

// update to single routing policy
AppProfile updated3 =
client.updateAppProfile(
UpdateAppProfileRequest.of(updated)
.setRoutingPolicy(AppProfile.SingleClusterRoutingPolicy.of(newClusterId)));

AppProfile freshAppProfile3 = client.getAppProfile(newInstanceId, testAppProfile);
assertThat(freshAppProfile3.getDescription()).isEqualTo(updated3.getDescription());

AppProfile.SingleClusterRoutingPolicy freshAppProfilePolicy3 =
(AppProfile.SingleClusterRoutingPolicy) freshAppProfile3.getPolicy();
AppProfile.SingleClusterRoutingPolicy updatedAppProfilePolicy3 =
(AppProfile.SingleClusterRoutingPolicy) updated3.getPolicy();

assertThat(freshAppProfilePolicy3.getClusterId()).isEqualTo(newClusterId);
assertThat(freshAppProfilePolicy3.getClusterId())
.isEqualTo(updatedAppProfilePolicy3.getClusterId());
assertThat(freshAppProfilePolicy3).isEqualTo(updatedAppProfilePolicy3);

assertThat(client.listAppProfiles(newInstanceId)).contains(freshAppProfile3);
} finally {
if (client.exists(newInstanceId)) {
client.deleteInstance(newInstanceId);
}
}
}

@Test
public void iamUpdateTest() {
Policy policy = client.getIamPolicy(instanceId);
@@ -20,6 +20,7 @@
import com.google.bigtable.admin.v2.AppProfile.SingleClusterRouting;
import com.google.bigtable.admin.v2.AppProfileName;
import com.google.cloud.bigtable.admin.v2.models.AppProfile.SingleClusterRoutingPolicy;
import com.google.common.collect.ImmutableList;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -48,6 +49,46 @@ public void testFromProto() {
assertThat(profile.getPolicy()).isEqualTo(SingleClusterRoutingPolicy.of("my-cluster", true));
}

@Test
public void testFromProtoWithMultiCluster() {
AppProfile profile =
AppProfile.fromProto(
com.google.bigtable.admin.v2.AppProfile.newBuilder()
.setName(AppProfileName.of("my-project", "my-instance", "my-profile").toString())
.setDescription("my description")
.setMultiClusterRoutingUseAny(
com.google.bigtable.admin.v2.AppProfile.MultiClusterRoutingUseAny.newBuilder()
.build())
.setEtag("my-etag")
.build());

assertThat(profile.getInstanceId()).isEqualTo("my-instance");
assertThat(profile.getId()).isEqualTo("my-profile");
assertThat(profile.getDescription()).isEqualTo("my description");
assertThat(profile.getPolicy()).isEqualTo(AppProfile.MultiClusterRoutingPolicy.of());
}

@Test
public void testFromProtoWithMultiClusterWithIds() {
AppProfile profile =
AppProfile.fromProto(
com.google.bigtable.admin.v2.AppProfile.newBuilder()
.setName(AppProfileName.of("my-project", "my-instance", "my-profile").toString())
.setDescription("my description")
.setMultiClusterRoutingUseAny(
com.google.bigtable.admin.v2.AppProfile.MultiClusterRoutingUseAny.newBuilder()
.addAllClusterIds(ImmutableList.of("cluster-id-1", "cluster-id-2"))
.build())
.setEtag("my-etag")
.build());

assertThat(profile.getInstanceId()).isEqualTo("my-instance");
assertThat(profile.getId()).isEqualTo("my-profile");
assertThat(profile.getDescription()).isEqualTo("my description");
assertThat(profile.getPolicy())
.isEqualTo(AppProfile.MultiClusterRoutingPolicy.of("cluster-id-1", "cluster-id-2"));
}

@Test
public void testNoNameError() {
Exception actualException = null;

0 comments on commit f4c5c32

Please sign in to comment.