com.google.truth
truth
diff --git a/bigtable-hbase-1.x-parent/bigtable-hbase-1.x/src/test/java/com/google/cloud/bigtable/hbase1_x/BigtableAdminTest.java b/bigtable-hbase-1.x-parent/bigtable-hbase-1.x/src/test/java/com/google/cloud/bigtable/hbase1_x/BigtableAdminTest.java
index fbced4e383..2cfee4d7a4 100644
--- a/bigtable-hbase-1.x-parent/bigtable-hbase-1.x/src/test/java/com/google/cloud/bigtable/hbase1_x/BigtableAdminTest.java
+++ b/bigtable-hbase-1.x-parent/bigtable-hbase-1.x/src/test/java/com/google/cloud/bigtable/hbase1_x/BigtableAdminTest.java
@@ -22,11 +22,11 @@
import com.google.bigtable.admin.v2.DropRowRangeRequest;
import com.google.cloud.bigtable.hbase.BigtableConfiguration;
import com.google.cloud.bigtable.hbase.BigtableOptionsFactory;
+import com.google.cloud.bigtable.test.helper.TestServerBuilder;
import com.google.protobuf.ByteString;
import com.google.protobuf.Empty;
import io.grpc.*;
import java.io.IOException;
-import java.net.ServerSocket;
import java.util.concurrent.ArrayBlockingQueue;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.ClusterStatus;
@@ -54,21 +54,16 @@ public class BigtableAdminTest {
@Before
public void setup() throws Exception {
- final int port;
-
- try (ServerSocket serverSocket = new ServerSocket(0)) {
- port = serverSocket.getLocalPort();
- }
-
fakeBigtableServer =
- ServerBuilder.forPort(port)
+ TestServerBuilder.newInstance()
.intercept(new RequestInterceptor())
.addService(new BigtableTableAdminGrpc.BigtableTableAdminImplBase() {})
- .build();
- fakeBigtableServer.start();
+ .buildAndStart();
Configuration configuration = BigtableConfiguration.configure(PROJECT_ID, INSTANCE_ID);
- configuration.set(BigtableOptionsFactory.BIGTABLE_EMULATOR_HOST_KEY, "localhost:" + port);
+ configuration.set(
+ BigtableOptionsFactory.BIGTABLE_EMULATOR_HOST_KEY,
+ "localhost:" + fakeBigtableServer.getPort());
connection = new BigtableConnection(configuration);
admin = (BigtableAdmin) connection.getAdmin();
}
diff --git a/bigtable-hbase-1.x-parent/bigtable-hbase-1.x/src/test/java/com/google/cloud/bigtable/hbase1_x/TestBigtableAdmin.java b/bigtable-hbase-1.x-parent/bigtable-hbase-1.x/src/test/java/com/google/cloud/bigtable/hbase1_x/TestBigtableAdmin.java
index 740672debe..6b2bf670b6 100644
--- a/bigtable-hbase-1.x-parent/bigtable-hbase-1.x/src/test/java/com/google/cloud/bigtable/hbase1_x/TestBigtableAdmin.java
+++ b/bigtable-hbase-1.x-parent/bigtable-hbase-1.x/src/test/java/com/google/cloud/bigtable/hbase1_x/TestBigtableAdmin.java
@@ -22,17 +22,16 @@
import com.google.bigtable.admin.v2.DropRowRangeRequest;
import com.google.cloud.bigtable.hbase.BigtableConfiguration;
import com.google.cloud.bigtable.hbase.BigtableOptionsFactory;
+import com.google.cloud.bigtable.test.helper.TestServerBuilder;
import com.google.protobuf.ByteString;
import com.google.protobuf.Empty;
import io.grpc.Metadata;
import io.grpc.Server;
-import io.grpc.ServerBuilder;
import io.grpc.ServerCall;
import io.grpc.ServerCallHandler;
import io.grpc.ServerInterceptor;
import io.grpc.Status;
import java.io.IOException;
-import java.net.ServerSocket;
import java.util.concurrent.ArrayBlockingQueue;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.ClusterStatus;
@@ -61,21 +60,16 @@ public class TestBigtableAdmin {
@Before
public void setup() throws Exception {
- final int port;
-
- try (ServerSocket serverSocket = new ServerSocket(0)) {
- port = serverSocket.getLocalPort();
- }
-
fakeBigtableServer =
- ServerBuilder.forPort(port)
+ TestServerBuilder.newInstance()
.intercept(new RequestInterceptor())
.addService(new BigtableTableAdminGrpc.BigtableTableAdminImplBase() {})
- .build();
- fakeBigtableServer.start();
+ .buildAndStart();
Configuration configuration = BigtableConfiguration.configure(PROJECT_ID, INSTANCE_ID);
- configuration.set(BigtableOptionsFactory.BIGTABLE_EMULATOR_HOST_KEY, "localhost:" + port);
+ configuration.set(
+ BigtableOptionsFactory.BIGTABLE_EMULATOR_HOST_KEY,
+ "localhost:" + fakeBigtableServer.getPort());
connection = new BigtableConnection(configuration);
admin = (BigtableAdmin) connection.getAdmin();
}
diff --git a/bigtable-hbase-1.x-parent/bigtable-hbase-1.x/src/test/java/com/google/cloud/bigtable/hbase1_x/TestBigtableConnection.java b/bigtable-hbase-1.x-parent/bigtable-hbase-1.x/src/test/java/com/google/cloud/bigtable/hbase1_x/TestBigtableConnection.java
index 5a31f033e6..a30c47ab3c 100644
--- a/bigtable-hbase-1.x-parent/bigtable-hbase-1.x/src/test/java/com/google/cloud/bigtable/hbase1_x/TestBigtableConnection.java
+++ b/bigtable-hbase-1.x-parent/bigtable-hbase-1.x/src/test/java/com/google/cloud/bigtable/hbase1_x/TestBigtableConnection.java
@@ -24,13 +24,12 @@
import com.google.cloud.bigtable.data.v2.internal.NameUtil;
import com.google.cloud.bigtable.hbase.AbstractBigtableTable;
import com.google.cloud.bigtable.hbase.BigtableOptionsFactory;
+import com.google.cloud.bigtable.test.helper.TestServerBuilder;
import com.google.common.collect.Queues;
import com.google.protobuf.ByteString;
import io.grpc.Server;
-import io.grpc.ServerBuilder;
import io.grpc.stub.StreamObserver;
import java.io.IOException;
-import java.net.ServerSocket;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executors;
@@ -57,7 +56,6 @@ public class TestBigtableConnection {
private static final String FULL_TABLE_NAME =
NameUtil.formatTableName(TEST_PROJECT_ID, TEST_INSTANCE_ID, TABLE_NAME.getNameAsString());
private static Server server;
- private static int dataPort;
private static FakeDataService fakeDataService = new FakeDataService();
private Configuration configuration;
@@ -65,11 +63,7 @@ public class TestBigtableConnection {
@BeforeClass
public static void setUpServer() throws IOException {
- try (ServerSocket s = new ServerSocket(0)) {
- dataPort = s.getLocalPort();
- }
- server = ServerBuilder.forPort(dataPort).addService(fakeDataService).build();
- server.start();
+ server = TestServerBuilder.newInstance().addService(fakeDataService).buildAndStart();
}
@AfterClass
@@ -87,7 +81,8 @@ public void setUp() throws IOException {
configuration.set(BigtableOptionsFactory.INSTANCE_ID_KEY, TEST_INSTANCE_ID);
configuration.set(BigtableOptionsFactory.BIGTABLE_NULL_CREDENTIAL_ENABLE_KEY, "true");
configuration.set(BigtableOptionsFactory.BIGTABLE_DATA_CHANNEL_COUNT_KEY, "1");
- configuration.set(BigtableOptionsFactory.BIGTABLE_EMULATOR_HOST_KEY, "localhost:" + dataPort);
+ configuration.set(
+ BigtableOptionsFactory.BIGTABLE_EMULATOR_HOST_KEY, "localhost:" + server.getPort());
connection = new BigtableConnection(configuration);
}
diff --git a/bigtable-hbase-1.x-parent/bigtable-hbase-1.x/src/test/java/com/google/cloud/bigtable/hbase1_x/TestMetrics.java b/bigtable-hbase-1.x-parent/bigtable-hbase-1.x/src/test/java/com/google/cloud/bigtable/hbase1_x/TestMetrics.java
index cc62f3ffb0..f702238f31 100644
--- a/bigtable-hbase-1.x-parent/bigtable-hbase-1.x/src/test/java/com/google/cloud/bigtable/hbase1_x/TestMetrics.java
+++ b/bigtable-hbase-1.x-parent/bigtable-hbase-1.x/src/test/java/com/google/cloud/bigtable/hbase1_x/TestMetrics.java
@@ -29,18 +29,17 @@
import com.google.cloud.bigtable.metrics.Meter;
import com.google.cloud.bigtable.metrics.MetricRegistry;
import com.google.cloud.bigtable.metrics.Timer;
+import com.google.cloud.bigtable.test.helper.TestServerBuilder;
import com.google.common.base.Stopwatch;
import com.google.common.collect.Range;
import com.google.protobuf.ByteString;
import com.google.protobuf.BytesValue;
import com.google.protobuf.StringValue;
import io.grpc.Server;
-import io.grpc.ServerBuilder;
import io.grpc.Status;
import io.grpc.StatusRuntimeException;
import io.grpc.stub.StreamObserver;
import java.io.IOException;
-import java.net.ServerSocket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -68,7 +67,6 @@ public class TestMetrics {
private final String TEST_INSTANCE_ID = "fake-instance-id";
private final TableName TABLE_NAME = TableName.valueOf("fake-table");
private Server server;
- private int dataPort;
private FakeMetricRegistry fakeMetricRegistry;
private MetricRegistry originalMetricRegistry;
@@ -97,11 +95,7 @@ public class TestMetrics {
@Before
public void setUp() throws IOException {
- try (ServerSocket s = new ServerSocket(0)) {
- dataPort = s.getLocalPort();
- }
- server = ServerBuilder.forPort(dataPort).addService(fakeDataService).build();
- server.start();
+ server = TestServerBuilder.newInstance().addService(fakeDataService).buildAndStart();
originalLevelToLog = BigtableClientMetrics.getLevelToLog();
originalMetricRegistry = BigtableClientMetrics.getMetricRegistry(originalLevelToLog);
@@ -111,7 +105,8 @@ public void setUp() throws IOException {
configuration.set(BigtableOptionsFactory.INSTANCE_ID_KEY, TEST_INSTANCE_ID);
configuration.set(BigtableOptionsFactory.BIGTABLE_NULL_CREDENTIAL_ENABLE_KEY, "true");
configuration.set(BigtableOptionsFactory.BIGTABLE_DATA_CHANNEL_COUNT_KEY, "1");
- configuration.set(BigtableOptionsFactory.BIGTABLE_EMULATOR_HOST_KEY, "localhost:" + dataPort);
+ configuration.set(
+ BigtableOptionsFactory.BIGTABLE_EMULATOR_HOST_KEY, "localhost:" + server.getPort());
configuration.set(BigtableOptionsFactory.BIGTABLE_USE_GCJ_CLIENT, "true");
fakeMetricRegistry = new FakeMetricRegistry();
diff --git a/bigtable-test/bigtable-internal-test-helper/pom.xml b/bigtable-test/bigtable-internal-test-helper/pom.xml
new file mode 100644
index 0000000000..0c8c7a6d76
--- /dev/null
+++ b/bigtable-test/bigtable-internal-test-helper/pom.xml
@@ -0,0 +1,102 @@
+
+
+
+ bigtable-test
+ com.google.cloud.bigtable
+ 2.0.0-alpha-1-SNAPSHOT
+
+ 4.0.0
+
+ bigtable-internal-test-helper
+
+ Module with helper code for Bigtable unit and integration tests.
+ Not intended to be shared with external users.
+
+
+
+
+
+ com.google.cloud
+ google-cloud-bigtable-bom
+ ${bigtable.version}
+ pom
+ import
+
+
+ com.google.cloud
+ google-cloud-bigtable-deps-bom
+ ${bigtable.version}
+ pom
+ import
+
+
+
+
+
+
+ io.grpc
+ grpc-api
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-deploy-plugin
+ 3.0.0-M1
+
+ true
+
+
+
+ org.sonatype.plugins
+ nexus-staging-maven-plugin
+
+ true
+
+
+
+ org.apache.maven.plugins
+ maven-site-plugin
+
+ true
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+
+ true
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+
+ true
+
+
+
+ org.apache.maven.plugins
+ maven-gpg-plugin
+
+ true
+
+
+
+ org.codehaus.mojo
+ clirr-maven-plugin
+
+ true
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/bigtable-test/bigtable-internal-test-helper/src/main/java/com/google/cloud/bigtable/test/helper/TestServerBuilder.java b/bigtable-test/bigtable-internal-test-helper/src/main/java/com/google/cloud/bigtable/test/helper/TestServerBuilder.java
new file mode 100644
index 0000000000..436e6795f6
--- /dev/null
+++ b/bigtable-test/bigtable-internal-test-helper/src/main/java/com/google/cloud/bigtable/test/helper/TestServerBuilder.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2021 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
+ *
+ * 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.test.helper;
+
+import io.grpc.BindableService;
+import io.grpc.Server;
+import io.grpc.ServerBuilder;
+import io.grpc.ServerInterceptor;
+import io.grpc.ServerServiceDefinition;
+import java.io.File;
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Wrapper around {@link ServerBuilder} that automatically finds a free port when starting the
+ * service.
+ *
+ * This wraps the call for getting a random free port (e.g. ServerSocket ss = new
+ * ServerSocket(0)) into a retry, since it is possible for another process on the host to use the
+ * port before the caller of the method can. Though it does not happen often, it happens enough to
+ * cause noticeable test flakes. Retrying the call will minimize the flakes.
+ */
+public class TestServerBuilder {
+ private List services = new ArrayList<>();
+ private List serverServiceDefinitions = new ArrayList<>();
+ private List interceptors = new ArrayList<>();
+ private File certChain = null;
+ private File privateKey = null;
+
+ public static TestServerBuilder newInstance() {
+ return new TestServerBuilder();
+ }
+
+ private TestServerBuilder() {}
+
+ /** See {@link ServerBuilder#addService(BindableService)}. */
+ public TestServerBuilder addService(BindableService service) {
+ services.add(service);
+ return this;
+ }
+
+ /** See {@link ServerBuilder#addService(ServerServiceDefinition)}. */
+ public TestServerBuilder addService(ServerServiceDefinition serverServiceDefinition) {
+ serverServiceDefinitions.add(serverServiceDefinition);
+ return this;
+ }
+
+ /** See {@link ServerBuilder#intercept(ServerInterceptor)}. */
+ public TestServerBuilder intercept(ServerInterceptor interceptor) {
+ interceptors.add(interceptor);
+ return this;
+ }
+
+ /** See {@link ServerBuilder#useTransportSecurity(File, File)}. */
+ public TestServerBuilder useTransportSecurity(File certChain, File privateKey) {
+ this.certChain = certChain;
+ this.privateKey = privateKey;
+ return this;
+ }
+
+ private Server buildServer(int port) {
+ ServerBuilder> builder = ServerBuilder.forPort(port);
+
+ for (BindableService service : services) {
+ builder.addService(service);
+ }
+ for (ServerServiceDefinition serverServiceDefinition : serverServiceDefinitions) {
+ builder.addService(serverServiceDefinition);
+ }
+ for (ServerInterceptor interceptor : interceptors) {
+ builder.intercept(interceptor);
+ }
+
+ if (certChain != null || privateKey != null) {
+ builder.useTransportSecurity(certChain, privateKey);
+ }
+ return builder.build();
+ }
+
+ /**
+ * Gets a free port on the host and starts the server, retrying in case the start fails (notably
+ * if the port is no longer available).
+ */
+ public Server buildAndStart() throws IOException {
+ IOException lastError = null;
+
+ int maxRetries = 3;
+ for (int retry = 0; retry < maxRetries; retry++) {
+ int port;
+ try (ServerSocket ss = new ServerSocket(0)) {
+ port = ss.getLocalPort();
+ }
+
+ Server server = buildServer(port);
+ try {
+ server.start();
+ return server;
+ } catch (IOException e) {
+ server.shutdown();
+ lastError = e;
+ }
+ }
+
+ throw lastError;
+ }
+}
diff --git a/bigtable-test/pom.xml b/bigtable-test/pom.xml
index 974b9cf90f..8fe3cddd6c 100644
--- a/bigtable-test/pom.xml
+++ b/bigtable-test/pom.xml
@@ -33,5 +33,6 @@ limitations under the License.
bigtable-emulator-maven-plugin
bigtable-build-helper
+ bigtable-internal-test-helper