From 8e7b92f93724d2ea9b3baf27257b02c3784aa6fc Mon Sep 17 00:00:00 2001 From: summerji Date: Fri, 12 Jun 2020 17:35:52 -0700 Subject: [PATCH 01/10] Enable Quota Project ID in Client setting --- .../google/api/gax/rpc/ClientSettings.java | 16 ++ .../com/google/api/gax/rpc/StubSettings.java | 41 ++++ .../api/gax/rpc/ClientSettingsTest.java | 184 ++++++++++++++++++ 3 files changed, 241 insertions(+) diff --git a/gax/src/main/java/com/google/api/gax/rpc/ClientSettings.java b/gax/src/main/java/com/google/api/gax/rpc/ClientSettings.java index 13b733641..88bc7af8a 100644 --- a/gax/src/main/java/com/google/api/gax/rpc/ClientSettings.java +++ b/gax/src/main/java/com/google/api/gax/rpc/ClientSettings.java @@ -93,6 +93,10 @@ public final String getEndpoint() { return stubSettings.getEndpoint(); } + public final String getQuotaProjectID() { + return stubSettings.getQuotaProjectID(); + } + @BetaApi("The surface for streaming is not stable yet and may change in the future.") @Nullable public final WatchdogProvider getWatchdogProvider() { @@ -114,6 +118,7 @@ public String toString() { .add("internalHeaderProvider", getInternalHeaderProvider()) .add("clock", getClock()) .add("endpoint", getEndpoint()) + .add("quotaProjectID", getQuotaProjectID()) .add("watchdogProvider", getWatchdogProvider()) .add("watchdogCheckInterval", getWatchdogCheckInterval()) .toString(); @@ -216,6 +221,11 @@ public B setEndpoint(String endpoint) { return self(); } + public B setQuotaProjectID(String quotaProjectID) { + stubSettings.setQuotaProjectID(quotaProjectID); + return self(); + } + @BetaApi("The surface for streaming is not stable yet and may change in the future.") public B setWatchdogProvider(@Nullable WatchdogProvider watchdogProvider) { stubSettings.setStreamWatchdogProvider(watchdogProvider); @@ -264,6 +274,11 @@ public String getEndpoint() { return stubSettings.getEndpoint(); } + /** Gets the QuotaProjectID that was previously set on this Builder. */ + public String getQuotaProjectID() { + return stubSettings.getQuotaProjectID(); + } + @BetaApi("The surface for streaming is not stable yet and may change in the future.") @Nullable public WatchdogProvider getWatchdogProvider() { @@ -294,6 +309,7 @@ public String toString() { .add("internalHeaderProvider", getInternalHeaderProvider()) .add("clock", getClock()) .add("endpoint", getEndpoint()) + .add("quotaProjectID", getQuotaProjectID()) .add("watchdogProvider", getWatchdogProvider()) .add("watchdogCheckInterval", getWatchdogCheckInterval()) .toString(); diff --git a/gax/src/main/java/com/google/api/gax/rpc/StubSettings.java b/gax/src/main/java/com/google/api/gax/rpc/StubSettings.java index 2cac53602..15c0abf7c 100644 --- a/gax/src/main/java/com/google/api/gax/rpc/StubSettings.java +++ b/gax/src/main/java/com/google/api/gax/rpc/StubSettings.java @@ -41,6 +41,8 @@ import com.google.api.gax.core.NoCredentialsProvider; import com.google.api.gax.tracing.ApiTracerFactory; import com.google.api.gax.tracing.NoopApiTracerFactory; +import com.google.auth.Credentials; +import com.google.auth.oauth2.QuotaProjectIdProvider; import com.google.common.base.MoreObjects; import com.google.common.base.Preconditions; import java.io.IOException; @@ -60,6 +62,8 @@ */ public abstract class StubSettings> { + static final String QUOTA_PROJECT_ID_HEADER_KEY = "x-google-user-project"; + private final ExecutorProvider executorProvider; private final CredentialsProvider credentialsProvider; private final HeaderProvider headerProvider; @@ -67,6 +71,7 @@ public abstract class StubSettings> { private final TransportChannelProvider transportChannelProvider; private final ApiClock clock; private final String endpoint; + private final String quotaProjectID; @Nullable private final WatchdogProvider streamWatchdogProvider; @Nonnull private final Duration streamWatchdogCheckInterval; @Nonnull private final ApiTracerFactory tracerFactory; @@ -80,6 +85,7 @@ protected StubSettings(Builder builder) { this.internalHeaderProvider = builder.internalHeaderProvider; this.clock = builder.clock; this.endpoint = builder.endpoint; + this.quotaProjectID = builder.quotaProjectID; this.streamWatchdogProvider = builder.streamWatchdogProvider; this.streamWatchdogCheckInterval = builder.streamWatchdogCheckInterval; this.tracerFactory = builder.tracerFactory; @@ -115,6 +121,10 @@ public final String getEndpoint() { return endpoint; } + public final String getQuotaProjectID() { + return quotaProjectID; + } + @BetaApi("The surface for streaming is not stable yet and may change in the future.") @Nullable public final WatchdogProvider getStreamWatchdogProvider() { @@ -146,6 +156,7 @@ public String toString() { .add("internalHeaderProvider", internalHeaderProvider) .add("clock", clock) .add("endpoint", endpoint) + .add("quotaProjectID", quotaProjectID) .add("streamWatchdogProvider", streamWatchdogProvider) .add("streamWatchdogCheckInterval", streamWatchdogCheckInterval) .add("tracerFactory", tracerFactory) @@ -164,6 +175,7 @@ public abstract static class Builder< private TransportChannelProvider transportChannelProvider; private ApiClock clock; private String endpoint; + private String quotaProjectID; @Nullable private WatchdogProvider streamWatchdogProvider; @Nonnull private Duration streamWatchdogCheckInterval; @Nonnull private ApiTracerFactory tracerFactory; @@ -177,6 +189,7 @@ protected Builder(StubSettings settings) { this.internalHeaderProvider = settings.internalHeaderProvider; this.clock = settings.clock; this.endpoint = settings.endpoint; + this.quotaProjectID = settings.quotaProjectID; this.streamWatchdogProvider = settings.streamWatchdogProvider; this.streamWatchdogCheckInterval = settings.streamWatchdogCheckInterval; this.tracerFactory = settings.tracerFactory; @@ -191,6 +204,7 @@ protected Builder(ClientContext clientContext) { this.internalHeaderProvider = new NoHeaderProvider(); this.clock = NanoClock.getDefaultClock(); this.endpoint = null; + this.quotaProjectID = null; this.streamWatchdogProvider = InstantiatingWatchdogProvider.create(); this.streamWatchdogCheckInterval = Duration.ofSeconds(10); this.tracerFactory = NoopApiTracerFactory.getInstance(); @@ -234,6 +248,14 @@ public B setExecutorProvider(ExecutorProvider executorProvider) { /** Sets the CredentialsProvider to use for getting the credentials to make calls with. */ public B setCredentialsProvider(CredentialsProvider credentialsProvider) { this.credentialsProvider = Preconditions.checkNotNull(credentialsProvider); + try { + Credentials credentials = credentialsProvider.getCredentials(); + if (this.quotaProjectID == null && credentials instanceof QuotaProjectIdProvider) { + this.quotaProjectID = ((QuotaProjectIdProvider) credentials).getQuotaProjectId(); + } + } catch (IOException e) { + System.out.println("fail to fetch credentials"); + } return self(); } @@ -247,6 +269,10 @@ public B setCredentialsProvider(CredentialsProvider credentialsProvider) { @BetaApi("The surface for customizing headers is not stable yet and may change in the future.") public B setHeaderProvider(HeaderProvider headerProvider) { this.headerProvider = headerProvider; + if (this.quotaProjectID == null + && headerProvider.getHeaders().containsKey(QUOTA_PROJECT_ID_HEADER_KEY)) { + this.quotaProjectID = headerProvider.getHeaders().get(QUOTA_PROJECT_ID_HEADER_KEY); + } return self(); } @@ -260,6 +286,10 @@ public B setHeaderProvider(HeaderProvider headerProvider) { @BetaApi("The surface for customizing headers is not stable yet and may change in the future.") protected B setInternalHeaderProvider(HeaderProvider internalHeaderProvider) { this.internalHeaderProvider = internalHeaderProvider; + if (this.quotaProjectID == null + && internalHeaderProvider.getHeaders().containsKey(QUOTA_PROJECT_ID_HEADER_KEY)) { + this.quotaProjectID = internalHeaderProvider.getHeaders().get(QUOTA_PROJECT_ID_HEADER_KEY); + } return self(); } @@ -298,6 +328,11 @@ public B setEndpoint(String endpoint) { return self(); } + public B setQuotaProjectID(String quotaProjectID) { + this.quotaProjectID = quotaProjectID; + return self(); + } + /** * Sets how often the {@link Watchdog} will check ongoing streaming RPCs. Defaults to 10 secs. * Use {@link Duration#ZERO} to disable. @@ -364,6 +399,11 @@ public String getEndpoint() { return endpoint; } + /** Gets the QuotaProjectID that was previously set on this Builder. */ + public String getQuotaProjectID() { + return quotaProjectID; + } + @BetaApi("The surface for streaming is not stable yet and may change in the future.") @Nonnull public Duration getStreamWatchdogCheckInterval() { @@ -396,6 +436,7 @@ public String toString() { .add("internalHeaderProvider", internalHeaderProvider) .add("clock", clock) .add("endpoint", endpoint) + .add("quotaProjectID", quotaProjectID) .add("streamWatchdogProvider", streamWatchdogProvider) .add("streamWatchdogCheckInterval", streamWatchdogCheckInterval) .add("tracerFactory", tracerFactory) diff --git a/gax/src/test/java/com/google/api/gax/rpc/ClientSettingsTest.java b/gax/src/test/java/com/google/api/gax/rpc/ClientSettingsTest.java index ee490107d..e182ccadf 100644 --- a/gax/src/test/java/com/google/api/gax/rpc/ClientSettingsTest.java +++ b/gax/src/test/java/com/google/api/gax/rpc/ClientSettingsTest.java @@ -29,6 +29,8 @@ */ package com.google.api.gax.rpc; +import static org.junit.Assert.fail; + import com.google.api.core.ApiClock; import com.google.api.core.ApiFunction; import com.google.api.core.NanoClock; @@ -41,7 +43,11 @@ import com.google.api.gax.rpc.testing.FakeCallContext; import com.google.api.gax.rpc.testing.FakeClientSettings; import com.google.auth.Credentials; +import com.google.auth.oauth2.GoogleCredentials; import com.google.common.truth.Truth; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -69,6 +75,7 @@ public void testEmptyBuilder() throws Exception { Truth.assertThat(builder.getWatchdogProvider()) .isInstanceOf(InstantiatingWatchdogProvider.class); Truth.assertThat(builder.getWatchdogCheckInterval()).isGreaterThan(Duration.ZERO); + Truth.assertThat(builder.getQuotaProjectID()).isNull(); FakeClientSettings settings = builder.build(); Truth.assertThat(settings.getExecutorProvider()) @@ -84,6 +91,7 @@ public void testEmptyBuilder() throws Exception { Truth.assertThat(settings.getWatchdogProvider()) .isInstanceOf(InstantiatingWatchdogProvider.class); Truth.assertThat(settings.getWatchdogCheckInterval()).isGreaterThan(Duration.ZERO); + Truth.assertThat((settings.getQuotaProjectID())).isSameInstanceAs(builder.getQuotaProjectID()); String settingsString = settings.toString(); Truth.assertThat(settingsString).contains("executorProvider"); @@ -93,6 +101,7 @@ public void testEmptyBuilder() throws Exception { Truth.assertThat(settingsString).contains("headerProvider"); Truth.assertThat(settingsString).contains("watchdogProvider"); Truth.assertThat(settingsString).contains("watchdogCheckInterval"); + Truth.assertThat(settingsString).contains(("quotaProjectID")); } @Test @@ -107,6 +116,7 @@ public void testBuilder() throws Exception { HeaderProvider internalHeaderProvider = Mockito.mock(HeaderProvider.class); WatchdogProvider watchdogProvider = Mockito.mock(WatchdogProvider.class); Duration watchdogCheckInterval = Duration.ofSeconds(13); + String quotaProjectID = "test_quota_project_id"; builder.setExecutorProvider(executorProvider); builder.setTransportChannelProvider(transportProvider); @@ -116,6 +126,7 @@ public void testBuilder() throws Exception { builder.setClock(clock); builder.setWatchdogProvider(watchdogProvider); builder.setWatchdogCheckInterval(watchdogCheckInterval); + builder.setQuotaProjectID(quotaProjectID); Truth.assertThat(builder.getExecutorProvider()).isSameInstanceAs(executorProvider); Truth.assertThat(builder.getTransportChannelProvider()).isSameInstanceAs(transportProvider); @@ -125,6 +136,7 @@ public void testBuilder() throws Exception { Truth.assertThat(builder.getInternalHeaderProvider()).isSameInstanceAs(internalHeaderProvider); Truth.assertThat(builder.getWatchdogProvider()).isSameInstanceAs(watchdogProvider); Truth.assertThat(builder.getWatchdogCheckInterval()).isSameInstanceAs(watchdogCheckInterval); + Truth.assertThat(builder.getQuotaProjectID()).isEqualTo(quotaProjectID); String builderString = builder.toString(); Truth.assertThat(builderString).contains("executorProvider"); @@ -135,6 +147,7 @@ public void testBuilder() throws Exception { Truth.assertThat(builderString).contains("internalHeaderProvider"); Truth.assertThat(builderString).contains("watchdogProvider"); Truth.assertThat(builderString).contains("watchdogCheckInterval"); + Truth.assertThat(builderString).contains("quotaProjectID"); } @Test @@ -187,6 +200,7 @@ public void testBuilderFromSettings() throws Exception { HeaderProvider internalHeaderProvider = Mockito.mock(HeaderProvider.class); WatchdogProvider watchdogProvider = Mockito.mock(WatchdogProvider.class); Duration watchdogCheckInterval = Duration.ofSeconds(14); + String quotaProjectID = "test_builder_from_settings_quotaProjectID"; builder.setExecutorProvider(executorProvider); builder.setTransportChannelProvider(transportProvider); @@ -196,6 +210,7 @@ public void testBuilderFromSettings() throws Exception { builder.setInternalHeaderProvider(internalHeaderProvider); builder.setWatchdogProvider(watchdogProvider); builder.setWatchdogCheckInterval(watchdogCheckInterval); + builder.setQuotaProjectID(quotaProjectID); FakeClientSettings settings = builder.build(); FakeClientSettings.Builder newBuilder = new FakeClientSettings.Builder(settings); @@ -209,6 +224,7 @@ public void testBuilderFromSettings() throws Exception { .isSameInstanceAs(internalHeaderProvider); Truth.assertThat(newBuilder.getWatchdogProvider()).isSameInstanceAs(watchdogProvider); Truth.assertThat(newBuilder.getWatchdogCheckInterval()).isEqualTo(watchdogCheckInterval); + Truth.assertThat(newBuilder.getQuotaProjectID()).isEqualTo(quotaProjectID); } @Test @@ -238,4 +254,172 @@ public Void apply(UnaryCallSettings.Builder input) { Truth.assertThat(builders.get(1).getRetryableCodes()) .containsExactly(StatusCode.Code.DEADLINE_EXCEEDED); } + + static GoogleCredentials loadCredentials(String credentialFile) { + try { + InputStream keyStream = new ByteArrayInputStream(credentialFile.getBytes()); + return GoogleCredentials.fromStream(keyStream); + } catch (IOException e) { + fail("Couldn't create fake JSON credentials."); + } + return null; + } + + @Test + public void testBuilderQuotaProjectID() { + final String QUOTA_PROJECT_ID_KEY = "x-google-user-project"; + final String QUOTA_PROJECT_ID_FROM_HEADER_VALUE = "quota_project_id_from_headers"; + final String QUOTA_PROJECT_ID_FROM_BUILDERS = "quota_project_id_from_builders"; + final String QUOTA_PROJECT_ID_FROM_INTERNAL_HEADER_VALUE = + "quota_project_id_from_internal_headers"; + final String QUOTA_PROJECT_ID_FROM_CREDENTIALS_VALUE = "quota_project_id_from_credentials"; + final String JSON_KEY_QUOTA_PROJECT_ID = + "{\n" + + " \"private_key_id\": \"somekeyid\",\n" + + " \"private_key\": \"-----BEGIN PRIVATE KEY-----\\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggS" + + "kAgEAAoIBAQC+K2hSuFpAdrJI\\nnCgcDz2M7t7bjdlsadsasad+fvRSW6TjNQZ3p5LLQY1kSZRqBqylRkzteMOyHg" + + "aR\\n0Pmxh3ILCND5men43j3h4eDbrhQBuxfEMalkG92sL+PNQSETY2tnvXryOvmBRwa/\\nQP/9dJfIkIDJ9Fw9N4" + + "Bhhhp6mCcRpdQjV38H7JsyJ7lih/oNjECgYAt\\nknddadwkwewcVxHFhcZJO+XWf6ofLUXpRwiTZakGMn8EE1uVa2" + + "LgczOjwWHGi99MFjxSer5m9\\n1tCa3/KEGKiS/YL71JvjwX3mb+cewlkcmweBKZHM2JPTk0ZednFSpVZMtycjkbLa" + + "\\ndYOS8V85AgMBewECggEBAKksaldajfDZDV6nGqbFjMiizAKJolr/M3OQw16K6o3/\\n0S31xIe3sSlgW0+UbYlF" + + "4U8KifhManD1apVSC3csafaspP4RZUHFhtBywLO9pR5c\\nr6S5aLp+gPWFyIp1pfXbWGvc5VY/v9x7ya1VEa6rXvL" + + "sKupSeWAW4tMj3eo/64ge\\nsdaceaLYw52KeBYiT6+vpsnYrEkAHO1fF/LavbLLOFJmFTMxmsNaG0tuiJHgjshB\\" + + "n82DpMCbXG9YcCgI/DbzuIjsdj2JC1cascSP//3PmefWysucBQe7Jryb6NQtASmnv\\nCdDw/0jmZTEjpe4S1lxfHp" + + "lAhHFtdgYTvyYtaLZiVVkCgYEA8eVpof2rceecw/I6\\n5ng1q3Hl2usdWV/4mZMvR0fOemacLLfocX6IYxT1zA1FF" + + "JlbXSRsJMf/Qq39mOR2\\nSpW+hr4jCoHeRVYLgsbggtrevGmILAlNoqCMpGZ6vDmJpq6ECV9olliDvpPgWOP+\\nm" + + "YPDreFBGxWvQrADNbRt2dmGsrsCgYEAyUHqB2wvJHFqdmeBsaacewzV8x9WgmeX\\ngUIi9REwXlGDW0Mz50dxpxcK" + + "CAYn65+7TCnY5O/jmL0VRxU1J2mSWyWTo1C+17L0\\n3fUqjxL1pkefwecxwecvC+gFFYdJ4CQ/MHHXU81Lwl1iWdF" + + "Cd2UoGddYaOF+KNeM\\nHC7cmqra+JsCgYEAlUNywzq8nUg7282E+uICfCB0LfwejuymR93CtsFgb7cRd6ak\\nECR" + + "8FGfCpH8ruWJINllbQfcHVCX47ndLZwqv3oVFKh6pAS/vVI4dpOepP8++7y1u\\ncoOvtreXCX6XqfrWDtKIvv0vjl" + + "HBhhhp6mCcRpdQjV38H7JsyJ7lih/oNjECgYAt\\nkndj5uNl5SiuVxHFhcZJO+XWf6ofLUregtevZakGMn8EE1uVa" + + "2AY7eafmoU/nZPT\\n00YB0TBATdCbn/nBSuKDESkhSg9s2GEKQZG5hBmL5uCMfo09z3SfxZIhJdlerreP\\nJ7gSi" + + "dI12N+EZxYd4xIJh/HFDgp7RRO87f+WJkofMQKBgGTnClK1VMaCRbJZPriw\\nEfeFCoOX75MxKwXs6xgrw4W//AYG" + + "GUjDt83lD6AZP6tws7gJ2IwY/qP7+lyhjEqN\\nHtfPZRGFkGZsdaksdlaksd323423d+15/UvrlRSFPNj1tWQmNKk" + + "XyRDW4IG1Oa2p\\nrALStNBx5Y9t0/LQnFI4w3aG\\n-----END PRIVATE KEY-----\\n\",\n" + + " \"project_id\": \"someprojectid\",\n" + + " \"client_email\": \"someclientid@developer.gserviceaccount.com\",\n" + + " \"client_id\": \"someclientid.apps.googleusercontent.com\",\n" + + " \"type\": \"service_account\",\n" + + " \"quota_project_id\": \"" + + QUOTA_PROJECT_ID_FROM_CREDENTIALS_VALUE + + "\"\n" + + "}"; + + final GoogleCredentials credentialsWithQuotaProject = + loadCredentials(JSON_KEY_QUOTA_PROJECT_ID); + + CredentialsProvider credentialsProvider_no_quota = Mockito.mock(CredentialsProvider.class); + HeaderProvider headerProvider_no_quota = Mockito.mock(HeaderProvider.class); + HeaderProvider internalHeaderProvider_no_quota = Mockito.mock(HeaderProvider.class); + HeaderProvider headerProvider_with_quota = + new HeaderProvider() { + @Override + public Map getHeaders() { + return Collections.singletonMap( + QUOTA_PROJECT_ID_KEY, QUOTA_PROJECT_ID_FROM_HEADER_VALUE); + } + }; + HeaderProvider internalHeaderProvider_with_quota = + new HeaderProvider() { + @Override + public Map getHeaders() { + return Collections.singletonMap( + QUOTA_PROJECT_ID_KEY, QUOTA_PROJECT_ID_FROM_INTERNAL_HEADER_VALUE); + } + }; + CredentialsProvider credentialsProvider_with_quota = + new CredentialsProvider() { + @Override + public Credentials getCredentials() throws IOException { + return credentialsWithQuotaProject; + } + }; + + // Case for setting quota_project_id from builder only + // expect value is from builders + FakeClientSettings.Builder builder_setQuotaOnly = new FakeClientSettings.Builder(); + builder_setQuotaOnly.setCredentialsProvider(credentialsProvider_no_quota); + builder_setQuotaOnly.setHeaderProvider(headerProvider_no_quota); + builder_setQuotaOnly.setInternalHeaderProvider(internalHeaderProvider_no_quota); + builder_setQuotaOnly.setQuotaProjectID(QUOTA_PROJECT_ID_FROM_BUILDERS); + + // Case for setting quota_project_id from HeaderProvider Only + // expect value is from HeaderProvider + FakeClientSettings.Builder builder_setQuotaFromHeadersOnly = new FakeClientSettings.Builder(); + builder_setQuotaFromHeadersOnly.setHeaderProvider(headerProvider_with_quota); + + // Case for setting quota_project_id from HeaderProvider and set from builders + // expect value is from builders + FakeClientSettings.Builder builder_setQuotaFromHeadersAndBuilders = + new FakeClientSettings.Builder(); + builder_setQuotaFromHeadersOnly.setHeaderProvider(headerProvider_with_quota); + builder_setQuotaFromHeadersAndBuilders.setQuotaProjectID(QUOTA_PROJECT_ID_FROM_BUILDERS); + + // Case for setting quota_project_id from InternalHeaderProvider and set from builders + // expect value is from InternalHeaderProvider + FakeClientSettings.Builder builder_setQuotaFromInternalHeadersOnly = + new FakeClientSettings.Builder(); + builder_setQuotaFromInternalHeadersOnly.setInternalHeaderProvider( + internalHeaderProvider_with_quota); + + // Case for setting quota_project_id from InternalHeaderProvider and set from builders + // expect value is from builders + FakeClientSettings.Builder builder_setQuotaFromInternalHeadersAndBuilders = + new FakeClientSettings.Builder(); + builder_setQuotaFromInternalHeadersAndBuilders.setInternalHeaderProvider( + internalHeaderProvider_with_quota); + builder_setQuotaFromInternalHeadersAndBuilders.setQuotaProjectID( + QUOTA_PROJECT_ID_FROM_BUILDERS); + + // Case for setting quota_project_id from CredentialProvider Only + // expect value is from CredentialProvider + FakeClientSettings.Builder builder_setQuotaFromCredentialsProvider = + new FakeClientSettings.Builder(); + builder_setQuotaFromCredentialsProvider.setCredentialsProvider(credentialsProvider_with_quota); + + // Case for setting quota_project_id from CredentialProvider and Builders + // expect value is from builders + FakeClientSettings.Builder builder_setQuotaFromCredentialsProviderAndBuilder = + new FakeClientSettings.Builder(); + builder_setQuotaFromCredentialsProviderAndBuilder.setCredentialsProvider( + credentialsProvider_with_quota); + builder_setQuotaFromCredentialsProviderAndBuilder.setQuotaProjectID( + QUOTA_PROJECT_ID_FROM_BUILDERS); + + // Case for setting quota_project_id from All three sources + // expect value is from builders + FakeClientSettings.Builder builder_setQuotaFromAllSources = new FakeClientSettings.Builder(); + builder_setQuotaFromAllSources.setHeaderProvider(headerProvider_with_quota); + builder_setQuotaFromAllSources.setInternalHeaderProvider(headerProvider_with_quota); + builder_setQuotaFromAllSources.setCredentialsProvider(credentialsProvider_with_quota); + builder_setQuotaFromAllSources.setQuotaProjectID(QUOTA_PROJECT_ID_FROM_BUILDERS); + + // Case for setting quota_project_id from All three sources but set from builders first + // expect value is from builders + FakeClientSettings.Builder builder_setQuotaFromAllSourcesOrder = + new FakeClientSettings.Builder(); + builder_setQuotaFromAllSourcesOrder.setQuotaProjectID(QUOTA_PROJECT_ID_FROM_BUILDERS); + builder_setQuotaFromAllSourcesOrder.setHeaderProvider(headerProvider_with_quota); + builder_setQuotaFromAllSourcesOrder.setInternalHeaderProvider(headerProvider_with_quota); + builder_setQuotaFromAllSourcesOrder.setCredentialsProvider(credentialsProvider_with_quota); + + Truth.assertThat(builder_setQuotaOnly.getQuotaProjectID()) + .isEqualTo(QUOTA_PROJECT_ID_FROM_BUILDERS); + Truth.assertThat(builder_setQuotaFromHeadersOnly.getQuotaProjectID()) + .isEqualTo(QUOTA_PROJECT_ID_FROM_HEADER_VALUE); + Truth.assertThat(builder_setQuotaFromHeadersAndBuilders.getQuotaProjectID()) + .isEqualTo(QUOTA_PROJECT_ID_FROM_BUILDERS); + Truth.assertThat((builder_setQuotaFromInternalHeadersOnly).getQuotaProjectID()) + .isEqualTo(QUOTA_PROJECT_ID_FROM_INTERNAL_HEADER_VALUE); + Truth.assertThat(builder_setQuotaFromInternalHeadersAndBuilders.getQuotaProjectID()) + .isEqualTo(QUOTA_PROJECT_ID_FROM_BUILDERS); + Truth.assertThat(builder_setQuotaFromCredentialsProvider.getQuotaProjectID()) + .isEqualTo(QUOTA_PROJECT_ID_FROM_CREDENTIALS_VALUE); + Truth.assertThat(builder_setQuotaFromCredentialsProviderAndBuilder.getQuotaProjectID()) + .isEqualTo(QUOTA_PROJECT_ID_FROM_BUILDERS); + Truth.assertThat(builder_setQuotaFromAllSources.getQuotaProjectID()) + .isEqualTo(QUOTA_PROJECT_ID_FROM_BUILDERS); + Truth.assertThat(builder_setQuotaFromAllSourcesOrder.getQuotaProjectID()) + .isEqualTo(QUOTA_PROJECT_ID_FROM_BUILDERS); + } } From c641572aa70da2f8d3ff670ae1b958dded0f2761 Mon Sep 17 00:00:00 2001 From: summerji Date: Mon, 15 Jun 2020 00:09:44 -0700 Subject: [PATCH 02/10] Add quota project Id in clientContext --- .../com/google/api/gax/rpc/ClientContext.java | 9 +- .../com/google/api/gax/rpc/StubSettings.java | 18 ++ .../api/gax/rpc/ClientSettingsTest.java | 192 ++++++++++++++---- 3 files changed, 177 insertions(+), 42 deletions(-) diff --git a/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java b/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java index 377ec730a..9791c53e2 100644 --- a/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java +++ b/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java @@ -96,6 +96,9 @@ public abstract class ClientContext { @Nullable public abstract String getEndpoint(); + @Nullable + public abstract String getQuotaProjectID(); + /** Gets the {@link ApiTracerFactory} that will be used to generate traces for operations. */ @BetaApi("The surface for tracing is not stable yet and may change in the future.") @Nonnull @@ -110,7 +113,8 @@ public static Builder newBuilder() { .setClock(NanoClock.getDefaultClock()) .setStreamWatchdog(null) .setStreamWatchdogCheckInterval(Duration.ZERO) - .setTracerFactory(NoopApiTracerFactory.getInstance()); + .setTracerFactory(NoopApiTracerFactory.getInstance()) + .setQuotaProjectID(null); } public abstract Builder toBuilder(); @@ -200,6 +204,7 @@ public static ClientContext create(StubSettings settings) throws IOException { .setClock(clock) .setDefaultCallContext(defaultCallContext) .setEndpoint(settings.getEndpoint()) + .setQuotaProjectID(settings.getQuotaProjectID()) .setStreamWatchdog(watchdog) .setStreamWatchdogCheckInterval(settings.getStreamWatchdogCheckInterval()) .setTracerFactory(settings.getTracerFactory()) @@ -229,6 +234,8 @@ public abstract static class Builder { public abstract Builder setEndpoint(String endpoint); + public abstract Builder setQuotaProjectID(String quotaProjectID); + @BetaApi("The surface for streaming is not stable yet and may change in the future.") public abstract Builder setStreamWatchdog(Watchdog watchdog); diff --git a/gax/src/main/java/com/google/api/gax/rpc/StubSettings.java b/gax/src/main/java/com/google/api/gax/rpc/StubSettings.java index 15c0abf7c..193cfc3b6 100644 --- a/gax/src/main/java/com/google/api/gax/rpc/StubSettings.java +++ b/gax/src/main/java/com/google/api/gax/rpc/StubSettings.java @@ -195,6 +195,23 @@ protected Builder(StubSettings settings) { this.tracerFactory = settings.tracerFactory; } + /** Get Quota Project ID from Client Context * */ + private static String getQuotaProjectIDFromClientContext(ClientContext clientContext) { + if (clientContext.getQuotaProjectID() != null) { + return clientContext.getQuotaProjectID(); + } + if (clientContext.getCredentials() instanceof QuotaProjectIdProvider) { + return ((QuotaProjectIdProvider) clientContext.getCredentials()).getQuotaProjectId(); + } + if (clientContext.getHeaders().containsKey(QUOTA_PROJECT_ID_HEADER_KEY)) { + return clientContext.getHeaders().get(QUOTA_PROJECT_ID_HEADER_KEY); + } + if (clientContext.getInternalHeaders().containsKey(QUOTA_PROJECT_ID_HEADER_KEY)) { + return clientContext.getInternalHeaders().get(QUOTA_PROJECT_ID_HEADER_KEY); + } + return null; + } + protected Builder(ClientContext clientContext) { if (clientContext == null) { this.executorProvider = InstantiatingExecutorProvider.newBuilder().build(); @@ -222,6 +239,7 @@ protected Builder(ClientContext clientContext) { FixedWatchdogProvider.create(clientContext.getStreamWatchdog()); this.streamWatchdogCheckInterval = clientContext.getStreamWatchdogCheckInterval(); this.tracerFactory = clientContext.getTracerFactory(); + this.quotaProjectID = getQuotaProjectIDFromClientContext(clientContext); } } diff --git a/gax/src/test/java/com/google/api/gax/rpc/ClientSettingsTest.java b/gax/src/test/java/com/google/api/gax/rpc/ClientSettingsTest.java index e182ccadf..8dc1c9ef2 100644 --- a/gax/src/test/java/com/google/api/gax/rpc/ClientSettingsTest.java +++ b/gax/src/test/java/com/google/api/gax/rpc/ClientSettingsTest.java @@ -44,6 +44,7 @@ import com.google.api.gax.rpc.testing.FakeClientSettings; import com.google.auth.Credentials; import com.google.auth.oauth2.GoogleCredentials; +import com.google.common.collect.ImmutableMap; import com.google.common.truth.Truth; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -61,6 +62,49 @@ @RunWith(JUnit4.class) public class ClientSettingsTest { + private static final String QUOTA_PROJECT_ID_KEY = "x-google-user-project"; + private static final String QUOTA_PROJECT_ID_FROM_HEADER_VALUE = "quota_project_id_from_headers"; + private static final String QUOTA_PROJECT_ID_FROM_BUILDERS = "quota_project_id_from_builders"; + private static final String QUOTA_PROJECT_ID_FROM_INTERNAL_HEADER_VALUE = + "quota_project_id_from_internal_headers"; + private static final String QUOTA_PROJECT_ID_FROM_CREDENTIALS_VALUE = + "quota_project_id_from_credentials"; + private static final String QUOTA_PROJECT_ID_FROM_CONTEXT = + "quota_project_id_from_client_context"; + private static final String JSON_KEY_QUOTA_PROJECT_ID = + "{\n" + + " \"private_key_id\": \"somekeyid\",\n" + + " \"private_key\": \"-----BEGIN PRIVATE KEY-----\\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggS" + + "kAgEAAoIBAQC+K2hSuFpAdrJI\\nnCgcDz2M7t7bjdlsadsasad+fvRSW6TjNQZ3p5LLQY1kSZRqBqylRkzteMOyHg" + + "aR\\n0Pmxh3ILCND5men43j3h4eDbrhQBuxfEMalkG92sL+PNQSETY2tnvXryOvmBRwa/\\nQP/9dJfIkIDJ9Fw9N4" + + "Bhhhp6mCcRpdQjV38H7JsyJ7lih/oNjECgYAt\\nknddadwkwewcVxHFhcZJO+XWf6ofLUXpRwiTZakGMn8EE1uVa2" + + "LgczOjwWHGi99MFjxSer5m9\\n1tCa3/KEGKiS/YL71JvjwX3mb+cewlkcmweBKZHM2JPTk0ZednFSpVZMtycjkbLa" + + "\\ndYOS8V85AgMBewECggEBAKksaldajfDZDV6nGqbFjMiizAKJolr/M3OQw16K6o3/\\n0S31xIe3sSlgW0+UbYlF" + + "4U8KifhManD1apVSC3csafaspP4RZUHFhtBywLO9pR5c\\nr6S5aLp+gPWFyIp1pfXbWGvc5VY/v9x7ya1VEa6rXvL" + + "sKupSeWAW4tMj3eo/64ge\\nsdaceaLYw52KeBYiT6+vpsnYrEkAHO1fF/LavbLLOFJmFTMxmsNaG0tuiJHgjshB\\" + + "n82DpMCbXG9YcCgI/DbzuIjsdj2JC1cascSP//3PmefWysucBQe7Jryb6NQtASmnv\\nCdDw/0jmZTEjpe4S1lxfHp" + + "lAhHFtdgYTvyYtaLZiVVkCgYEA8eVpof2rceecw/I6\\n5ng1q3Hl2usdWV/4mZMvR0fOemacLLfocX6IYxT1zA1FF" + + "JlbXSRsJMf/Qq39mOR2\\nSpW+hr4jCoHeRVYLgsbggtrevGmILAlNoqCMpGZ6vDmJpq6ECV9olliDvpPgWOP+\\nm" + + "YPDreFBGxWvQrADNbRt2dmGsrsCgYEAyUHqB2wvJHFqdmeBsaacewzV8x9WgmeX\\ngUIi9REwXlGDW0Mz50dxpxcK" + + "CAYn65+7TCnY5O/jmL0VRxU1J2mSWyWTo1C+17L0\\n3fUqjxL1pkefwecxwecvC+gFFYdJ4CQ/MHHXU81Lwl1iWdF" + + "Cd2UoGddYaOF+KNeM\\nHC7cmqra+JsCgYEAlUNywzq8nUg7282E+uICfCB0LfwejuymR93CtsFgb7cRd6ak\\nECR" + + "8FGfCpH8ruWJINllbQfcHVCX47ndLZwqv3oVFKh6pAS/vVI4dpOepP8++7y1u\\ncoOvtreXCX6XqfrWDtKIvv0vjl" + + "HBhhhp6mCcRpdQjV38H7JsyJ7lih/oNjECgYAt\\nkndj5uNl5SiuVxHFhcZJO+XWf6ofLUregtevZakGMn8EE1uVa" + + "2AY7eafmoU/nZPT\\n00YB0TBATdCbn/nBSuKDESkhSg9s2GEKQZG5hBmL5uCMfo09z3SfxZIhJdlerreP\\nJ7gSi" + + "dI12N+EZxYd4xIJh/HFDgp7RRO87f+WJkofMQKBgGTnClK1VMaCRbJZPriw\\nEfeFCoOX75MxKwXs6xgrw4W//AYG" + + "GUjDt83lD6AZP6tws7gJ2IwY/qP7+lyhjEqN\\nHtfPZRGFkGZsdaksdlaksd323423d+15/UvrlRSFPNj1tWQmNKk" + + "XyRDW4IG1Oa2p\\nrALStNBx5Y9t0/LQnFI4w3aG\\n-----END PRIVATE KEY-----\\n\",\n" + + " \"project_id\": \"someprojectid\",\n" + + " \"client_email\": \"someclientid@developer.gserviceaccount.com\",\n" + + " \"client_id\": \"someclientid.apps.googleusercontent.com\",\n" + + " \"type\": \"service_account\",\n" + + " \"quota_project_id\": \"" + + QUOTA_PROJECT_ID_FROM_CREDENTIALS_VALUE + + "\"\n" + + "}"; + + private static final GoogleCredentials credentialsWithQuotaProject = + loadCredentials(JSON_KEY_QUOTA_PROJECT_ID); @Test public void testEmptyBuilder() throws Exception { @@ -152,6 +196,7 @@ public void testBuilder() throws Exception { @Test public void testBuilderFromClientContext() throws Exception { + final String QUOTA_PROJECT_ID_FROM_CONTEXT = "some_quota_project_id_from_context"; ApiClock clock = Mockito.mock(ApiClock.class); ApiCallContext callContext = FakeCallContext.createDefault(); Map headers = Collections.singletonMap("spiffykey", "spiffyvalue"); @@ -172,6 +217,7 @@ public void testBuilderFromClientContext() throws Exception { .setHeaders(headers) .setStreamWatchdog(watchdog) .setStreamWatchdogCheckInterval(watchdogCheckInterval) + .setQuotaProjectID(QUOTA_PROJECT_ID_FROM_CONTEXT) .build(); FakeClientSettings.Builder builder = new FakeClientSettings.Builder(clientContext); @@ -186,6 +232,7 @@ public void testBuilderFromClientContext() throws Exception { Truth.assertThat(builder.getWatchdogProvider()).isInstanceOf(FixedWatchdogProvider.class); Truth.assertThat(builder.getWatchdogProvider().getWatchdog()).isSameInstanceAs(watchdog); Truth.assertThat(builder.getWatchdogCheckInterval()).isEqualTo(watchdogCheckInterval); + Truth.assertThat(builder.getQuotaProjectID()).isEqualTo(QUOTA_PROJECT_ID_FROM_CONTEXT); } @Test @@ -266,47 +313,7 @@ static GoogleCredentials loadCredentials(String credentialFile) { } @Test - public void testBuilderQuotaProjectID() { - final String QUOTA_PROJECT_ID_KEY = "x-google-user-project"; - final String QUOTA_PROJECT_ID_FROM_HEADER_VALUE = "quota_project_id_from_headers"; - final String QUOTA_PROJECT_ID_FROM_BUILDERS = "quota_project_id_from_builders"; - final String QUOTA_PROJECT_ID_FROM_INTERNAL_HEADER_VALUE = - "quota_project_id_from_internal_headers"; - final String QUOTA_PROJECT_ID_FROM_CREDENTIALS_VALUE = "quota_project_id_from_credentials"; - final String JSON_KEY_QUOTA_PROJECT_ID = - "{\n" - + " \"private_key_id\": \"somekeyid\",\n" - + " \"private_key\": \"-----BEGIN PRIVATE KEY-----\\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggS" - + "kAgEAAoIBAQC+K2hSuFpAdrJI\\nnCgcDz2M7t7bjdlsadsasad+fvRSW6TjNQZ3p5LLQY1kSZRqBqylRkzteMOyHg" - + "aR\\n0Pmxh3ILCND5men43j3h4eDbrhQBuxfEMalkG92sL+PNQSETY2tnvXryOvmBRwa/\\nQP/9dJfIkIDJ9Fw9N4" - + "Bhhhp6mCcRpdQjV38H7JsyJ7lih/oNjECgYAt\\nknddadwkwewcVxHFhcZJO+XWf6ofLUXpRwiTZakGMn8EE1uVa2" - + "LgczOjwWHGi99MFjxSer5m9\\n1tCa3/KEGKiS/YL71JvjwX3mb+cewlkcmweBKZHM2JPTk0ZednFSpVZMtycjkbLa" - + "\\ndYOS8V85AgMBewECggEBAKksaldajfDZDV6nGqbFjMiizAKJolr/M3OQw16K6o3/\\n0S31xIe3sSlgW0+UbYlF" - + "4U8KifhManD1apVSC3csafaspP4RZUHFhtBywLO9pR5c\\nr6S5aLp+gPWFyIp1pfXbWGvc5VY/v9x7ya1VEa6rXvL" - + "sKupSeWAW4tMj3eo/64ge\\nsdaceaLYw52KeBYiT6+vpsnYrEkAHO1fF/LavbLLOFJmFTMxmsNaG0tuiJHgjshB\\" - + "n82DpMCbXG9YcCgI/DbzuIjsdj2JC1cascSP//3PmefWysucBQe7Jryb6NQtASmnv\\nCdDw/0jmZTEjpe4S1lxfHp" - + "lAhHFtdgYTvyYtaLZiVVkCgYEA8eVpof2rceecw/I6\\n5ng1q3Hl2usdWV/4mZMvR0fOemacLLfocX6IYxT1zA1FF" - + "JlbXSRsJMf/Qq39mOR2\\nSpW+hr4jCoHeRVYLgsbggtrevGmILAlNoqCMpGZ6vDmJpq6ECV9olliDvpPgWOP+\\nm" - + "YPDreFBGxWvQrADNbRt2dmGsrsCgYEAyUHqB2wvJHFqdmeBsaacewzV8x9WgmeX\\ngUIi9REwXlGDW0Mz50dxpxcK" - + "CAYn65+7TCnY5O/jmL0VRxU1J2mSWyWTo1C+17L0\\n3fUqjxL1pkefwecxwecvC+gFFYdJ4CQ/MHHXU81Lwl1iWdF" - + "Cd2UoGddYaOF+KNeM\\nHC7cmqra+JsCgYEAlUNywzq8nUg7282E+uICfCB0LfwejuymR93CtsFgb7cRd6ak\\nECR" - + "8FGfCpH8ruWJINllbQfcHVCX47ndLZwqv3oVFKh6pAS/vVI4dpOepP8++7y1u\\ncoOvtreXCX6XqfrWDtKIvv0vjl" - + "HBhhhp6mCcRpdQjV38H7JsyJ7lih/oNjECgYAt\\nkndj5uNl5SiuVxHFhcZJO+XWf6ofLUregtevZakGMn8EE1uVa" - + "2AY7eafmoU/nZPT\\n00YB0TBATdCbn/nBSuKDESkhSg9s2GEKQZG5hBmL5uCMfo09z3SfxZIhJdlerreP\\nJ7gSi" - + "dI12N+EZxYd4xIJh/HFDgp7RRO87f+WJkofMQKBgGTnClK1VMaCRbJZPriw\\nEfeFCoOX75MxKwXs6xgrw4W//AYG" - + "GUjDt83lD6AZP6tws7gJ2IwY/qP7+lyhjEqN\\nHtfPZRGFkGZsdaksdlaksd323423d+15/UvrlRSFPNj1tWQmNKk" - + "XyRDW4IG1Oa2p\\nrALStNBx5Y9t0/LQnFI4w3aG\\n-----END PRIVATE KEY-----\\n\",\n" - + " \"project_id\": \"someprojectid\",\n" - + " \"client_email\": \"someclientid@developer.gserviceaccount.com\",\n" - + " \"client_id\": \"someclientid.apps.googleusercontent.com\",\n" - + " \"type\": \"service_account\",\n" - + " \"quota_project_id\": \"" - + QUOTA_PROJECT_ID_FROM_CREDENTIALS_VALUE - + "\"\n" - + "}"; - - final GoogleCredentials credentialsWithQuotaProject = - loadCredentials(JSON_KEY_QUOTA_PROJECT_ID); + public void testBuilderFromSettings_QuotaProjectID() { CredentialsProvider credentialsProvider_no_quota = Mockito.mock(CredentialsProvider.class); HeaderProvider headerProvider_no_quota = Mockito.mock(HeaderProvider.class); @@ -422,4 +429,107 @@ public Credentials getCredentials() throws IOException { Truth.assertThat(builder_setQuotaFromAllSourcesOrder.getQuotaProjectID()) .isEqualTo(QUOTA_PROJECT_ID_FROM_BUILDERS); } + + @Test + public void testBuilderFromClientContext_QuotaProjectID() { + ApiCallContext callContext = FakeCallContext.createDefault(); + + ClientContext clientContextQuotaOnly = + ClientContext.newBuilder() + .setTransportChannel(Mockito.mock(TransportChannel.class)) + .setDefaultCallContext(callContext) + .setQuotaProjectID(QUOTA_PROJECT_ID_FROM_CONTEXT) + .build(); + FakeClientSettings.Builder builderQuotaOnly = + new FakeClientSettings.Builder(clientContextQuotaOnly); + + ClientContext clientContextCredentialOnly = + ClientContext.newBuilder() + .setTransportChannel(Mockito.mock(TransportChannel.class)) + .setDefaultCallContext(callContext) + .setCredentials(credentialsWithQuotaProject) + .build(); + FakeClientSettings.Builder builderCredentialOnly = + new FakeClientSettings.Builder(clientContextCredentialOnly); + + ClientContext clientContextCredentialAndQuota = + ClientContext.newBuilder() + .setTransportChannel(Mockito.mock(TransportChannel.class)) + .setDefaultCallContext(callContext) + .setCredentials(credentialsWithQuotaProject) + .setQuotaProjectID(QUOTA_PROJECT_ID_FROM_CONTEXT) + .build(); + FakeClientSettings.Builder builderCredentialAndQuota = + new FakeClientSettings.Builder(clientContextCredentialAndQuota); + + ClientContext clientContextHeadersOnly = + ClientContext.newBuilder() + .setTransportChannel(Mockito.mock(TransportChannel.class)) + .setDefaultCallContext(callContext) + .setHeaders(ImmutableMap.of(QUOTA_PROJECT_ID_KEY, QUOTA_PROJECT_ID_FROM_HEADER_VALUE)) + .build(); + FakeClientSettings.Builder builderHeadersOnly = + new FakeClientSettings.Builder(clientContextHeadersOnly); + + ClientContext clientContextHeadersAndQuota = + ClientContext.newBuilder() + .setTransportChannel(Mockito.mock(TransportChannel.class)) + .setDefaultCallContext(callContext) + .setQuotaProjectID(QUOTA_PROJECT_ID_FROM_CONTEXT) + .setHeaders(ImmutableMap.of(QUOTA_PROJECT_ID_KEY, QUOTA_PROJECT_ID_FROM_HEADER_VALUE)) + .build(); + FakeClientSettings.Builder builderHeadersAndQuota = + new FakeClientSettings.Builder(clientContextHeadersAndQuota); + + ClientContext clientContextInternalHeadersOnly = + ClientContext.newBuilder() + .setTransportChannel(Mockito.mock(TransportChannel.class)) + .setDefaultCallContext(callContext) + .setInternalHeaders( + ImmutableMap.of(QUOTA_PROJECT_ID_KEY, QUOTA_PROJECT_ID_FROM_INTERNAL_HEADER_VALUE)) + .build(); + FakeClientSettings.Builder builderInternalHeadersOnly = + new FakeClientSettings.Builder(clientContextInternalHeadersOnly); + + ClientContext clientContextInternalHeadersAndQuota = + ClientContext.newBuilder() + .setTransportChannel(Mockito.mock(TransportChannel.class)) + .setDefaultCallContext(callContext) + .setInternalHeaders( + ImmutableMap.of(QUOTA_PROJECT_ID_KEY, QUOTA_PROJECT_ID_FROM_INTERNAL_HEADER_VALUE)) + .setQuotaProjectID(QUOTA_PROJECT_ID_FROM_CONTEXT) + .build(); + FakeClientSettings.Builder builderInternalHeadersAndQuota = + new FakeClientSettings.Builder(clientContextInternalHeadersAndQuota); + + ClientContext clientContextQuotaFromAllSources = + ClientContext.newBuilder() + .setTransportChannel(Mockito.mock(TransportChannel.class)) + .setDefaultCallContext(callContext) + .setHeaders( + ImmutableMap.of(QUOTA_PROJECT_ID_KEY, QUOTA_PROJECT_ID_FROM_INTERNAL_HEADER_VALUE)) + .setCredentials(credentialsWithQuotaProject) + .setQuotaProjectID(QUOTA_PROJECT_ID_FROM_CONTEXT) + .setInternalHeaders( + ImmutableMap.of(QUOTA_PROJECT_ID_KEY, QUOTA_PROJECT_ID_FROM_INTERNAL_HEADER_VALUE)) + .build(); + FakeClientSettings.Builder builderQuotaFromAllSources = + new FakeClientSettings.Builder(clientContextQuotaFromAllSources); + + Truth.assertThat(builderQuotaOnly.getQuotaProjectID()).isEqualTo(QUOTA_PROJECT_ID_FROM_CONTEXT); + Truth.assertThat(builderCredentialOnly.getQuotaProjectID()) + .isEqualTo(QUOTA_PROJECT_ID_FROM_CREDENTIALS_VALUE); + Truth.assertThat(builderCredentialAndQuota.getQuotaProjectID()) + .isEqualTo(QUOTA_PROJECT_ID_FROM_CONTEXT); + Truth.assertThat(builderHeadersOnly.getQuotaProjectID()) + .isEqualTo(QUOTA_PROJECT_ID_FROM_HEADER_VALUE); + Truth.assertThat(builderHeadersAndQuota.getQuotaProjectID()) + .isEqualTo(QUOTA_PROJECT_ID_FROM_CONTEXT); + Truth.assertThat(builderInternalHeadersOnly.getQuotaProjectID()) + .isEqualTo(QUOTA_PROJECT_ID_FROM_INTERNAL_HEADER_VALUE); + Truth.assertThat(builderInternalHeadersAndQuota.getQuotaProjectID()) + .isEqualTo(QUOTA_PROJECT_ID_FROM_CONTEXT); + Truth.assertThat(builderQuotaFromAllSources.getQuotaProjectID()) + .isEqualTo(QUOTA_PROJECT_ID_FROM_CONTEXT); + } } From cea611860a607b189b52794e26ca930de79f4b4e Mon Sep 17 00:00:00 2001 From: summerji Date: Thu, 18 Jun 2020 13:47:22 -0700 Subject: [PATCH 03/10] change from quotaProjectID to quotaProjectId --- .../com/google/api/gax/rpc/ClientContext.java | 8 +- .../google/api/gax/rpc/ClientSettings.java | 18 ++-- .../com/google/api/gax/rpc/StubSettings.java | 48 +++++------ .../api/gax/rpc/ClientSettingsTest.java | 84 +++++++++---------- 4 files changed, 79 insertions(+), 79 deletions(-) diff --git a/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java b/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java index 9791c53e2..070913501 100644 --- a/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java +++ b/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java @@ -97,7 +97,7 @@ public abstract class ClientContext { public abstract String getEndpoint(); @Nullable - public abstract String getQuotaProjectID(); + public abstract String getQuotaProjectId(); /** Gets the {@link ApiTracerFactory} that will be used to generate traces for operations. */ @BetaApi("The surface for tracing is not stable yet and may change in the future.") @@ -114,7 +114,7 @@ public static Builder newBuilder() { .setStreamWatchdog(null) .setStreamWatchdogCheckInterval(Duration.ZERO) .setTracerFactory(NoopApiTracerFactory.getInstance()) - .setQuotaProjectID(null); + .setQuotaProjectId(null); } public abstract Builder toBuilder(); @@ -204,7 +204,7 @@ public static ClientContext create(StubSettings settings) throws IOException { .setClock(clock) .setDefaultCallContext(defaultCallContext) .setEndpoint(settings.getEndpoint()) - .setQuotaProjectID(settings.getQuotaProjectID()) + .setQuotaProjectId(settings.getQuotaProjectId()) .setStreamWatchdog(watchdog) .setStreamWatchdogCheckInterval(settings.getStreamWatchdogCheckInterval()) .setTracerFactory(settings.getTracerFactory()) @@ -234,7 +234,7 @@ public abstract static class Builder { public abstract Builder setEndpoint(String endpoint); - public abstract Builder setQuotaProjectID(String quotaProjectID); + public abstract Builder setQuotaProjectId(String QuotaProjectId); @BetaApi("The surface for streaming is not stable yet and may change in the future.") public abstract Builder setStreamWatchdog(Watchdog watchdog); diff --git a/gax/src/main/java/com/google/api/gax/rpc/ClientSettings.java b/gax/src/main/java/com/google/api/gax/rpc/ClientSettings.java index 88bc7af8a..7575fea2b 100644 --- a/gax/src/main/java/com/google/api/gax/rpc/ClientSettings.java +++ b/gax/src/main/java/com/google/api/gax/rpc/ClientSettings.java @@ -93,8 +93,8 @@ public final String getEndpoint() { return stubSettings.getEndpoint(); } - public final String getQuotaProjectID() { - return stubSettings.getQuotaProjectID(); + public final String getQuotaProjectId() { + return stubSettings.getQuotaProjectId(); } @BetaApi("The surface for streaming is not stable yet and may change in the future.") @@ -118,7 +118,7 @@ public String toString() { .add("internalHeaderProvider", getInternalHeaderProvider()) .add("clock", getClock()) .add("endpoint", getEndpoint()) - .add("quotaProjectID", getQuotaProjectID()) + .add("quotaProjectId", getQuotaProjectId()) .add("watchdogProvider", getWatchdogProvider()) .add("watchdogCheckInterval", getWatchdogCheckInterval()) .toString(); @@ -221,8 +221,8 @@ public B setEndpoint(String endpoint) { return self(); } - public B setQuotaProjectID(String quotaProjectID) { - stubSettings.setQuotaProjectID(quotaProjectID); + public B setQuotaProjectId(String quotaProjectId) { + stubSettings.setQuotaProjectId(quotaProjectId); return self(); } @@ -274,9 +274,9 @@ public String getEndpoint() { return stubSettings.getEndpoint(); } - /** Gets the QuotaProjectID that was previously set on this Builder. */ - public String getQuotaProjectID() { - return stubSettings.getQuotaProjectID(); + /** Gets the QuotaProjectId that was previously set on this Builder. */ + public String getQuotaProjectId() { + return stubSettings.getQuotaProjectId(); } @BetaApi("The surface for streaming is not stable yet and may change in the future.") @@ -309,7 +309,7 @@ public String toString() { .add("internalHeaderProvider", getInternalHeaderProvider()) .add("clock", getClock()) .add("endpoint", getEndpoint()) - .add("quotaProjectID", getQuotaProjectID()) + .add("quotaProjectId", getQuotaProjectId()) .add("watchdogProvider", getWatchdogProvider()) .add("watchdogCheckInterval", getWatchdogCheckInterval()) .toString(); diff --git a/gax/src/main/java/com/google/api/gax/rpc/StubSettings.java b/gax/src/main/java/com/google/api/gax/rpc/StubSettings.java index 193cfc3b6..a6d5e2246 100644 --- a/gax/src/main/java/com/google/api/gax/rpc/StubSettings.java +++ b/gax/src/main/java/com/google/api/gax/rpc/StubSettings.java @@ -71,7 +71,7 @@ public abstract class StubSettings> { private final TransportChannelProvider transportChannelProvider; private final ApiClock clock; private final String endpoint; - private final String quotaProjectID; + private final String quotaProjectId; @Nullable private final WatchdogProvider streamWatchdogProvider; @Nonnull private final Duration streamWatchdogCheckInterval; @Nonnull private final ApiTracerFactory tracerFactory; @@ -85,7 +85,7 @@ protected StubSettings(Builder builder) { this.internalHeaderProvider = builder.internalHeaderProvider; this.clock = builder.clock; this.endpoint = builder.endpoint; - this.quotaProjectID = builder.quotaProjectID; + this.quotaProjectId = builder.quotaProjectId; this.streamWatchdogProvider = builder.streamWatchdogProvider; this.streamWatchdogCheckInterval = builder.streamWatchdogCheckInterval; this.tracerFactory = builder.tracerFactory; @@ -121,8 +121,8 @@ public final String getEndpoint() { return endpoint; } - public final String getQuotaProjectID() { - return quotaProjectID; + public final String getQuotaProjectId() { + return quotaProjectId; } @BetaApi("The surface for streaming is not stable yet and may change in the future.") @@ -156,7 +156,7 @@ public String toString() { .add("internalHeaderProvider", internalHeaderProvider) .add("clock", clock) .add("endpoint", endpoint) - .add("quotaProjectID", quotaProjectID) + .add("quotaProjectId", quotaProjectId) .add("streamWatchdogProvider", streamWatchdogProvider) .add("streamWatchdogCheckInterval", streamWatchdogCheckInterval) .add("tracerFactory", tracerFactory) @@ -175,7 +175,7 @@ public abstract static class Builder< private TransportChannelProvider transportChannelProvider; private ApiClock clock; private String endpoint; - private String quotaProjectID; + private String quotaProjectId; @Nullable private WatchdogProvider streamWatchdogProvider; @Nonnull private Duration streamWatchdogCheckInterval; @Nonnull private ApiTracerFactory tracerFactory; @@ -189,16 +189,16 @@ protected Builder(StubSettings settings) { this.internalHeaderProvider = settings.internalHeaderProvider; this.clock = settings.clock; this.endpoint = settings.endpoint; - this.quotaProjectID = settings.quotaProjectID; + this.quotaProjectId = settings.quotaProjectId; this.streamWatchdogProvider = settings.streamWatchdogProvider; this.streamWatchdogCheckInterval = settings.streamWatchdogCheckInterval; this.tracerFactory = settings.tracerFactory; } /** Get Quota Project ID from Client Context * */ - private static String getQuotaProjectIDFromClientContext(ClientContext clientContext) { - if (clientContext.getQuotaProjectID() != null) { - return clientContext.getQuotaProjectID(); + private static String getQuotaProjectIdFromClientContext(ClientContext clientContext) { + if (clientContext.getQuotaProjectId() != null) { + return clientContext.getQuotaProjectId(); } if (clientContext.getCredentials() instanceof QuotaProjectIdProvider) { return ((QuotaProjectIdProvider) clientContext.getCredentials()).getQuotaProjectId(); @@ -221,7 +221,7 @@ protected Builder(ClientContext clientContext) { this.internalHeaderProvider = new NoHeaderProvider(); this.clock = NanoClock.getDefaultClock(); this.endpoint = null; - this.quotaProjectID = null; + this.quotaProjectId = null; this.streamWatchdogProvider = InstantiatingWatchdogProvider.create(); this.streamWatchdogCheckInterval = Duration.ofSeconds(10); this.tracerFactory = NoopApiTracerFactory.getInstance(); @@ -239,7 +239,7 @@ protected Builder(ClientContext clientContext) { FixedWatchdogProvider.create(clientContext.getStreamWatchdog()); this.streamWatchdogCheckInterval = clientContext.getStreamWatchdogCheckInterval(); this.tracerFactory = clientContext.getTracerFactory(); - this.quotaProjectID = getQuotaProjectIDFromClientContext(clientContext); + this.quotaProjectId = getQuotaProjectIdFromClientContext(clientContext); } } @@ -268,8 +268,8 @@ public B setCredentialsProvider(CredentialsProvider credentialsProvider) { this.credentialsProvider = Preconditions.checkNotNull(credentialsProvider); try { Credentials credentials = credentialsProvider.getCredentials(); - if (this.quotaProjectID == null && credentials instanceof QuotaProjectIdProvider) { - this.quotaProjectID = ((QuotaProjectIdProvider) credentials).getQuotaProjectId(); + if (this.quotaProjectId == null && credentials instanceof QuotaProjectIdProvider) { + this.quotaProjectId = ((QuotaProjectIdProvider) credentials).getQuotaProjectId(); } } catch (IOException e) { System.out.println("fail to fetch credentials"); @@ -287,9 +287,9 @@ public B setCredentialsProvider(CredentialsProvider credentialsProvider) { @BetaApi("The surface for customizing headers is not stable yet and may change in the future.") public B setHeaderProvider(HeaderProvider headerProvider) { this.headerProvider = headerProvider; - if (this.quotaProjectID == null + if (this.quotaProjectId == null && headerProvider.getHeaders().containsKey(QUOTA_PROJECT_ID_HEADER_KEY)) { - this.quotaProjectID = headerProvider.getHeaders().get(QUOTA_PROJECT_ID_HEADER_KEY); + this.quotaProjectId = headerProvider.getHeaders().get(QUOTA_PROJECT_ID_HEADER_KEY); } return self(); } @@ -304,9 +304,9 @@ public B setHeaderProvider(HeaderProvider headerProvider) { @BetaApi("The surface for customizing headers is not stable yet and may change in the future.") protected B setInternalHeaderProvider(HeaderProvider internalHeaderProvider) { this.internalHeaderProvider = internalHeaderProvider; - if (this.quotaProjectID == null + if (this.quotaProjectId == null && internalHeaderProvider.getHeaders().containsKey(QUOTA_PROJECT_ID_HEADER_KEY)) { - this.quotaProjectID = internalHeaderProvider.getHeaders().get(QUOTA_PROJECT_ID_HEADER_KEY); + this.quotaProjectId = internalHeaderProvider.getHeaders().get(QUOTA_PROJECT_ID_HEADER_KEY); } return self(); } @@ -346,8 +346,8 @@ public B setEndpoint(String endpoint) { return self(); } - public B setQuotaProjectID(String quotaProjectID) { - this.quotaProjectID = quotaProjectID; + public B setQuotaProjectId(String quotaProjectId) { + this.quotaProjectId = quotaProjectId; return self(); } @@ -417,9 +417,9 @@ public String getEndpoint() { return endpoint; } - /** Gets the QuotaProjectID that was previously set on this Builder. */ - public String getQuotaProjectID() { - return quotaProjectID; + /** Gets the QuotaProjectId that was previously set on this Builder. */ + public String getQuotaProjectId() { + return quotaProjectId; } @BetaApi("The surface for streaming is not stable yet and may change in the future.") @@ -454,7 +454,7 @@ public String toString() { .add("internalHeaderProvider", internalHeaderProvider) .add("clock", clock) .add("endpoint", endpoint) - .add("quotaProjectID", quotaProjectID) + .add("quotaProjectId", quotaProjectId) .add("streamWatchdogProvider", streamWatchdogProvider) .add("streamWatchdogCheckInterval", streamWatchdogCheckInterval) .add("tracerFactory", tracerFactory) diff --git a/gax/src/test/java/com/google/api/gax/rpc/ClientSettingsTest.java b/gax/src/test/java/com/google/api/gax/rpc/ClientSettingsTest.java index 8dc1c9ef2..4551b925c 100644 --- a/gax/src/test/java/com/google/api/gax/rpc/ClientSettingsTest.java +++ b/gax/src/test/java/com/google/api/gax/rpc/ClientSettingsTest.java @@ -119,7 +119,7 @@ public void testEmptyBuilder() throws Exception { Truth.assertThat(builder.getWatchdogProvider()) .isInstanceOf(InstantiatingWatchdogProvider.class); Truth.assertThat(builder.getWatchdogCheckInterval()).isGreaterThan(Duration.ZERO); - Truth.assertThat(builder.getQuotaProjectID()).isNull(); + Truth.assertThat(builder.getQuotaProjectId()).isNull(); FakeClientSettings settings = builder.build(); Truth.assertThat(settings.getExecutorProvider()) @@ -135,7 +135,7 @@ public void testEmptyBuilder() throws Exception { Truth.assertThat(settings.getWatchdogProvider()) .isInstanceOf(InstantiatingWatchdogProvider.class); Truth.assertThat(settings.getWatchdogCheckInterval()).isGreaterThan(Duration.ZERO); - Truth.assertThat((settings.getQuotaProjectID())).isSameInstanceAs(builder.getQuotaProjectID()); + Truth.assertThat((settings.getQuotaProjectId())).isSameInstanceAs(builder.getQuotaProjectId()); String settingsString = settings.toString(); Truth.assertThat(settingsString).contains("executorProvider"); @@ -145,7 +145,7 @@ public void testEmptyBuilder() throws Exception { Truth.assertThat(settingsString).contains("headerProvider"); Truth.assertThat(settingsString).contains("watchdogProvider"); Truth.assertThat(settingsString).contains("watchdogCheckInterval"); - Truth.assertThat(settingsString).contains(("quotaProjectID")); + Truth.assertThat(settingsString).contains(("quotaProjectId")); } @Test @@ -160,7 +160,7 @@ public void testBuilder() throws Exception { HeaderProvider internalHeaderProvider = Mockito.mock(HeaderProvider.class); WatchdogProvider watchdogProvider = Mockito.mock(WatchdogProvider.class); Duration watchdogCheckInterval = Duration.ofSeconds(13); - String quotaProjectID = "test_quota_project_id"; + String quotaProjectId = "test_quota_project_id"; builder.setExecutorProvider(executorProvider); builder.setTransportChannelProvider(transportProvider); @@ -170,7 +170,7 @@ public void testBuilder() throws Exception { builder.setClock(clock); builder.setWatchdogProvider(watchdogProvider); builder.setWatchdogCheckInterval(watchdogCheckInterval); - builder.setQuotaProjectID(quotaProjectID); + builder.setQuotaProjectId(quotaProjectId); Truth.assertThat(builder.getExecutorProvider()).isSameInstanceAs(executorProvider); Truth.assertThat(builder.getTransportChannelProvider()).isSameInstanceAs(transportProvider); @@ -180,7 +180,7 @@ public void testBuilder() throws Exception { Truth.assertThat(builder.getInternalHeaderProvider()).isSameInstanceAs(internalHeaderProvider); Truth.assertThat(builder.getWatchdogProvider()).isSameInstanceAs(watchdogProvider); Truth.assertThat(builder.getWatchdogCheckInterval()).isSameInstanceAs(watchdogCheckInterval); - Truth.assertThat(builder.getQuotaProjectID()).isEqualTo(quotaProjectID); + Truth.assertThat(builder.getQuotaProjectId()).isEqualTo(quotaProjectId); String builderString = builder.toString(); Truth.assertThat(builderString).contains("executorProvider"); @@ -191,7 +191,7 @@ public void testBuilder() throws Exception { Truth.assertThat(builderString).contains("internalHeaderProvider"); Truth.assertThat(builderString).contains("watchdogProvider"); Truth.assertThat(builderString).contains("watchdogCheckInterval"); - Truth.assertThat(builderString).contains("quotaProjectID"); + Truth.assertThat(builderString).contains("quotaProjectId"); } @Test @@ -217,7 +217,7 @@ public void testBuilderFromClientContext() throws Exception { .setHeaders(headers) .setStreamWatchdog(watchdog) .setStreamWatchdogCheckInterval(watchdogCheckInterval) - .setQuotaProjectID(QUOTA_PROJECT_ID_FROM_CONTEXT) + .setQuotaProjectId(QUOTA_PROJECT_ID_FROM_CONTEXT) .build(); FakeClientSettings.Builder builder = new FakeClientSettings.Builder(clientContext); @@ -232,7 +232,7 @@ public void testBuilderFromClientContext() throws Exception { Truth.assertThat(builder.getWatchdogProvider()).isInstanceOf(FixedWatchdogProvider.class); Truth.assertThat(builder.getWatchdogProvider().getWatchdog()).isSameInstanceAs(watchdog); Truth.assertThat(builder.getWatchdogCheckInterval()).isEqualTo(watchdogCheckInterval); - Truth.assertThat(builder.getQuotaProjectID()).isEqualTo(QUOTA_PROJECT_ID_FROM_CONTEXT); + Truth.assertThat(builder.getQuotaProjectId()).isEqualTo(QUOTA_PROJECT_ID_FROM_CONTEXT); } @Test @@ -247,7 +247,7 @@ public void testBuilderFromSettings() throws Exception { HeaderProvider internalHeaderProvider = Mockito.mock(HeaderProvider.class); WatchdogProvider watchdogProvider = Mockito.mock(WatchdogProvider.class); Duration watchdogCheckInterval = Duration.ofSeconds(14); - String quotaProjectID = "test_builder_from_settings_quotaProjectID"; + String quotaProjectId = "test_builder_from_settings_quotaProjectId"; builder.setExecutorProvider(executorProvider); builder.setTransportChannelProvider(transportProvider); @@ -257,7 +257,7 @@ public void testBuilderFromSettings() throws Exception { builder.setInternalHeaderProvider(internalHeaderProvider); builder.setWatchdogProvider(watchdogProvider); builder.setWatchdogCheckInterval(watchdogCheckInterval); - builder.setQuotaProjectID(quotaProjectID); + builder.setQuotaProjectId(quotaProjectId); FakeClientSettings settings = builder.build(); FakeClientSettings.Builder newBuilder = new FakeClientSettings.Builder(settings); @@ -271,7 +271,7 @@ public void testBuilderFromSettings() throws Exception { .isSameInstanceAs(internalHeaderProvider); Truth.assertThat(newBuilder.getWatchdogProvider()).isSameInstanceAs(watchdogProvider); Truth.assertThat(newBuilder.getWatchdogCheckInterval()).isEqualTo(watchdogCheckInterval); - Truth.assertThat(newBuilder.getQuotaProjectID()).isEqualTo(quotaProjectID); + Truth.assertThat(newBuilder.getQuotaProjectId()).isEqualTo(quotaProjectId); } @Test @@ -313,7 +313,7 @@ static GoogleCredentials loadCredentials(String credentialFile) { } @Test - public void testBuilderFromSettings_QuotaProjectID() { + public void testBuilderFromSettings_QuotaProjectId() { CredentialsProvider credentialsProvider_no_quota = Mockito.mock(CredentialsProvider.class); HeaderProvider headerProvider_no_quota = Mockito.mock(HeaderProvider.class); @@ -348,7 +348,7 @@ public Credentials getCredentials() throws IOException { builder_setQuotaOnly.setCredentialsProvider(credentialsProvider_no_quota); builder_setQuotaOnly.setHeaderProvider(headerProvider_no_quota); builder_setQuotaOnly.setInternalHeaderProvider(internalHeaderProvider_no_quota); - builder_setQuotaOnly.setQuotaProjectID(QUOTA_PROJECT_ID_FROM_BUILDERS); + builder_setQuotaOnly.setQuotaProjectId(QUOTA_PROJECT_ID_FROM_BUILDERS); // Case for setting quota_project_id from HeaderProvider Only // expect value is from HeaderProvider @@ -360,7 +360,7 @@ public Credentials getCredentials() throws IOException { FakeClientSettings.Builder builder_setQuotaFromHeadersAndBuilders = new FakeClientSettings.Builder(); builder_setQuotaFromHeadersOnly.setHeaderProvider(headerProvider_with_quota); - builder_setQuotaFromHeadersAndBuilders.setQuotaProjectID(QUOTA_PROJECT_ID_FROM_BUILDERS); + builder_setQuotaFromHeadersAndBuilders.setQuotaProjectId(QUOTA_PROJECT_ID_FROM_BUILDERS); // Case for setting quota_project_id from InternalHeaderProvider and set from builders // expect value is from InternalHeaderProvider @@ -375,7 +375,7 @@ public Credentials getCredentials() throws IOException { new FakeClientSettings.Builder(); builder_setQuotaFromInternalHeadersAndBuilders.setInternalHeaderProvider( internalHeaderProvider_with_quota); - builder_setQuotaFromInternalHeadersAndBuilders.setQuotaProjectID( + builder_setQuotaFromInternalHeadersAndBuilders.setQuotaProjectId( QUOTA_PROJECT_ID_FROM_BUILDERS); // Case for setting quota_project_id from CredentialProvider Only @@ -390,7 +390,7 @@ public Credentials getCredentials() throws IOException { new FakeClientSettings.Builder(); builder_setQuotaFromCredentialsProviderAndBuilder.setCredentialsProvider( credentialsProvider_with_quota); - builder_setQuotaFromCredentialsProviderAndBuilder.setQuotaProjectID( + builder_setQuotaFromCredentialsProviderAndBuilder.setQuotaProjectId( QUOTA_PROJECT_ID_FROM_BUILDERS); // Case for setting quota_project_id from All three sources @@ -399,46 +399,46 @@ public Credentials getCredentials() throws IOException { builder_setQuotaFromAllSources.setHeaderProvider(headerProvider_with_quota); builder_setQuotaFromAllSources.setInternalHeaderProvider(headerProvider_with_quota); builder_setQuotaFromAllSources.setCredentialsProvider(credentialsProvider_with_quota); - builder_setQuotaFromAllSources.setQuotaProjectID(QUOTA_PROJECT_ID_FROM_BUILDERS); + builder_setQuotaFromAllSources.setQuotaProjectId(QUOTA_PROJECT_ID_FROM_BUILDERS); // Case for setting quota_project_id from All three sources but set from builders first // expect value is from builders FakeClientSettings.Builder builder_setQuotaFromAllSourcesOrder = new FakeClientSettings.Builder(); - builder_setQuotaFromAllSourcesOrder.setQuotaProjectID(QUOTA_PROJECT_ID_FROM_BUILDERS); + builder_setQuotaFromAllSourcesOrder.setQuotaProjectId(QUOTA_PROJECT_ID_FROM_BUILDERS); builder_setQuotaFromAllSourcesOrder.setHeaderProvider(headerProvider_with_quota); builder_setQuotaFromAllSourcesOrder.setInternalHeaderProvider(headerProvider_with_quota); builder_setQuotaFromAllSourcesOrder.setCredentialsProvider(credentialsProvider_with_quota); - Truth.assertThat(builder_setQuotaOnly.getQuotaProjectID()) + Truth.assertThat(builder_setQuotaOnly.getQuotaProjectId()) .isEqualTo(QUOTA_PROJECT_ID_FROM_BUILDERS); - Truth.assertThat(builder_setQuotaFromHeadersOnly.getQuotaProjectID()) + Truth.assertThat(builder_setQuotaFromHeadersOnly.getQuotaProjectId()) .isEqualTo(QUOTA_PROJECT_ID_FROM_HEADER_VALUE); - Truth.assertThat(builder_setQuotaFromHeadersAndBuilders.getQuotaProjectID()) + Truth.assertThat(builder_setQuotaFromHeadersAndBuilders.getQuotaProjectId()) .isEqualTo(QUOTA_PROJECT_ID_FROM_BUILDERS); - Truth.assertThat((builder_setQuotaFromInternalHeadersOnly).getQuotaProjectID()) + Truth.assertThat((builder_setQuotaFromInternalHeadersOnly).getQuotaProjectId()) .isEqualTo(QUOTA_PROJECT_ID_FROM_INTERNAL_HEADER_VALUE); - Truth.assertThat(builder_setQuotaFromInternalHeadersAndBuilders.getQuotaProjectID()) + Truth.assertThat(builder_setQuotaFromInternalHeadersAndBuilders.getQuotaProjectId()) .isEqualTo(QUOTA_PROJECT_ID_FROM_BUILDERS); - Truth.assertThat(builder_setQuotaFromCredentialsProvider.getQuotaProjectID()) + Truth.assertThat(builder_setQuotaFromCredentialsProvider.getQuotaProjectId()) .isEqualTo(QUOTA_PROJECT_ID_FROM_CREDENTIALS_VALUE); - Truth.assertThat(builder_setQuotaFromCredentialsProviderAndBuilder.getQuotaProjectID()) + Truth.assertThat(builder_setQuotaFromCredentialsProviderAndBuilder.getQuotaProjectId()) .isEqualTo(QUOTA_PROJECT_ID_FROM_BUILDERS); - Truth.assertThat(builder_setQuotaFromAllSources.getQuotaProjectID()) + Truth.assertThat(builder_setQuotaFromAllSources.getQuotaProjectId()) .isEqualTo(QUOTA_PROJECT_ID_FROM_BUILDERS); - Truth.assertThat(builder_setQuotaFromAllSourcesOrder.getQuotaProjectID()) + Truth.assertThat(builder_setQuotaFromAllSourcesOrder.getQuotaProjectId()) .isEqualTo(QUOTA_PROJECT_ID_FROM_BUILDERS); } @Test - public void testBuilderFromClientContext_QuotaProjectID() { + public void testBuilderFromClientContext_QuotaProjectId() { ApiCallContext callContext = FakeCallContext.createDefault(); ClientContext clientContextQuotaOnly = ClientContext.newBuilder() .setTransportChannel(Mockito.mock(TransportChannel.class)) .setDefaultCallContext(callContext) - .setQuotaProjectID(QUOTA_PROJECT_ID_FROM_CONTEXT) + .setQuotaProjectId(QUOTA_PROJECT_ID_FROM_CONTEXT) .build(); FakeClientSettings.Builder builderQuotaOnly = new FakeClientSettings.Builder(clientContextQuotaOnly); @@ -457,7 +457,7 @@ public void testBuilderFromClientContext_QuotaProjectID() { .setTransportChannel(Mockito.mock(TransportChannel.class)) .setDefaultCallContext(callContext) .setCredentials(credentialsWithQuotaProject) - .setQuotaProjectID(QUOTA_PROJECT_ID_FROM_CONTEXT) + .setQuotaProjectId(QUOTA_PROJECT_ID_FROM_CONTEXT) .build(); FakeClientSettings.Builder builderCredentialAndQuota = new FakeClientSettings.Builder(clientContextCredentialAndQuota); @@ -475,7 +475,7 @@ public void testBuilderFromClientContext_QuotaProjectID() { ClientContext.newBuilder() .setTransportChannel(Mockito.mock(TransportChannel.class)) .setDefaultCallContext(callContext) - .setQuotaProjectID(QUOTA_PROJECT_ID_FROM_CONTEXT) + .setQuotaProjectId(QUOTA_PROJECT_ID_FROM_CONTEXT) .setHeaders(ImmutableMap.of(QUOTA_PROJECT_ID_KEY, QUOTA_PROJECT_ID_FROM_HEADER_VALUE)) .build(); FakeClientSettings.Builder builderHeadersAndQuota = @@ -497,7 +497,7 @@ public void testBuilderFromClientContext_QuotaProjectID() { .setDefaultCallContext(callContext) .setInternalHeaders( ImmutableMap.of(QUOTA_PROJECT_ID_KEY, QUOTA_PROJECT_ID_FROM_INTERNAL_HEADER_VALUE)) - .setQuotaProjectID(QUOTA_PROJECT_ID_FROM_CONTEXT) + .setQuotaProjectId(QUOTA_PROJECT_ID_FROM_CONTEXT) .build(); FakeClientSettings.Builder builderInternalHeadersAndQuota = new FakeClientSettings.Builder(clientContextInternalHeadersAndQuota); @@ -509,27 +509,27 @@ public void testBuilderFromClientContext_QuotaProjectID() { .setHeaders( ImmutableMap.of(QUOTA_PROJECT_ID_KEY, QUOTA_PROJECT_ID_FROM_INTERNAL_HEADER_VALUE)) .setCredentials(credentialsWithQuotaProject) - .setQuotaProjectID(QUOTA_PROJECT_ID_FROM_CONTEXT) + .setQuotaProjectId(QUOTA_PROJECT_ID_FROM_CONTEXT) .setInternalHeaders( ImmutableMap.of(QUOTA_PROJECT_ID_KEY, QUOTA_PROJECT_ID_FROM_INTERNAL_HEADER_VALUE)) .build(); FakeClientSettings.Builder builderQuotaFromAllSources = new FakeClientSettings.Builder(clientContextQuotaFromAllSources); - Truth.assertThat(builderQuotaOnly.getQuotaProjectID()).isEqualTo(QUOTA_PROJECT_ID_FROM_CONTEXT); - Truth.assertThat(builderCredentialOnly.getQuotaProjectID()) + Truth.assertThat(builderQuotaOnly.getQuotaProjectId()).isEqualTo(QUOTA_PROJECT_ID_FROM_CONTEXT); + Truth.assertThat(builderCredentialOnly.getQuotaProjectId()) .isEqualTo(QUOTA_PROJECT_ID_FROM_CREDENTIALS_VALUE); - Truth.assertThat(builderCredentialAndQuota.getQuotaProjectID()) + Truth.assertThat(builderCredentialAndQuota.getQuotaProjectId()) .isEqualTo(QUOTA_PROJECT_ID_FROM_CONTEXT); - Truth.assertThat(builderHeadersOnly.getQuotaProjectID()) + Truth.assertThat(builderHeadersOnly.getQuotaProjectId()) .isEqualTo(QUOTA_PROJECT_ID_FROM_HEADER_VALUE); - Truth.assertThat(builderHeadersAndQuota.getQuotaProjectID()) + Truth.assertThat(builderHeadersAndQuota.getQuotaProjectId()) .isEqualTo(QUOTA_PROJECT_ID_FROM_CONTEXT); - Truth.assertThat(builderInternalHeadersOnly.getQuotaProjectID()) + Truth.assertThat(builderInternalHeadersOnly.getQuotaProjectId()) .isEqualTo(QUOTA_PROJECT_ID_FROM_INTERNAL_HEADER_VALUE); - Truth.assertThat(builderInternalHeadersAndQuota.getQuotaProjectID()) + Truth.assertThat(builderInternalHeadersAndQuota.getQuotaProjectId()) .isEqualTo(QUOTA_PROJECT_ID_FROM_CONTEXT); - Truth.assertThat(builderQuotaFromAllSources.getQuotaProjectID()) + Truth.assertThat(builderQuotaFromAllSources.getQuotaProjectId()) .isEqualTo(QUOTA_PROJECT_ID_FROM_CONTEXT); } } From a157f44b90e559f4efb203cdc7be4d9a797c6cae Mon Sep 17 00:00:00 2001 From: summerji Date: Tue, 14 Jul 2020 23:54:11 -0700 Subject: [PATCH 04/10] Add Executor --- build.gradle | 2 +- gax/build.gradle | 2 +- gax/src/main/java/com/google/api/gax/rpc/ClientContext.java | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 47daab1f9..6aeb073b9 100644 --- a/build.gradle +++ b/build.gradle @@ -24,7 +24,7 @@ apply plugin: 'com.github.sherter.google-java-format' apply plugin: 'io.codearte.nexus-staging' // TODO: Populate this from dependencies.properties version property (for proper Gradle-Bazel sync) -project.version = "1.57.0" // {x-version-update:gax:current} +project.version = "1.57.3-SNAPSHOT" // {x-version-update:gax:current} ext { // Project names not used for release diff --git a/gax/build.gradle b/gax/build.gradle index 9749f9690..9ee90a28d 100644 --- a/gax/build.gradle +++ b/gax/build.gradle @@ -1,7 +1,7 @@ archivesBaseName = "gax" // TODO: Populate this from dependencies.properties version property (for proper Gradle-Bazel sync) -project.version = "1.57.0" // {x-version-update:gax:current} +project.version = "1.57.2" // {x-version-update:gax:current} dependencies { compile libraries['maven.com_google_guava_guava'], diff --git a/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java b/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java index 070913501..9bc162064 100644 --- a/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java +++ b/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java @@ -60,6 +60,7 @@ */ @AutoValue public abstract class ClientContext { + private static final String QUOTA_PROJECT_ID_HEADER_KEY = "x-goog-user-project"; /** * The objects that need to be closed in order to clean up the resources created in the process of @@ -148,6 +149,9 @@ public static ClientContext create(StubSettings settings) throws IOException { .putAll(settings.getHeaderProvider().getHeaders()) .putAll(settings.getInternalHeaderProvider().getHeaders()) .build(); + if (settings.getQuotaProjectId() != null) { + headers.put(QUOTA_PROJECT_ID_HEADER_KEY, settings.getQuotaProjectId()); + } if (transportChannelProvider.needsHeaders()) { transportChannelProvider = transportChannelProvider.withHeaders(headers); } From 1151fdc1880f852366e506cae3d861d519ef41ed Mon Sep 17 00:00:00 2001 From: summerji Date: Thu, 16 Jul 2020 12:12:12 -0700 Subject: [PATCH 05/10] Add quotaProjectHidingCredentialsTest --- .../com/google/api/gax/rpc/ClientContext.java | 43 ++++++++-- .../com/google/api/gax/rpc/StubSettings.java | 2 +- .../QuotaProjectIdHidingCredentials.java | 79 ++++++++++++++++++ .../google/api/gax/rpc/ClientContextTest.java | 82 +++++++++++++++++++ .../api/gax/rpc/ClientSettingsTest.java | 2 +- .../QuotaProjectIdHidingCredentialsTest.java | 74 +++++++++++++++++ 6 files changed, 272 insertions(+), 10 deletions(-) create mode 100644 gax/src/main/java/com/google/api/gax/rpc/internal/QuotaProjectIdHidingCredentials.java create mode 100644 gax/src/test/java/com/google/api/gax/rpc/internal/QuotaProjectIdHidingCredentialsTest.java diff --git a/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java b/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java index 9bc162064..5911fb4b9 100644 --- a/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java +++ b/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java @@ -35,6 +35,7 @@ import com.google.api.gax.core.BackgroundResource; import com.google.api.gax.core.ExecutorAsBackgroundResource; import com.google.api.gax.core.ExecutorProvider; +import com.google.api.gax.rpc.internal.QuotaProjectIdHidingCredentials; import com.google.api.gax.tracing.ApiTracerFactory; import com.google.api.gax.tracing.NoopApiTracerFactory; import com.google.auth.Credentials; @@ -139,19 +140,17 @@ public static ClientContext create(StubSettings settings) throws IOException { final ScheduledExecutorService executor = executorProvider.getExecutor(); Credentials credentials = settings.getCredentialsProvider().getCredentials(); + if (settings.getQuotaProjectId() != null) { + credentials = new QuotaProjectIdHidingCredentials(credentials); + // Map> meta = credentials.getRequestMetadata(); + // System.out.println("meta is" + meta); + } TransportChannelProvider transportChannelProvider = settings.getTransportChannelProvider(); if (transportChannelProvider.needsExecutor()) { transportChannelProvider = transportChannelProvider.withExecutor((Executor) executor); } - Map headers = - ImmutableMap.builder() - .putAll(settings.getHeaderProvider().getHeaders()) - .putAll(settings.getInternalHeaderProvider().getHeaders()) - .build(); - if (settings.getQuotaProjectId() != null) { - headers.put(QUOTA_PROJECT_ID_HEADER_KEY, settings.getQuotaProjectId()); - } + Map headers = createHeaders(settings); if (transportChannelProvider.needsHeaders()) { transportChannelProvider = transportChannelProvider.withHeaders(headers); } @@ -215,6 +214,34 @@ public static ClientContext create(StubSettings settings) throws IOException { .build(); } + /** + * Create a header map from HeaderProvider and InternalHeaderProvider from settings with Quota + * Project Id. + */ + private static Map createHeaders(StubSettings settings) { + ImmutableMap.Builder headersBuilder = ImmutableMap.builder(); + if (settings.getQuotaProjectId() != null) { + headersBuilder.put(QUOTA_PROJECT_ID_HEADER_KEY, settings.getQuotaProjectId()); + for (Map.Entry entry : settings.getHeaderProvider().getHeaders().entrySet()) { + if (entry.getKey().equals(QUOTA_PROJECT_ID_HEADER_KEY)) { + continue; + } + headersBuilder.put(entry); + } + for (Map.Entry entry : + settings.getInternalHeaderProvider().getHeaders().entrySet()) { + if (entry.getKey().equals(QUOTA_PROJECT_ID_HEADER_KEY)) { + continue; + } + headersBuilder.put(entry); + } + } else { + headersBuilder.putAll(settings.getHeaderProvider().getHeaders()); + headersBuilder.putAll(settings.getInternalHeaderProvider().getHeaders()); + } + return headersBuilder.build(); + } + @AutoValue.Builder public abstract static class Builder { diff --git a/gax/src/main/java/com/google/api/gax/rpc/StubSettings.java b/gax/src/main/java/com/google/api/gax/rpc/StubSettings.java index a6d5e2246..b22f6a451 100644 --- a/gax/src/main/java/com/google/api/gax/rpc/StubSettings.java +++ b/gax/src/main/java/com/google/api/gax/rpc/StubSettings.java @@ -62,7 +62,7 @@ */ public abstract class StubSettings> { - static final String QUOTA_PROJECT_ID_HEADER_KEY = "x-google-user-project"; + static final String QUOTA_PROJECT_ID_HEADER_KEY = "x-goog-user-project"; private final ExecutorProvider executorProvider; private final CredentialsProvider credentialsProvider; diff --git a/gax/src/main/java/com/google/api/gax/rpc/internal/QuotaProjectIdHidingCredentials.java b/gax/src/main/java/com/google/api/gax/rpc/internal/QuotaProjectIdHidingCredentials.java new file mode 100644 index 000000000..4c8461b98 --- /dev/null +++ b/gax/src/main/java/com/google/api/gax/rpc/internal/QuotaProjectIdHidingCredentials.java @@ -0,0 +1,79 @@ +/* + * Copyright 2018 Google LLC + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.google.api.gax.rpc.internal; + +import com.google.auth.Credentials; +import java.io.IOException; +import java.net.URI; +import java.util.List; +import java.util.Map; + +public class QuotaProjectIdHidingCredentials extends Credentials { + private static final String QUOTA_PROJECT_ID_HEADER_KEY = "x-goog-user-project"; + private Credentials wrappedCredentials; + + public QuotaProjectIdHidingCredentials(Credentials credentials) { + this.wrappedCredentials = credentials; + } + + @Override + public String getAuthenticationType() { + return this.wrappedCredentials.getAuthenticationType(); + } + + @Override + public Map> getRequestMetadata(URI uri) throws IOException { + Map> requestMetadata = this.wrappedCredentials.getRequestMetadata(uri); + if (requestMetadata.containsKey(QUOTA_PROJECT_ID_HEADER_KEY)) { + requestMetadata.put(QUOTA_PROJECT_ID_HEADER_KEY, null); // maybe delelete + } + return requestMetadata; + } + + @Override + public Map> getRequestMetadata() throws IOException { + return this.getRequestMetadata(null); + } + + @Override + public boolean hasRequestMetadata() { + return this.wrappedCredentials.hasRequestMetadata(); + } + + @Override + public boolean hasRequestMetadataOnly() { + return this.wrappedCredentials.hasRequestMetadataOnly(); + } + + @Override + public void refresh() throws IOException { + this.wrappedCredentials.refresh(); + } +} diff --git a/gax/src/test/java/com/google/api/gax/rpc/ClientContextTest.java b/gax/src/test/java/com/google/api/gax/rpc/ClientContextTest.java index 45be3da78..3f67d77bd 100644 --- a/gax/src/test/java/com/google/api/gax/rpc/ClientContextTest.java +++ b/gax/src/test/java/com/google/api/gax/rpc/ClientContextTest.java @@ -30,23 +30,32 @@ package com.google.api.gax.rpc; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.fail; import com.google.api.core.ApiClock; import com.google.api.gax.core.BackgroundResource; +import com.google.api.gax.core.CredentialsProvider; import com.google.api.gax.core.ExecutorProvider; import com.google.api.gax.core.FixedCredentialsProvider; import com.google.api.gax.rpc.testing.FakeChannel; import com.google.api.gax.rpc.testing.FakeClientSettings; import com.google.api.gax.rpc.testing.FakeTransportChannel; import com.google.auth.Credentials; +import com.google.auth.oauth2.GoogleCredentials; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.truth.Truth; +import java.io.ByteArrayInputStream; import java.io.IOException; +import java.io.InputStream; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.Executor; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor; +import javax.annotation.Nullable; +import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -336,4 +345,77 @@ public void testWatchdogProvider() throws IOException { List resources = context.getBackgroundResources(); assertThat(resources.get(2)).isInstanceOf(Watchdog.class); } + + @Test + public void testHidingQuotaProjectId() throws IOException { + final String QUOTA_PROJECT_ID_KEY = "x-goog-user-project"; + final String QUOTA_PROJECT_ID_FROM_HEADER_VALUE = "quota_project_id_from_headers"; + final String QUOTA_PROJECT_ID_FROM_CREDENTIALS_VALUE = "quota_project_id_from_credentials"; + FakeClientSettings.Builder builder = new FakeClientSettings.Builder(); + + InterceptingExecutor executor = new InterceptingExecutor(1); + FakeTransportChannel transportChannel = FakeTransportChannel.create(new FakeChannel()); + FakeTransportProvider transportProvider = + new FakeTransportProvider(transportChannel, executor, true, null, null); + final Credentials credentialsWithQuota = loadCredentials(QUOTA_PROJECT_ID_FROM_CREDENTIALS_VALUE); + HeaderProvider headerProviderWithQuota = Mockito.mock(HeaderProvider.class); + Mockito.when(headerProviderWithQuota.getHeaders()).thenReturn(ImmutableMap.of(QUOTA_PROJECT_ID_KEY, QUOTA_PROJECT_ID_FROM_HEADER_VALUE)); + HeaderProvider internalHeaderProvider = Mockito.mock(HeaderProvider.class); + + builder.setExecutorProvider(new FakeExecutorProvider(executor, true)); + builder.setTransportChannelProvider(transportProvider); + builder.setCredentialsProvider(new CredentialsProvider() { + @Override + public Credentials getCredentials() throws IOException { + return credentialsWithQuota; + } + }); + + builder.setHeaderProvider(headerProviderWithQuota); + builder.setInternalHeaderProvider(internalHeaderProvider); + + ClientContext clientContext = ClientContext.create(builder.build()); + Assert.assertFalse(clientContext.getCredentials().getRequestMetadata().containsKey(QUOTA_PROJECT_ID_KEY)); + } + + static GoogleCredentials loadCredentials(String QUOTA_PROJECT_ID_FROM_CREDENTIALS_VALUE) { + final String JSON_KEY_QUOTA_PROJECT_ID = + "{\n" + + " \"private_key_id\": \"somekeyid\",\n" + + " \"private_key\": \"-----BEGIN PRIVATE KEY-----\\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggS" + + "kAgEAAoIBAQC+K2hSuFpAdrJI\\nnCgcDz2M7t7bjdlsadsasad+fvRSW6TjNQZ3p5LLQY1kSZRqBqylRkzteMOyHg" + + "aR\\n0Pmxh3ILCND5men43j3h4eDbrhQBuxfEMalkG92sL+PNQSETY2tnvXryOvmBRwa/\\nQP/9dJfIkIDJ9Fw9N4" + + "Bhhhp6mCcRpdQjV38H7JsyJ7lih/oNjECgYAt\\nknddadwkwewcVxHFhcZJO+XWf6ofLUXpRwiTZakGMn8EE1uVa2" + + "LgczOjwWHGi99MFjxSer5m9\\n1tCa3/KEGKiS/YL71JvjwX3mb+cewlkcmweBKZHM2JPTk0ZednFSpVZMtycjkbLa" + + "\\ndYOS8V85AgMBewECggEBAKksaldajfDZDV6nGqbFjMiizAKJolr/M3OQw16K6o3/\\n0S31xIe3sSlgW0+UbYlF" + + "4U8KifhManD1apVSC3csafaspP4RZUHFhtBywLO9pR5c\\nr6S5aLp+gPWFyIp1pfXbWGvc5VY/v9x7ya1VEa6rXvL" + + "sKupSeWAW4tMj3eo/64ge\\nsdaceaLYw52KeBYiT6+vpsnYrEkAHO1fF/LavbLLOFJmFTMxmsNaG0tuiJHgjshB\\" + + "n82DpMCbXG9YcCgI/DbzuIjsdj2JC1cascSP//3PmefWysucBQe7Jryb6NQtASmnv\\nCdDw/0jmZTEjpe4S1lxfHp" + + "lAhHFtdgYTvyYtaLZiVVkCgYEA8eVpof2rceecw/I6\\n5ng1q3Hl2usdWV/4mZMvR0fOemacLLfocX6IYxT1zA1FF" + + "JlbXSRsJMf/Qq39mOR2\\nSpW+hr4jCoHeRVYLgsbggtrevGmILAlNoqCMpGZ6vDmJpq6ECV9olliDvpPgWOP+\\nm" + + "YPDreFBGxWvQrADNbRt2dmGsrsCgYEAyUHqB2wvJHFqdmeBsaacewzV8x9WgmeX\\ngUIi9REwXlGDW0Mz50dxpxcK" + + "CAYn65+7TCnY5O/jmL0VRxU1J2mSWyWTo1C+17L0\\n3fUqjxL1pkefwecxwecvC+gFFYdJ4CQ/MHHXU81Lwl1iWdF" + + "Cd2UoGddYaOF+KNeM\\nHC7cmqra+JsCgYEAlUNywzq8nUg7282E+uICfCB0LfwejuymR93CtsFgb7cRd6ak\\nECR" + + "8FGfCpH8ruWJINllbQfcHVCX47ndLZwqv3oVFKh6pAS/vVI4dpOepP8++7y1u\\ncoOvtreXCX6XqfrWDtKIvv0vjl" + + "HBhhhp6mCcRpdQjV38H7JsyJ7lih/oNjECgYAt\\nkndj5uNl5SiuVxHFhcZJO+XWf6ofLUregtevZakGMn8EE1uVa" + + "2AY7eafmoU/nZPT\\n00YB0TBATdCbn/nBSuKDESkhSg9s2GEKQZG5hBmL5uCMfo09z3SfxZIhJdlerreP\\nJ7gSi" + + "dI12N+EZxYd4xIJh/HFDgp7RRO87f+WJkofMQKBgGTnClK1VMaCRbJZPriw\\nEfeFCoOX75MxKwXs6xgrw4W//AYG" + + "GUjDt83lD6AZP6tws7gJ2IwY/qP7+lyhjEqN\\nHtfPZRGFkGZsdaksdlaksd323423d+15/UvrlRSFPNj1tWQmNKk" + + "XyRDW4IG1Oa2p\\nrALStNBx5Y9t0/LQnFI4w3aG\\n-----END PRIVATE KEY-----\\n\",\n" + + " \"project_id\": \"someprojectid\",\n" + + " \"client_email\": \"someclientid@developer.gserviceaccount.com\",\n" + + " \"client_id\": \"someclientid.apps.googleusercontent.com\",\n" + + " \"type\": \"service_account\",\n" + + " \"quota_project_id\": \"" + + QUOTA_PROJECT_ID_FROM_CREDENTIALS_VALUE + + "\"\n" + + "}"; + try { + InputStream keyStream = new ByteArrayInputStream(JSON_KEY_QUOTA_PROJECT_ID.getBytes()); + return GoogleCredentials.fromStream(keyStream); + } catch (IOException e) { + fail("Couldn't create fake JSON credentials."); + } + return null; + } } diff --git a/gax/src/test/java/com/google/api/gax/rpc/ClientSettingsTest.java b/gax/src/test/java/com/google/api/gax/rpc/ClientSettingsTest.java index 4551b925c..cf842a923 100644 --- a/gax/src/test/java/com/google/api/gax/rpc/ClientSettingsTest.java +++ b/gax/src/test/java/com/google/api/gax/rpc/ClientSettingsTest.java @@ -62,7 +62,7 @@ @RunWith(JUnit4.class) public class ClientSettingsTest { - private static final String QUOTA_PROJECT_ID_KEY = "x-google-user-project"; + private static final String QUOTA_PROJECT_ID_KEY = "x-goog-user-project"; private static final String QUOTA_PROJECT_ID_FROM_HEADER_VALUE = "quota_project_id_from_headers"; private static final String QUOTA_PROJECT_ID_FROM_BUILDERS = "quota_project_id_from_builders"; private static final String QUOTA_PROJECT_ID_FROM_INTERNAL_HEADER_VALUE = diff --git a/gax/src/test/java/com/google/api/gax/rpc/internal/QuotaProjectIdHidingCredentialsTest.java b/gax/src/test/java/com/google/api/gax/rpc/internal/QuotaProjectIdHidingCredentialsTest.java new file mode 100644 index 000000000..a5e58150b --- /dev/null +++ b/gax/src/test/java/com/google/api/gax/rpc/internal/QuotaProjectIdHidingCredentialsTest.java @@ -0,0 +1,74 @@ +package com.google.api.gax.rpc.internal; + +import static org.junit.Assert.fail; + +import com.google.auth.oauth2.GoogleCredentials; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.concurrent.ExecutionException; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class QuotaProjectIdHidingCredentialsTest { + private static final String QUOTA_PROJECT_ID_KEY = "x-goog-user-project"; + private static final String QUOTA_PROJECT_ID_FROM_CREDENTIALS_VALUE = + "quota_project_id_from_credentials"; + private static final String JSON_KEY_QUOTA_PROJECT_ID = + "{\n" + + " \"private_key_id\": \"somekeyid\",\n" + + " \"private_key\": \"-----BEGIN PRIVATE KEY-----\\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggS" + + "kAgEAAoIBAQC+K2hSuFpAdrJI\\nnCgcDz2M7t7bjdlsadsasad+fvRSW6TjNQZ3p5LLQY1kSZRqBqylRkzteMOyHg" + + "aR\\n0Pmxh3ILCND5men43j3h4eDbrhQBuxfEMalkG92sL+PNQSETY2tnvXryOvmBRwa/\\nQP/9dJfIkIDJ9Fw9N4" + + "Bhhhp6mCcRpdQjV38H7JsyJ7lih/oNjECgYAt\\nknddadwkwewcVxHFhcZJO+XWf6ofLUXpRwiTZakGMn8EE1uVa2" + + "LgczOjwWHGi99MFjxSer5m9\\n1tCa3/KEGKiS/YL71JvjwX3mb+cewlkcmweBKZHM2JPTk0ZednFSpVZMtycjkbLa" + + "\\ndYOS8V85AgMBewECggEBAKksaldajfDZDV6nGqbFjMiizAKJolr/M3OQw16K6o3/\\n0S31xIe3sSlgW0+UbYlF" + + "4U8KifhManD1apVSC3csafaspP4RZUHFhtBywLO9pR5c\\nr6S5aLp+gPWFyIp1pfXbWGvc5VY/v9x7ya1VEa6rXvL" + + "sKupSeWAW4tMj3eo/64ge\\nsdaceaLYw52KeBYiT6+vpsnYrEkAHO1fF/LavbLLOFJmFTMxmsNaG0tuiJHgjshB\\" + + "n82DpMCbXG9YcCgI/DbzuIjsdj2JC1cascSP//3PmefWysucBQe7Jryb6NQtASmnv\\nCdDw/0jmZTEjpe4S1lxfHp" + + "lAhHFtdgYTvyYtaLZiVVkCgYEA8eVpof2rceecw/I6\\n5ng1q3Hl2usdWV/4mZMvR0fOemacLLfocX6IYxT1zA1FF" + + "JlbXSRsJMf/Qq39mOR2\\nSpW+hr4jCoHeRVYLgsbggtrevGmILAlNoqCMpGZ6vDmJpq6ECV9olliDvpPgWOP+\\nm" + + "YPDreFBGxWvQrADNbRt2dmGsrsCgYEAyUHqB2wvJHFqdmeBsaacewzV8x9WgmeX\\ngUIi9REwXlGDW0Mz50dxpxcK" + + "CAYn65+7TCnY5O/jmL0VRxU1J2mSWyWTo1C+17L0\\n3fUqjxL1pkefwecxwecvC+gFFYdJ4CQ/MHHXU81Lwl1iWdF" + + "Cd2UoGddYaOF+KNeM\\nHC7cmqra+JsCgYEAlUNywzq8nUg7282E+uICfCB0LfwejuymR93CtsFgb7cRd6ak\\nECR" + + "8FGfCpH8ruWJINllbQfcHVCX47ndLZwqv3oVFKh6pAS/vVI4dpOepP8++7y1u\\ncoOvtreXCX6XqfrWDtKIvv0vjl" + + "HBhhhp6mCcRpdQjV38H7JsyJ7lih/oNjECgYAt\\nkndj5uNl5SiuVxHFhcZJO+XWf6ofLUregtevZakGMn8EE1uVa" + + "2AY7eafmoU/nZPT\\n00YB0TBATdCbn/nBSuKDESkhSg9s2GEKQZG5hBmL5uCMfo09z3SfxZIhJdlerreP\\nJ7gSi" + + "dI12N+EZxYd4xIJh/HFDgp7RRO87f+WJkofMQKBgGTnClK1VMaCRbJZPriw\\nEfeFCoOX75MxKwXs6xgrw4W//AYG" + + "GUjDt83lD6AZP6tws7gJ2IwY/qP7+lyhjEqN\\nHtfPZRGFkGZsdaksdlaksd323423d+15/UvrlRSFPNj1tWQmNKk" + + "XyRDW4IG1Oa2p\\nrALStNBx5Y9t0/LQnFI4w3aG\\n-----END PRIVATE KEY-----\\n\",\n" + + " \"project_id\": \"someprojectid\",\n" + + " \"client_email\": \"someclientid@developer.gserviceaccount.com\",\n" + + " \"client_id\": \"someclientid.apps.googleusercontent.com\",\n" + + " \"type\": \"service_account\",\n" + + " \"quota_project_id\": \"" + + QUOTA_PROJECT_ID_FROM_CREDENTIALS_VALUE + + "\"\n" + + "}"; + private GoogleCredentials credentialsWithQuotaProjectId; + + @Before + public void setup() { + credentialsWithQuotaProjectId = loadCredentials(JSON_KEY_QUOTA_PROJECT_ID).createScoped("test_scope"); + } + + @Test + public void createQuotaProjectIdHidingCredentials() throws IOException { + QuotaProjectIdHidingCredentials quotaProjectIdHidingCredentials = new QuotaProjectIdHidingCredentials(credentialsWithQuotaProjectId); + Assert.assertFalse(quotaProjectIdHidingCredentials.getRequestMetadata().containsKey(QUOTA_PROJECT_ID_KEY)); + } + + static GoogleCredentials loadCredentials(String credentialFile) { + try { + InputStream keyStream = new ByteArrayInputStream(credentialFile.getBytes()); + return GoogleCredentials.fromStream(keyStream); + } catch (IOException e) { + fail("Couldn't create fake JSON credentials."); + } + return null; + } +} From c6b9d4742d9c7b1a35417be556c0fa81ae9e68ad Mon Sep 17 00:00:00 2001 From: summerji Date: Thu, 16 Jul 2020 13:41:48 -0700 Subject: [PATCH 06/10] correct getRequestMetadata --- .../QuotaProjectIdHidingCredentials.java | 13 +++++++--- .../google/api/gax/rpc/ClientContextTest.java | 25 ++++++++++--------- .../QuotaProjectIdHidingCredentialsTest.java | 10 +++++--- 3 files changed, 28 insertions(+), 20 deletions(-) diff --git a/gax/src/main/java/com/google/api/gax/rpc/internal/QuotaProjectIdHidingCredentials.java b/gax/src/main/java/com/google/api/gax/rpc/internal/QuotaProjectIdHidingCredentials.java index 4c8461b98..f0853244d 100644 --- a/gax/src/main/java/com/google/api/gax/rpc/internal/QuotaProjectIdHidingCredentials.java +++ b/gax/src/main/java/com/google/api/gax/rpc/internal/QuotaProjectIdHidingCredentials.java @@ -30,6 +30,7 @@ package com.google.api.gax.rpc.internal; import com.google.auth.Credentials; +import com.google.common.collect.ImmutableMap; import java.io.IOException; import java.net.URI; import java.util.List; @@ -50,11 +51,15 @@ public String getAuthenticationType() { @Override public Map> getRequestMetadata(URI uri) throws IOException { - Map> requestMetadata = this.wrappedCredentials.getRequestMetadata(uri); - if (requestMetadata.containsKey(QUOTA_PROJECT_ID_HEADER_KEY)) { - requestMetadata.put(QUOTA_PROJECT_ID_HEADER_KEY, null); // maybe delelete + ImmutableMap.Builder> metaBuilder = ImmutableMap.builder(); + for (Map.Entry> entry : + this.wrappedCredentials.getRequestMetadata(uri).entrySet()) { + if (entry.getKey().equals(QUOTA_PROJECT_ID_HEADER_KEY)) { + continue; + } + metaBuilder.put(entry); } - return requestMetadata; + return metaBuilder.build(); } @Override diff --git a/gax/src/test/java/com/google/api/gax/rpc/ClientContextTest.java b/gax/src/test/java/com/google/api/gax/rpc/ClientContextTest.java index 3f67d77bd..305ae9803 100644 --- a/gax/src/test/java/com/google/api/gax/rpc/ClientContextTest.java +++ b/gax/src/test/java/com/google/api/gax/rpc/ClientContextTest.java @@ -42,19 +42,16 @@ import com.google.api.gax.rpc.testing.FakeTransportChannel; import com.google.auth.Credentials; import com.google.auth.oauth2.GoogleCredentials; -import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.truth.Truth; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.Executor; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor; -import javax.annotation.Nullable; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; @@ -357,25 +354,29 @@ public void testHidingQuotaProjectId() throws IOException { FakeTransportChannel transportChannel = FakeTransportChannel.create(new FakeChannel()); FakeTransportProvider transportProvider = new FakeTransportProvider(transportChannel, executor, true, null, null); - final Credentials credentialsWithQuota = loadCredentials(QUOTA_PROJECT_ID_FROM_CREDENTIALS_VALUE); + final Credentials credentialsWithQuota = + loadCredentials(QUOTA_PROJECT_ID_FROM_CREDENTIALS_VALUE); HeaderProvider headerProviderWithQuota = Mockito.mock(HeaderProvider.class); - Mockito.when(headerProviderWithQuota.getHeaders()).thenReturn(ImmutableMap.of(QUOTA_PROJECT_ID_KEY, QUOTA_PROJECT_ID_FROM_HEADER_VALUE)); + Mockito.when(headerProviderWithQuota.getHeaders()) + .thenReturn(ImmutableMap.of(QUOTA_PROJECT_ID_KEY, QUOTA_PROJECT_ID_FROM_HEADER_VALUE)); HeaderProvider internalHeaderProvider = Mockito.mock(HeaderProvider.class); builder.setExecutorProvider(new FakeExecutorProvider(executor, true)); builder.setTransportChannelProvider(transportProvider); - builder.setCredentialsProvider(new CredentialsProvider() { - @Override - public Credentials getCredentials() throws IOException { - return credentialsWithQuota; - } - }); + builder.setCredentialsProvider( + new CredentialsProvider() { + @Override + public Credentials getCredentials() throws IOException { + return credentialsWithQuota; + } + }); builder.setHeaderProvider(headerProviderWithQuota); builder.setInternalHeaderProvider(internalHeaderProvider); ClientContext clientContext = ClientContext.create(builder.build()); - Assert.assertFalse(clientContext.getCredentials().getRequestMetadata().containsKey(QUOTA_PROJECT_ID_KEY)); + Assert.assertFalse( + clientContext.getCredentials().getRequestMetadata().containsKey(QUOTA_PROJECT_ID_KEY)); } static GoogleCredentials loadCredentials(String QUOTA_PROJECT_ID_FROM_CREDENTIALS_VALUE) { diff --git a/gax/src/test/java/com/google/api/gax/rpc/internal/QuotaProjectIdHidingCredentialsTest.java b/gax/src/test/java/com/google/api/gax/rpc/internal/QuotaProjectIdHidingCredentialsTest.java index a5e58150b..e5d3d14b4 100644 --- a/gax/src/test/java/com/google/api/gax/rpc/internal/QuotaProjectIdHidingCredentialsTest.java +++ b/gax/src/test/java/com/google/api/gax/rpc/internal/QuotaProjectIdHidingCredentialsTest.java @@ -6,7 +6,6 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; -import java.util.concurrent.ExecutionException; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -53,13 +52,16 @@ public class QuotaProjectIdHidingCredentialsTest { @Before public void setup() { - credentialsWithQuotaProjectId = loadCredentials(JSON_KEY_QUOTA_PROJECT_ID).createScoped("test_scope"); + credentialsWithQuotaProjectId = + loadCredentials(JSON_KEY_QUOTA_PROJECT_ID).createScoped("test_scope"); } @Test public void createQuotaProjectIdHidingCredentials() throws IOException { - QuotaProjectIdHidingCredentials quotaProjectIdHidingCredentials = new QuotaProjectIdHidingCredentials(credentialsWithQuotaProjectId); - Assert.assertFalse(quotaProjectIdHidingCredentials.getRequestMetadata().containsKey(QUOTA_PROJECT_ID_KEY)); + QuotaProjectIdHidingCredentials quotaProjectIdHidingCredentials = + new QuotaProjectIdHidingCredentials(credentialsWithQuotaProjectId); + Assert.assertFalse( + quotaProjectIdHidingCredentials.getRequestMetadata().containsKey(QUOTA_PROJECT_ID_KEY)); } static GoogleCredentials loadCredentials(String credentialFile) { From 0a8d1792ac39bd7c7297be6e7d4fe08ceef60de1 Mon Sep 17 00:00:00 2001 From: summerji Date: Thu, 16 Jul 2020 19:54:11 -0700 Subject: [PATCH 07/10] Add unit test for QuotaProjectIdHidingCredentials --- .../QuotaProjectIdHidingCredentialsTest.java | 137 +++++++++++------- 1 file changed, 83 insertions(+), 54 deletions(-) diff --git a/gax/src/test/java/com/google/api/gax/rpc/internal/QuotaProjectIdHidingCredentialsTest.java b/gax/src/test/java/com/google/api/gax/rpc/internal/QuotaProjectIdHidingCredentialsTest.java index e5d3d14b4..38cc54f9b 100644 --- a/gax/src/test/java/com/google/api/gax/rpc/internal/QuotaProjectIdHidingCredentialsTest.java +++ b/gax/src/test/java/com/google/api/gax/rpc/internal/QuotaProjectIdHidingCredentialsTest.java @@ -1,76 +1,105 @@ +/* + * Copyright 2018 Google LLC + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package com.google.api.gax.rpc.internal; -import static org.junit.Assert.fail; - +import com.google.auth.Credentials; import com.google.auth.oauth2.GoogleCredentials; -import java.io.ByteArrayInputStream; +import com.google.common.collect.ImmutableMap; import java.io.IOException; -import java.io.InputStream; +import java.util.Collections; +import java.util.List; +import java.util.Map; import org.junit.Assert; -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 QuotaProjectIdHidingCredentialsTest { private static final String QUOTA_PROJECT_ID_KEY = "x-goog-user-project"; private static final String QUOTA_PROJECT_ID_FROM_CREDENTIALS_VALUE = "quota_project_id_from_credentials"; - private static final String JSON_KEY_QUOTA_PROJECT_ID = - "{\n" - + " \"private_key_id\": \"somekeyid\",\n" - + " \"private_key\": \"-----BEGIN PRIVATE KEY-----\\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggS" - + "kAgEAAoIBAQC+K2hSuFpAdrJI\\nnCgcDz2M7t7bjdlsadsasad+fvRSW6TjNQZ3p5LLQY1kSZRqBqylRkzteMOyHg" - + "aR\\n0Pmxh3ILCND5men43j3h4eDbrhQBuxfEMalkG92sL+PNQSETY2tnvXryOvmBRwa/\\nQP/9dJfIkIDJ9Fw9N4" - + "Bhhhp6mCcRpdQjV38H7JsyJ7lih/oNjECgYAt\\nknddadwkwewcVxHFhcZJO+XWf6ofLUXpRwiTZakGMn8EE1uVa2" - + "LgczOjwWHGi99MFjxSer5m9\\n1tCa3/KEGKiS/YL71JvjwX3mb+cewlkcmweBKZHM2JPTk0ZednFSpVZMtycjkbLa" - + "\\ndYOS8V85AgMBewECggEBAKksaldajfDZDV6nGqbFjMiizAKJolr/M3OQw16K6o3/\\n0S31xIe3sSlgW0+UbYlF" - + "4U8KifhManD1apVSC3csafaspP4RZUHFhtBywLO9pR5c\\nr6S5aLp+gPWFyIp1pfXbWGvc5VY/v9x7ya1VEa6rXvL" - + "sKupSeWAW4tMj3eo/64ge\\nsdaceaLYw52KeBYiT6+vpsnYrEkAHO1fF/LavbLLOFJmFTMxmsNaG0tuiJHgjshB\\" - + "n82DpMCbXG9YcCgI/DbzuIjsdj2JC1cascSP//3PmefWysucBQe7Jryb6NQtASmnv\\nCdDw/0jmZTEjpe4S1lxfHp" - + "lAhHFtdgYTvyYtaLZiVVkCgYEA8eVpof2rceecw/I6\\n5ng1q3Hl2usdWV/4mZMvR0fOemacLLfocX6IYxT1zA1FF" - + "JlbXSRsJMf/Qq39mOR2\\nSpW+hr4jCoHeRVYLgsbggtrevGmILAlNoqCMpGZ6vDmJpq6ECV9olliDvpPgWOP+\\nm" - + "YPDreFBGxWvQrADNbRt2dmGsrsCgYEAyUHqB2wvJHFqdmeBsaacewzV8x9WgmeX\\ngUIi9REwXlGDW0Mz50dxpxcK" - + "CAYn65+7TCnY5O/jmL0VRxU1J2mSWyWTo1C+17L0\\n3fUqjxL1pkefwecxwecvC+gFFYdJ4CQ/MHHXU81Lwl1iWdF" - + "Cd2UoGddYaOF+KNeM\\nHC7cmqra+JsCgYEAlUNywzq8nUg7282E+uICfCB0LfwejuymR93CtsFgb7cRd6ak\\nECR" - + "8FGfCpH8ruWJINllbQfcHVCX47ndLZwqv3oVFKh6pAS/vVI4dpOepP8++7y1u\\ncoOvtreXCX6XqfrWDtKIvv0vjl" - + "HBhhhp6mCcRpdQjV38H7JsyJ7lih/oNjECgYAt\\nkndj5uNl5SiuVxHFhcZJO+XWf6ofLUregtevZakGMn8EE1uVa" - + "2AY7eafmoU/nZPT\\n00YB0TBATdCbn/nBSuKDESkhSg9s2GEKQZG5hBmL5uCMfo09z3SfxZIhJdlerreP\\nJ7gSi" - + "dI12N+EZxYd4xIJh/HFDgp7RRO87f+WJkofMQKBgGTnClK1VMaCRbJZPriw\\nEfeFCoOX75MxKwXs6xgrw4W//AYG" - + "GUjDt83lD6AZP6tws7gJ2IwY/qP7+lyhjEqN\\nHtfPZRGFkGZsdaksdlaksd323423d+15/UvrlRSFPNj1tWQmNKk" - + "XyRDW4IG1Oa2p\\nrALStNBx5Y9t0/LQnFI4w3aG\\n-----END PRIVATE KEY-----\\n\",\n" - + " \"project_id\": \"someprojectid\",\n" - + " \"client_email\": \"someclientid@developer.gserviceaccount.com\",\n" - + " \"client_id\": \"someclientid.apps.googleusercontent.com\",\n" - + " \"type\": \"service_account\",\n" - + " \"quota_project_id\": \"" - + QUOTA_PROJECT_ID_FROM_CREDENTIALS_VALUE - + "\"\n" - + "}"; - private GoogleCredentials credentialsWithQuotaProjectId; - - @Before - public void setup() { - credentialsWithQuotaProjectId = - loadCredentials(JSON_KEY_QUOTA_PROJECT_ID).createScoped("test_scope"); - } @Test - public void createQuotaProjectIdHidingCredentials() throws IOException { + public void quotaProjectIdHidingCredentials_getRequestMetadata() throws IOException { + // Credentials with quota project id + Map> metaDataWithQuota = + ImmutableMap.of( + "k1", + Collections.singletonList("v1"), + QUOTA_PROJECT_ID_KEY, + Collections.singletonList(QUOTA_PROJECT_ID_FROM_CREDENTIALS_VALUE)); + Credentials credentialsWithQuotaProjectId = Mockito.mock(GoogleCredentials.class); + Mockito.when(credentialsWithQuotaProjectId.getRequestMetadata(null)) + .thenReturn(metaDataWithQuota); QuotaProjectIdHidingCredentials quotaProjectIdHidingCredentials = new QuotaProjectIdHidingCredentials(credentialsWithQuotaProjectId); - Assert.assertFalse( - quotaProjectIdHidingCredentials.getRequestMetadata().containsKey(QUOTA_PROJECT_ID_KEY)); + Map> metaDataHidingQuota = + quotaProjectIdHidingCredentials.getRequestMetadata(); + + Assert.assertTrue(metaDataWithQuota.containsKey(QUOTA_PROJECT_ID_KEY)); + Assert.assertFalse(metaDataHidingQuota.containsKey(QUOTA_PROJECT_ID_KEY)); + Assert.assertEquals(metaDataWithQuota.size() - 1, metaDataHidingQuota.size()); + + // Credentials without quota project id + Map> metaDataWithoutQuota = + ImmutableMap.of("k1", Collections.singletonList("v1")); + Credentials credentialsWithoutQuotaProjectId = Mockito.mock(GoogleCredentials.class); + Mockito.when(credentialsWithoutQuotaProjectId.getRequestMetadata(null)) + .thenReturn(metaDataWithoutQuota); + QuotaProjectIdHidingCredentials quotaProjectIdHidingCredentialsWithout = + new QuotaProjectIdHidingCredentials(credentialsWithoutQuotaProjectId); + Map> metaDataHidingQuotaWithout = + quotaProjectIdHidingCredentials.getRequestMetadata(); + + Assert.assertEquals( + quotaProjectIdHidingCredentialsWithout.getRequestMetadata(), metaDataWithoutQuota); } - static GoogleCredentials loadCredentials(String credentialFile) { - try { - InputStream keyStream = new ByteArrayInputStream(credentialFile.getBytes()); - return GoogleCredentials.fromStream(keyStream); - } catch (IOException e) { - fail("Couldn't create fake JSON credentials."); - } - return null; + @Test + public void quotaProjectIdHidingCredentials_getAuthenticationType() throws IOException { + final String mockType = "mock_type"; + Credentials credentials = Mockito.mock(GoogleCredentials.class); + Mockito.when(credentials.getAuthenticationType()).thenReturn(mockType); + Mockito.when(credentials.hasRequestMetadata()).thenReturn(true); + Mockito.when(credentials.hasRequestMetadataOnly()).thenReturn(false); + + QuotaProjectIdHidingCredentials quotaProjectIdHidingCredentials = + new QuotaProjectIdHidingCredentials(credentials); + quotaProjectIdHidingCredentials.refresh(); + + Assert.assertEquals(quotaProjectIdHidingCredentials.getAuthenticationType(), mockType); + Assert.assertTrue(quotaProjectIdHidingCredentials.hasRequestMetadata()); + Assert.assertFalse(quotaProjectIdHidingCredentials.hasRequestMetadataOnly()); + + Mockito.verify(credentials, Mockito.atLeastOnce()).refresh(); } } From a63ffae9fbb21cb1abae0768638e33de55efbc91 Mon Sep 17 00:00:00 2001 From: summerji Date: Fri, 17 Jul 2020 00:56:35 -0700 Subject: [PATCH 08/10] add unit test for client context --- .../com/google/api/gax/rpc/ClientContext.java | 8 +- .../google/api/gax/rpc/ClientContextTest.java | 213 +++++++++++++----- 2 files changed, 163 insertions(+), 58 deletions(-) diff --git a/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java b/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java index 5911fb4b9..339817eed 100644 --- a/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java +++ b/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java @@ -142,15 +142,13 @@ public static ClientContext create(StubSettings settings) throws IOException { Credentials credentials = settings.getCredentialsProvider().getCredentials(); if (settings.getQuotaProjectId() != null) { credentials = new QuotaProjectIdHidingCredentials(credentials); - // Map> meta = credentials.getRequestMetadata(); - // System.out.println("meta is" + meta); } TransportChannelProvider transportChannelProvider = settings.getTransportChannelProvider(); if (transportChannelProvider.needsExecutor()) { transportChannelProvider = transportChannelProvider.withExecutor((Executor) executor); } - Map headers = createHeaders(settings); + Map headers = getHeadersFromSettings(settings); if (transportChannelProvider.needsHeaders()) { transportChannelProvider = transportChannelProvider.withHeaders(headers); } @@ -215,10 +213,10 @@ public static ClientContext create(StubSettings settings) throws IOException { } /** - * Create a header map from HeaderProvider and InternalHeaderProvider from settings with Quota + * Getting a header map from HeaderProvider and InternalHeaderProvider from settings with Quota * Project Id. */ - private static Map createHeaders(StubSettings settings) { + private static Map getHeadersFromSettings(StubSettings settings) { ImmutableMap.Builder headersBuilder = ImmutableMap.builder(); if (settings.getQuotaProjectId() != null) { headersBuilder.put(QUOTA_PROJECT_ID_HEADER_KEY, settings.getQuotaProjectId()); diff --git a/gax/src/test/java/com/google/api/gax/rpc/ClientContextTest.java b/gax/src/test/java/com/google/api/gax/rpc/ClientContextTest.java index 305ae9803..0f7305ca2 100644 --- a/gax/src/test/java/com/google/api/gax/rpc/ClientContextTest.java +++ b/gax/src/test/java/com/google/api/gax/rpc/ClientContextTest.java @@ -30,7 +30,6 @@ package com.google.api.gax.rpc; import static com.google.common.truth.Truth.assertThat; -import static org.junit.Assert.fail; import com.google.api.core.ApiClock; import com.google.api.gax.core.BackgroundResource; @@ -44,15 +43,13 @@ import com.google.auth.oauth2.GoogleCredentials; import com.google.common.collect.ImmutableMap; import com.google.common.truth.Truth; -import java.io.ByteArrayInputStream; import java.io.IOException; -import java.io.InputStream; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.Executor; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor; -import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -344,9 +341,121 @@ public void testWatchdogProvider() throws IOException { } @Test - public void testHidingQuotaProjectId() throws IOException { + public void testMergeHeaders_getQuotaProjectIdFromHeadersProvider() throws IOException { + final String QUOTA_PROJECT_ID_KEY = "x-goog-user-project"; + final String QUOTA_PROJECT_ID_FROM_SETTINGS = "quota_project_id_from_settings"; + FakeClientSettings.Builder builder = new FakeClientSettings.Builder(); + + InterceptingExecutor executor = new InterceptingExecutor(1); + FakeTransportChannel transportChannel = FakeTransportChannel.create(new FakeChannel()); + FakeTransportProvider transportProvider = + new FakeTransportProvider(transportChannel, executor, true, null, null); + + HeaderProvider headerProvider = Mockito.mock(HeaderProvider.class); + Mockito.when(headerProvider.getHeaders()).thenReturn(ImmutableMap.of("header_k1", "v1")); + HeaderProvider internalHeaderProvider = Mockito.mock(HeaderProvider.class); + Mockito.when(internalHeaderProvider.getHeaders()) + .thenReturn(ImmutableMap.of("internal_header_k1", "v1")); + + builder.setTransportChannelProvider(transportProvider); + builder.setCredentialsProvider( + FixedCredentialsProvider.create(Mockito.mock(Credentials.class))); + builder.setHeaderProvider(headerProvider); + builder.setInternalHeaderProvider(internalHeaderProvider); + builder.setQuotaProjectId(QUOTA_PROJECT_ID_FROM_SETTINGS); + + ClientContext context = ClientContext.create(builder.build()); + List resources = context.getBackgroundResources(); + FakeTransportChannel fakeTransportChannel = (FakeTransportChannel) resources.get(0); + assertThat(fakeTransportChannel.getHeaders().size()) + .isEqualTo( + headerProvider.getHeaders().size() + internalHeaderProvider.getHeaders().size() + 1); + assertThat(fakeTransportChannel.getHeaders().get(QUOTA_PROJECT_ID_KEY)) + .isEqualTo(QUOTA_PROJECT_ID_FROM_SETTINGS); + } + + @Test + public void testMergeHeaders_getQuotaProjectIdFromSettings() throws IOException { + final String QUOTA_PROJECT_ID_KEY = "x-goog-user-project"; + final String QUOTA_PROJECT_ID_FROM_HEADERS = "quota_project_id_from_headers"; + final String QUOTA_PROJECT_ID_FROM_INTERNAL_HEADERS = "quota_project_id_from_internal_headers"; + final String QUOTA_PROJECT_ID_FROM_SETTINGS = "quota_project_id_from_settings"; + FakeClientSettings.Builder builder = new FakeClientSettings.Builder(); + + InterceptingExecutor executor = new InterceptingExecutor(1); + FakeTransportChannel transportChannel = FakeTransportChannel.create(new FakeChannel()); + FakeTransportProvider transportProvider = + new FakeTransportProvider(transportChannel, executor, true, null, null); + + HeaderProvider headerProvider = + new HeaderProvider() { + @Override + public Map getHeaders() { + return ImmutableMap.of(QUOTA_PROJECT_ID_KEY, QUOTA_PROJECT_ID_FROM_HEADERS, "k2", "v2"); + } + }; + HeaderProvider internalHeaderProvider = + new HeaderProvider() { + @Override + public Map getHeaders() { + return ImmutableMap.of( + QUOTA_PROJECT_ID_KEY, + QUOTA_PROJECT_ID_FROM_INTERNAL_HEADERS, + "internal_header_k1", + "v1"); + } + }; + + builder.setTransportChannelProvider(transportProvider); + builder.setCredentialsProvider( + FixedCredentialsProvider.create(Mockito.mock(Credentials.class))); + builder.setHeaderProvider(headerProvider); + builder.setInternalHeaderProvider(internalHeaderProvider); + builder.setQuotaProjectId(QUOTA_PROJECT_ID_FROM_SETTINGS); + + ClientContext context = ClientContext.create(builder.build()); + List resources = context.getBackgroundResources(); + FakeTransportChannel fakeTransportChannel = (FakeTransportChannel) resources.get(0); + assertThat(fakeTransportChannel.getHeaders().size()) + .isEqualTo( + headerProvider.getHeaders().size() + internalHeaderProvider.getHeaders().size() - 1); + assertThat(fakeTransportChannel.getHeaders().get(QUOTA_PROJECT_ID_KEY)) + .isEqualTo(QUOTA_PROJECT_ID_FROM_SETTINGS); + } + + @Test + public void testMergeHeaders_noQuotaProjectIdSet() throws IOException { + final String QUOTA_PROJECT_ID_KEY = "x-goog-user-project"; + FakeClientSettings.Builder builder = new FakeClientSettings.Builder(); + + InterceptingExecutor executor = new InterceptingExecutor(1); + FakeTransportChannel transportChannel = FakeTransportChannel.create(new FakeChannel()); + FakeTransportProvider transportProvider = + new FakeTransportProvider(transportChannel, executor, true, null, null); + + HeaderProvider headerProvider = Mockito.mock(HeaderProvider.class); + Mockito.when(headerProvider.getHeaders()).thenReturn(ImmutableMap.of("header_k1", "v1")); + HeaderProvider internalHeaderProvider = Mockito.mock(HeaderProvider.class); + Mockito.when(internalHeaderProvider.getHeaders()) + .thenReturn(ImmutableMap.of("internal_header_k1", "v1")); + + builder.setTransportChannelProvider(transportProvider); + builder.setCredentialsProvider( + FixedCredentialsProvider.create(Mockito.mock(Credentials.class))); + builder.setHeaderProvider(headerProvider); + builder.setInternalHeaderProvider(internalHeaderProvider); + + ClientContext context = ClientContext.create(builder.build()); + List resources = context.getBackgroundResources(); + FakeTransportChannel fakeTransportChannel = (FakeTransportChannel) resources.get(0); + assertThat(fakeTransportChannel.getHeaders().size()) + .isEqualTo(headerProvider.getHeaders().size() + internalHeaderProvider.getHeaders().size()); + assertThat(fakeTransportChannel.getHeaders().containsKey(QUOTA_PROJECT_ID_KEY)).isFalse(); + } + + @Test + public void testHidingQuotaProjectId_quotaSetFromSetting() throws IOException { final String QUOTA_PROJECT_ID_KEY = "x-goog-user-project"; - final String QUOTA_PROJECT_ID_FROM_HEADER_VALUE = "quota_project_id_from_headers"; final String QUOTA_PROJECT_ID_FROM_CREDENTIALS_VALUE = "quota_project_id_from_credentials"; FakeClientSettings.Builder builder = new FakeClientSettings.Builder(); @@ -354,11 +463,16 @@ public void testHidingQuotaProjectId() throws IOException { FakeTransportChannel transportChannel = FakeTransportChannel.create(new FakeChannel()); FakeTransportProvider transportProvider = new FakeTransportProvider(transportChannel, executor, true, null, null); - final Credentials credentialsWithQuota = - loadCredentials(QUOTA_PROJECT_ID_FROM_CREDENTIALS_VALUE); + Map> metaDataWithQuota = + ImmutableMap.of( + "k1", + Collections.singletonList("v1"), + QUOTA_PROJECT_ID_KEY, + Collections.singletonList(QUOTA_PROJECT_ID_FROM_CREDENTIALS_VALUE)); + final Credentials credentialsWithQuotaProjectId = Mockito.mock(GoogleCredentials.class); + Mockito.when(credentialsWithQuotaProjectId.getRequestMetadata(null)) + .thenReturn(metaDataWithQuota); HeaderProvider headerProviderWithQuota = Mockito.mock(HeaderProvider.class); - Mockito.when(headerProviderWithQuota.getHeaders()) - .thenReturn(ImmutableMap.of(QUOTA_PROJECT_ID_KEY, QUOTA_PROJECT_ID_FROM_HEADER_VALUE)); HeaderProvider internalHeaderProvider = Mockito.mock(HeaderProvider.class); builder.setExecutorProvider(new FakeExecutorProvider(executor, true)); @@ -367,56 +481,49 @@ public void testHidingQuotaProjectId() throws IOException { new CredentialsProvider() { @Override public Credentials getCredentials() throws IOException { - return credentialsWithQuota; + return credentialsWithQuotaProjectId; } }); - builder.setHeaderProvider(headerProviderWithQuota); builder.setInternalHeaderProvider(internalHeaderProvider); + builder.setQuotaProjectId(QUOTA_PROJECT_ID_FROM_CREDENTIALS_VALUE); ClientContext clientContext = ClientContext.create(builder.build()); - Assert.assertFalse( - clientContext.getCredentials().getRequestMetadata().containsKey(QUOTA_PROJECT_ID_KEY)); + assertThat(clientContext.getCredentials().getRequestMetadata().size()) + .isEqualTo(metaDataWithQuota.size() - 1); + assertThat( + clientContext.getCredentials().getRequestMetadata().containsKey(QUOTA_PROJECT_ID_KEY)) + .isFalse(); } - static GoogleCredentials loadCredentials(String QUOTA_PROJECT_ID_FROM_CREDENTIALS_VALUE) { - final String JSON_KEY_QUOTA_PROJECT_ID = - "{\n" - + " \"private_key_id\": \"somekeyid\",\n" - + " \"private_key\": \"-----BEGIN PRIVATE KEY-----\\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggS" - + "kAgEAAoIBAQC+K2hSuFpAdrJI\\nnCgcDz2M7t7bjdlsadsasad+fvRSW6TjNQZ3p5LLQY1kSZRqBqylRkzteMOyHg" - + "aR\\n0Pmxh3ILCND5men43j3h4eDbrhQBuxfEMalkG92sL+PNQSETY2tnvXryOvmBRwa/\\nQP/9dJfIkIDJ9Fw9N4" - + "Bhhhp6mCcRpdQjV38H7JsyJ7lih/oNjECgYAt\\nknddadwkwewcVxHFhcZJO+XWf6ofLUXpRwiTZakGMn8EE1uVa2" - + "LgczOjwWHGi99MFjxSer5m9\\n1tCa3/KEGKiS/YL71JvjwX3mb+cewlkcmweBKZHM2JPTk0ZednFSpVZMtycjkbLa" - + "\\ndYOS8V85AgMBewECggEBAKksaldajfDZDV6nGqbFjMiizAKJolr/M3OQw16K6o3/\\n0S31xIe3sSlgW0+UbYlF" - + "4U8KifhManD1apVSC3csafaspP4RZUHFhtBywLO9pR5c\\nr6S5aLp+gPWFyIp1pfXbWGvc5VY/v9x7ya1VEa6rXvL" - + "sKupSeWAW4tMj3eo/64ge\\nsdaceaLYw52KeBYiT6+vpsnYrEkAHO1fF/LavbLLOFJmFTMxmsNaG0tuiJHgjshB\\" - + "n82DpMCbXG9YcCgI/DbzuIjsdj2JC1cascSP//3PmefWysucBQe7Jryb6NQtASmnv\\nCdDw/0jmZTEjpe4S1lxfHp" - + "lAhHFtdgYTvyYtaLZiVVkCgYEA8eVpof2rceecw/I6\\n5ng1q3Hl2usdWV/4mZMvR0fOemacLLfocX6IYxT1zA1FF" - + "JlbXSRsJMf/Qq39mOR2\\nSpW+hr4jCoHeRVYLgsbggtrevGmILAlNoqCMpGZ6vDmJpq6ECV9olliDvpPgWOP+\\nm" - + "YPDreFBGxWvQrADNbRt2dmGsrsCgYEAyUHqB2wvJHFqdmeBsaacewzV8x9WgmeX\\ngUIi9REwXlGDW0Mz50dxpxcK" - + "CAYn65+7TCnY5O/jmL0VRxU1J2mSWyWTo1C+17L0\\n3fUqjxL1pkefwecxwecvC+gFFYdJ4CQ/MHHXU81Lwl1iWdF" - + "Cd2UoGddYaOF+KNeM\\nHC7cmqra+JsCgYEAlUNywzq8nUg7282E+uICfCB0LfwejuymR93CtsFgb7cRd6ak\\nECR" - + "8FGfCpH8ruWJINllbQfcHVCX47ndLZwqv3oVFKh6pAS/vVI4dpOepP8++7y1u\\ncoOvtreXCX6XqfrWDtKIvv0vjl" - + "HBhhhp6mCcRpdQjV38H7JsyJ7lih/oNjECgYAt\\nkndj5uNl5SiuVxHFhcZJO+XWf6ofLUregtevZakGMn8EE1uVa" - + "2AY7eafmoU/nZPT\\n00YB0TBATdCbn/nBSuKDESkhSg9s2GEKQZG5hBmL5uCMfo09z3SfxZIhJdlerreP\\nJ7gSi" - + "dI12N+EZxYd4xIJh/HFDgp7RRO87f+WJkofMQKBgGTnClK1VMaCRbJZPriw\\nEfeFCoOX75MxKwXs6xgrw4W//AYG" - + "GUjDt83lD6AZP6tws7gJ2IwY/qP7+lyhjEqN\\nHtfPZRGFkGZsdaksdlaksd323423d+15/UvrlRSFPNj1tWQmNKk" - + "XyRDW4IG1Oa2p\\nrALStNBx5Y9t0/LQnFI4w3aG\\n-----END PRIVATE KEY-----\\n\",\n" - + " \"project_id\": \"someprojectid\",\n" - + " \"client_email\": \"someclientid@developer.gserviceaccount.com\",\n" - + " \"client_id\": \"someclientid.apps.googleusercontent.com\",\n" - + " \"type\": \"service_account\",\n" - + " \"quota_project_id\": \"" - + QUOTA_PROJECT_ID_FROM_CREDENTIALS_VALUE - + "\"\n" - + "}"; - try { - InputStream keyStream = new ByteArrayInputStream(JSON_KEY_QUOTA_PROJECT_ID.getBytes()); - return GoogleCredentials.fromStream(keyStream); - } catch (IOException e) { - fail("Couldn't create fake JSON credentials."); - } - return null; + @Test + public void testHidingQuotaProjectId_noQuotaSetFromSetting() throws IOException { + final String QUOTA_PROJECT_ID_KEY = "x-goog-user-project"; + FakeClientSettings.Builder builder = new FakeClientSettings.Builder(); + + InterceptingExecutor executor = new InterceptingExecutor(1); + FakeTransportChannel transportChannel = FakeTransportChannel.create(new FakeChannel()); + FakeTransportProvider transportProvider = + new FakeTransportProvider(transportChannel, executor, true, null, null); + Map> metaData = ImmutableMap.of("k1", Collections.singletonList("v1")); + final Credentials credentialsWithoutQuotaProjectId = Mockito.mock(GoogleCredentials.class); + Mockito.when(credentialsWithoutQuotaProjectId.getRequestMetadata(null)).thenReturn(metaData); + HeaderProvider headerProviderWithQuota = Mockito.mock(HeaderProvider.class); + HeaderProvider internalHeaderProvider = Mockito.mock(HeaderProvider.class); + + builder.setExecutorProvider(new FakeExecutorProvider(executor, true)); + builder.setTransportChannelProvider(transportProvider); + builder.setCredentialsProvider( + new CredentialsProvider() { + @Override + public Credentials getCredentials() throws IOException { + return credentialsWithoutQuotaProjectId; + } + }); + builder.setHeaderProvider(headerProviderWithQuota); + builder.setInternalHeaderProvider(internalHeaderProvider); + + ClientContext clientContext = ClientContext.create(builder.build()); + assertThat(clientContext.getCredentials().getRequestMetadata(null)).isEqualTo(metaData); } } From 0e1e2019b8b00ebc85d37d79c62e49f4eda6ea2c Mon Sep 17 00:00:00 2001 From: summerji Date: Wed, 22 Jul 2020 14:40:35 -0700 Subject: [PATCH 09/10] Add comment and beta annotation --- .../java/com/google/api/gax/rpc/ClientContext.java | 5 +++++ .../internal/QuotaProjectIdHidingCredentials.java | 12 ++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java b/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java index 339817eed..1dca243d9 100644 --- a/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java +++ b/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java @@ -140,7 +140,12 @@ public static ClientContext create(StubSettings settings) throws IOException { final ScheduledExecutorService executor = executorProvider.getExecutor(); Credentials credentials = settings.getCredentialsProvider().getCredentials(); + if (settings.getQuotaProjectId() != null) { + // If the quotaProjectId is set, wrap original credentials with correct quotaProjectId as + // QuotaProjectIdHidingCredentials. + // Ensure that a custom set quota project id takes priority over one detected by credentials. + // Avoid the backend receiving possibly conflict values of quotaProjectId credentials = new QuotaProjectIdHidingCredentials(credentials); } diff --git a/gax/src/main/java/com/google/api/gax/rpc/internal/QuotaProjectIdHidingCredentials.java b/gax/src/main/java/com/google/api/gax/rpc/internal/QuotaProjectIdHidingCredentials.java index f0853244d..51bbade9a 100644 --- a/gax/src/main/java/com/google/api/gax/rpc/internal/QuotaProjectIdHidingCredentials.java +++ b/gax/src/main/java/com/google/api/gax/rpc/internal/QuotaProjectIdHidingCredentials.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 Google LLC + * Copyright 2020 Google LLC * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -29,6 +29,7 @@ */ package com.google.api.gax.rpc.internal; +import com.google.api.client.util.Beta; import com.google.auth.Credentials; import com.google.common.collect.ImmutableMap; import java.io.IOException; @@ -36,9 +37,16 @@ import java.util.List; import java.util.Map; +/** + * {@code QuotaProjectIdHidingCredentials} is intended to be used to wrap a {@link Credentials} to + * hide quota project id + * + *

Ensure that a custom set quota project id takes priority over one detected by credentials. + */ +@Beta public class QuotaProjectIdHidingCredentials extends Credentials { private static final String QUOTA_PROJECT_ID_HEADER_KEY = "x-goog-user-project"; - private Credentials wrappedCredentials; + private final Credentials wrappedCredentials; public QuotaProjectIdHidingCredentials(Credentials credentials) { this.wrappedCredentials = credentials; From 7f91763fffddedd84674e2b66220f8c683facf3e Mon Sep 17 00:00:00 2001 From: Summer Ji Date: Thu, 23 Jul 2020 21:51:53 -0700 Subject: [PATCH 10/10] Update gax/src/test/java/com/google/api/gax/rpc/internal/QuotaProjectIdHidingCredentialsTest.java Co-authored-by: Jeff Ching --- .../gax/rpc/internal/QuotaProjectIdHidingCredentialsTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gax/src/test/java/com/google/api/gax/rpc/internal/QuotaProjectIdHidingCredentialsTest.java b/gax/src/test/java/com/google/api/gax/rpc/internal/QuotaProjectIdHidingCredentialsTest.java index 38cc54f9b..af36e0a5b 100644 --- a/gax/src/test/java/com/google/api/gax/rpc/internal/QuotaProjectIdHidingCredentialsTest.java +++ b/gax/src/test/java/com/google/api/gax/rpc/internal/QuotaProjectIdHidingCredentialsTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 Google LLC + * Copyright 2020 Google LLC * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are