From 656684b7f0fff003bb582977beb828f83da9a135 Mon Sep 17 00:00:00 2001 From: Igor Bernstein Date: Fri, 8 May 2020 14:20:29 -0400 Subject: [PATCH] fix: add missing api-client header (#290) * fix: add missing api-client header When migrating to custom callable chains, wI accidentally forgot to pull the api client header provider to the enhanced settings. * codestyle * codestyle --- .../v2/stub/EnhancedBigtableStubSettings.java | 1 + .../bigtable/data/v2/stub/HeadersTest.java | 237 ++++++++++++++++++ .../data/v2/stub/ResourceHeaderTest.java | 161 ------------ 3 files changed, 238 insertions(+), 161 deletions(-) create mode 100644 google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/stub/HeadersTest.java delete mode 100644 google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/stub/ResourceHeaderTest.java diff --git a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/EnhancedBigtableStubSettings.java b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/EnhancedBigtableStubSettings.java index 8a48115b5..d653542ac 100644 --- a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/EnhancedBigtableStubSettings.java +++ b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/EnhancedBigtableStubSettings.java @@ -519,6 +519,7 @@ private Builder() { setTransportChannelProvider(defaultTransportChannelProvider()); setStreamWatchdogCheckInterval(baseDefaults.getStreamWatchdogCheckInterval()); setStreamWatchdogProvider(baseDefaults.getStreamWatchdogProvider()); + setHeaderProvider(BigtableStubSettings.defaultApiClientHeaderProviderBuilder().build()); setTracerFactory( new OpencensusTracerFactory( diff --git a/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/stub/HeadersTest.java b/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/stub/HeadersTest.java new file mode 100644 index 000000000..32c7eb353 --- /dev/null +++ b/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/stub/HeadersTest.java @@ -0,0 +1,237 @@ +/* + * Copyright 2020 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.data.v2.stub; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.api.gax.batching.Batcher; +import com.google.bigtable.v2.BigtableGrpc; +import com.google.bigtable.v2.CheckAndMutateRowRequest; +import com.google.bigtable.v2.CheckAndMutateRowResponse; +import com.google.bigtable.v2.MutateRowRequest; +import com.google.bigtable.v2.MutateRowResponse; +import com.google.bigtable.v2.MutateRowsRequest; +import com.google.bigtable.v2.MutateRowsResponse; +import com.google.bigtable.v2.ReadModifyWriteRowRequest; +import com.google.bigtable.v2.ReadModifyWriteRowResponse; +import com.google.bigtable.v2.ReadRowsRequest; +import com.google.bigtable.v2.ReadRowsResponse; +import com.google.bigtable.v2.SampleRowKeysRequest; +import com.google.bigtable.v2.SampleRowKeysResponse; +import com.google.cloud.bigtable.data.v2.BigtableDataClient; +import com.google.cloud.bigtable.data.v2.BigtableDataSettings; +import com.google.cloud.bigtable.data.v2.internal.NameUtil; +import com.google.cloud.bigtable.data.v2.models.*; +import com.google.cloud.bigtable.data.v2.models.Mutation; +import com.google.rpc.Status; +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.stub.StreamObserver; +import java.net.ServerSocket; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class HeadersTest { + private static final String PROJECT_ID = "fake-project"; + private static final String INSTANCE_ID = "fake-instance"; + private static final String TABLE_ID = "fake-table"; + private static final String TABLE_NAME = + NameUtil.formatTableName(PROJECT_ID, INSTANCE_ID, TABLE_ID); + private static final String APP_PROFILE_ID = "fake-profile"; + + private static final Metadata.Key X_GOOG_REQUEST_PARAMS_KEY = + Metadata.Key.of("x-goog-request-params", Metadata.ASCII_STRING_MARSHALLER); + private static final Metadata.Key API_CLIENT_HEADER_KEY = + Metadata.Key.of("x-goog-api-client", Metadata.ASCII_STRING_MARSHALLER); + + private Server server; + private BlockingQueue sentMetadata = new ArrayBlockingQueue<>(10); + + private BigtableDataClient client; + + @Before + public void setUp() throws Exception { + int port; + try (ServerSocket ss = new ServerSocket(0)) { + port = ss.getLocalPort(); + } + server = + ServerBuilder.forPort(port) + .addService(new FakeBigtableService()) + .intercept(new MetadataInterceptor()) + .build(); + server.start(); + + BigtableDataSettings.Builder settings = + BigtableDataSettings.newBuilderForEmulator(port) + .setProjectId(PROJECT_ID) + .setInstanceId(INSTANCE_ID) + .setAppProfileId(APP_PROFILE_ID); + + // Force immediate flush + settings + .stubSettings() + .bulkMutateRowsSettings() + .setBatchingSettings( + settings + .stubSettings() + .bulkMutateRowsSettings() + .getBatchingSettings() + .toBuilder() + .setElementCountThreshold(1L) + .build()); + + client = BigtableDataClient.create(settings.build()); + } + + @After + public void tearDown() throws Exception { + client.close(); + server.shutdown(); + } + + @Test + public void readRowsTest() { + client.readRows(Query.create(TABLE_ID)); + verifyHeaderSent(); + } + + @Test + public void sampleRowKeysTest() { + client.sampleRowKeysAsync(TABLE_ID); + verifyHeaderSent(); + } + + @Test + public void mutateRowTest() { + client.mutateRowAsync(RowMutation.create(TABLE_ID, "fake-key").deleteRow()); + verifyHeaderSent(); + } + + @Test + public void mutateRowsTest() throws InterruptedException { + try (Batcher batcher = client.newBulkMutationBatcher(TABLE_ID)) { + batcher.add(RowMutationEntry.create("fake-key").deleteRow()); + } catch (RuntimeException e) { + // Ignore the errors: none of the methods are actually implemented + } + verifyHeaderSent(); + } + + @Test + public void checkAndMutateRowTest() { + client.checkAndMutateRowAsync( + ConditionalRowMutation.create(TABLE_ID, "fake-key").then(Mutation.create().deleteRow())); + verifyHeaderSent(); + } + + @Test + public void readModifyWriteTest() { + client.readModifyWriteRowAsync( + ReadModifyWriteRow.create(TABLE_ID, "fake-key").increment("cf", "q", 1)); + verifyHeaderSent(); + } + + private void verifyHeaderSent() { + Metadata metadata; + try { + metadata = sentMetadata.take(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + + String requestParamsvalue = metadata.get(X_GOOG_REQUEST_PARAMS_KEY); + assertThat(requestParamsvalue).containsMatch("(^|.*&)table_name=" + TABLE_NAME + "($|&.*)"); + assertThat(requestParamsvalue) + .containsMatch("(^|.*&)app_profile_id=" + APP_PROFILE_ID + "($|&.*)"); + + String apiClientValue = metadata.get(API_CLIENT_HEADER_KEY); + assertThat(apiClientValue).containsMatch("gl-java/[.\\d_]+"); + assertThat(apiClientValue).containsMatch("gax/[.\\d_]+"); + assertThat(apiClientValue).containsMatch("grpc/[.\\d_]+"); + } + + private class MetadataInterceptor implements ServerInterceptor { + @Override + public ServerCall.Listener interceptCall( + ServerCall serverCall, + Metadata metadata, + ServerCallHandler serverCallHandler) { + sentMetadata.add(metadata); + + return serverCallHandler.startCall(serverCall, metadata); + } + } + + private static class FakeBigtableService extends BigtableGrpc.BigtableImplBase { + @Override + public void readRows( + ReadRowsRequest request, StreamObserver responseObserver) { + responseObserver.onCompleted(); + } + + @Override + public void sampleRowKeys( + SampleRowKeysRequest request, StreamObserver responseObserver) { + responseObserver.onCompleted(); + } + + @Override + public void mutateRow( + MutateRowRequest request, StreamObserver responseObserver) { + responseObserver.onNext(MutateRowResponse.getDefaultInstance()); + responseObserver.onCompleted(); + } + + @Override + public void mutateRows( + MutateRowsRequest request, StreamObserver responseObserver) { + responseObserver.onNext( + MutateRowsResponse.newBuilder() + .addEntries( + MutateRowsResponse.Entry.newBuilder() + .setIndex(0) + .setStatus(Status.getDefaultInstance())) + .build()); + responseObserver.onCompleted(); + } + + @Override + public void checkAndMutateRow( + CheckAndMutateRowRequest request, + StreamObserver responseObserver) { + responseObserver.onNext(CheckAndMutateRowResponse.getDefaultInstance()); + } + + @Override + public void readModifyWriteRow( + ReadModifyWriteRowRequest request, + StreamObserver responseObserver) { + responseObserver.onNext(ReadModifyWriteRowResponse.getDefaultInstance()); + responseObserver.onCompleted(); + } + } +} diff --git a/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/stub/ResourceHeaderTest.java b/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/stub/ResourceHeaderTest.java deleted file mode 100644 index 85c8254ce..000000000 --- a/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/stub/ResourceHeaderTest.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * 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.data.v2.stub; - -import static com.google.common.truth.Truth.assertWithMessage; - -import com.google.api.gax.batching.Batcher; -import com.google.api.gax.core.NoCredentialsProvider; -import com.google.api.gax.grpc.testing.InProcessServer; -import com.google.api.gax.grpc.testing.LocalChannelProvider; -import com.google.api.gax.rpc.FixedHeaderProvider; -import com.google.bigtable.v2.BigtableGrpc; -import com.google.cloud.bigtable.data.v2.BigtableDataClient; -import com.google.cloud.bigtable.data.v2.BigtableDataSettings; -import com.google.cloud.bigtable.data.v2.internal.NameUtil; -import com.google.cloud.bigtable.data.v2.models.ConditionalRowMutation; -import com.google.cloud.bigtable.data.v2.models.Mutation; -import com.google.cloud.bigtable.data.v2.models.Query; -import com.google.cloud.bigtable.data.v2.models.ReadModifyWriteRow; -import com.google.cloud.bigtable.data.v2.models.RowMutation; -import com.google.cloud.bigtable.data.v2.models.RowMutationEntry; -import java.util.regex.Pattern; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -@RunWith(JUnit4.class) -public class ResourceHeaderTest { - private static final String PROJECT_ID = "fake-project"; - private static final String INSTANCE_ID = "fake-instance"; - private static final String TABLE_ID = "fake-table"; - private static final String TABLE_NAME = - NameUtil.formatTableName(PROJECT_ID, INSTANCE_ID, TABLE_ID); - private static final String APP_PROFILE_ID = "fake-profile"; - - private static final String CHANNEL_NAME = "resource-header-test:123"; - private static final String X_GOOG_REQUEST_PARAMS_KEY = "x-goog-request-params"; - private static final String TEST_HEADER_KEY = "simple-header-name"; - private static final String TEST_HEADER_VALUE = "simple-header-value"; - - private InProcessServer server; - private LocalChannelProvider channelProvider; - private BigtableDataClient client; - - @Before - public void setUp() throws Exception { - server = new InProcessServer<>(new BigtableGrpc.BigtableImplBase() {}, CHANNEL_NAME); - server.start(); - channelProvider = LocalChannelProvider.create(CHANNEL_NAME); - - BigtableDataSettings.Builder settings = - BigtableDataSettings.newBuilder() - .setProjectId(PROJECT_ID) - .setInstanceId(INSTANCE_ID) - .setAppProfileId(APP_PROFILE_ID) - .setCredentialsProvider(NoCredentialsProvider.create()); - - settings - .stubSettings() - .setTransportChannelProvider(channelProvider) - .setHeaderProvider(FixedHeaderProvider.create(TEST_HEADER_KEY, TEST_HEADER_VALUE)); - - // Force immediate flush - settings - .stubSettings() - .bulkMutateRowsSettings() - .setBatchingSettings( - settings - .stubSettings() - .bulkMutateRowsSettings() - .getBatchingSettings() - .toBuilder() - .setElementCountThreshold(1L) - .build()); - - client = BigtableDataClient.create(settings.build()); - } - - @After - public void tearDown() throws Exception { - client.close(); - server.stop(); - server.blockUntilShutdown(); - } - - @Test - public void readRowsTest() { - client.readRows(Query.create(TABLE_ID)); - verifyHeaderSent(); - } - - @Test - public void sampleRowKeysTest() { - client.sampleRowKeysAsync(TABLE_ID); - verifyHeaderSent(); - } - - @Test - public void mutateRowTest() { - client.mutateRowAsync(RowMutation.create(TABLE_ID, "fake-key").deleteRow()); - verifyHeaderSent(); - } - - @Test - public void mutateRowsTest() throws InterruptedException { - try (Batcher batcher = client.newBulkMutationBatcher(TABLE_ID)) { - batcher.add(RowMutationEntry.create("fake-key").deleteRow()); - } catch (RuntimeException e) { - // Ignore the errors: none of the methods are actually implemented - } - verifyHeaderSent(); - } - - @Test - public void checkAndMutateRowTest() { - client.checkAndMutateRowAsync( - ConditionalRowMutation.create(TABLE_ID, "fake-key").then(Mutation.create().deleteRow())); - verifyHeaderSent(); - } - - @Test - public void readModifyWriteTest() { - client.readModifyWriteRowAsync( - ReadModifyWriteRow.create(TABLE_ID, "fake-key").increment("cf", "q", 1)); - verifyHeaderSent(); - } - - private void verifyHeaderSent() { - boolean tableHeaderSent = - channelProvider.isHeaderSent( - X_GOOG_REQUEST_PARAMS_KEY, - Pattern.compile("(^|.*&)table_name=" + TABLE_NAME + "($|&.*)")); - assertWithMessage("Tablename header was sent").that(tableHeaderSent).isTrue(); - - boolean appProfileHeaderSent = - channelProvider.isHeaderSent( - X_GOOG_REQUEST_PARAMS_KEY, - Pattern.compile("(^|.*&)app_profile_id=" + APP_PROFILE_ID + "($|&.*)")); - assertWithMessage("App profile header was sent").that(appProfileHeaderSent).isTrue(); - - boolean testHeader = - channelProvider.isHeaderSent( - TEST_HEADER_KEY, Pattern.compile("^" + TEST_HEADER_VALUE + "$")); - assertWithMessage("HeaderProvider's header received in Channel").that(testHeader).isTrue(); - } -}